diff --git a/components/bt/bluedroid/app/app_client_profiles/battery_c/battery_c.c b/components/bt/bluedroid/app/app_client_profiles/battery_c/battery_c.c new file mode 100644 index 0000000000..afb3905a6f --- /dev/null +++ b/components/bt/bluedroid/app/app_client_profiles/battery_c/battery_c.c @@ -0,0 +1,185 @@ +/*************************************************************** +* * +* * This file is for client to execute battery-related operation +* * +***************************************************************/ +#include +#include +#include +#include + +#include "bta_api.h" +#include "bta_gatt_api.h" +#include "controller.h" + +#include "gatt_int.h" +#include "bt_trace.h" +#include "btm_api.h" +#include "bt_types.h" +#include "gattc_profile.h" + +#define BT_BD_ADDR_STR "%02x:%02x:%02x:%02x:%02x:%02x" +#define BT_BD_ADDR_HEX(addr) addr[0], addr[1], addr[2], addr[3], addr[4], addr[5] +tBTA_GATTC_IF client_if; + +tBT_UUID bas_uuid = {LEN_UUID_16, {UUID_SERVCLASS_BATTERY}}; + +uint16_t get_uuid16(tBT_UUID* p_uuid) +{ + if(p_uuid->len == LEN_UUID_16) + { + return p_uuid->uu.uuid16; + } + else if(p_uuid->len == LEN_UUID_128) + { + UINT16 u16; + UINT8 *p = &p_uuid->uu.uuid128[LEN_UUID_128 - 4]; + STREAM_TO_UINT16(u16, p); + return u16; + } + else + { + return (UINT16)p_uuid->uu.uuid32; + } +} + +/*fill a GATT ID structure*/ +void bta_le_fill_16bits_gatt_id(UINT8 inst_id, UINT16 uuid, tBTA_GATT_ID* p_output) +{ + p_output->inst_id = inst_id; + p_output->uuid.len = LEN_UUID_16; + p_output->uuid.uu.uuid16 = uuid; +} + +/*fill a service ID structure with a 16 bits service UUID*/ +void bta_le_fill_16bits_srvc_id(bool is_pri, UINT8 inst_id, UINT16 srvc_uuid, tBTA_GATT_SRVC_ID* p_output) +{ + memset((void *)p_output, 0, sizeof(tBTA_GATT_SRVC_ID)); + p_output->is_primary = is_pri; + bta_le_fill_16bits_gatt_id(inst_id, srvc_uuid, &p_output->id); +} + +/*fill a char ID structure with a 16 bits char UUID*/ +void bta_le_fill_16bits_char_id(UINT8 inst_id, UINT16 char_uuid, tBTA_GATT_ID* p_output) +{ + memset((void *)p_output, 0, sizeof(tBTA_GATT_ID)); + bta_le_fill_16bits_gatt_id(inst_id, char_uuid, p_output); +} + +/****************************************************************************** +** Function bas_gattc_callback +** +** Description battery service register callback function +*******************************************************************************/ +static void bas_gattc_callback(tBTA_GATTC_EVT event, tBTA_GATTC* p_data) +{ + switch (event) + { + case BTA_GATTC_REG_EVT: + { + tBTA_GATT_STATUS status = p_data->reg_oper.status; + client_if = p_data->reg_oper.client_if; + LOG_ERROR("BAS register completed: event=%d, status=%d, client_if=%d\n", + event, status, client_if); + + } + break; + + /*connect callback*/ + case BTA_GATTC_OPEN_EVT: + { + + LOG_ERROR("\n%s:device is connected "BT_BD_ADDR_STR", client_if=%d, status=%d, connect_id=%d\n", + __FUNCTION__, BT_BD_ADDR_HEX(p_data->open.remote_bda), p_data->open.client_if, + p_data->open.status, p_data->open.conn_id); + /*return whether the remote device is currently connected*/ + int is_connected = BTA_DmGetConnectionState(p_data->open.remote_bda); + LOG_ERROR("is_connected=%d\n",is_connected); + /*get the energy info of the controller*/ + + /*read battery level*/ + int conn_id = p_data->open.conn_id; + + /*discover service*/ + BTA_GATTC_ServiceSearchRequest(conn_id, NULL); + + } + break; + + case BTA_GATTC_SEARCH_RES_EVT: + { + // tBTA_GATTC_SRVC_RES service_result; + LOG_ERROR("find the service,uuid=0x%x, is_primary=%d\n", + get_uuid16(&p_data->srvc_res.service_uuid.id.uuid), + p_data->srvc_res.service_uuid.is_primary); + } + break; + + case BTA_GATTC_SEARCH_CMPL_EVT: + { + LOG_ERROR("search service complete, conn_id=%d,status=%d\n", p_data->search_cmpl.conn_id, + p_data->search_cmpl.status); + + /*get first characteristic of battey service*/ + LOG_ERROR("get first characteristic of battery service\n"); + tBTA_GATT_STATUS status; + tBTA_GATT_SRVC_ID battery_srvc_id; + tBTA_GATTC_CHAR_ID out_char_id; + tGATT_CHAR_PROP out_char_prop; + bta_le_fill_16bits_srvc_id(TRUE, 0, UUID_SERVCLASS_BATTERY, &battery_srvc_id); + status = BTA_GATTC_GetFirstChar(p_data->search_cmpl.conn_id, &battery_srvc_id, NULL, + &out_char_id, &out_char_prop); + if(status == 0) + { + LOG_ERROR("the first char:srvc_id=0x%x,char_id=0x%x, property = %d\n", + get_uuid16(&out_char_id.srvc_id.id.uuid), get_uuid16(&out_char_id.char_id.uuid), + out_char_prop); + /*read battery level*/ + tBTA_GATTC_CHAR_ID battery_char_id; + bta_le_fill_16bits_srvc_id(TRUE, 0, UUID_SERVCLASS_BATTERY, &battery_char_id.srvc_id); + bta_le_fill_16bits_char_id(0, GATT_UUID_BATTERY_LEVEL, &battery_char_id.char_id); + + BTA_GATTC_ReadCharacteristic(p_data->search_cmpl.conn_id, &battery_char_id, + BTA_GATT_AUTH_REQ_NONE); + } + } + break; + + case BTA_GATTC_READ_CHAR_EVT: + { + + LOG_ERROR("\nread characteristic:connect_id=%d, status=%d\n", + p_data->read.conn_id, p_data->read.status); + LOG_ERROR("srvc_id=0x%x,char_id=0x%x,descr_type=0x%x\n", + get_uuid16(&p_data->read.srvc_id.id.uuid), + get_uuid16(&p_data->read.char_id.uuid), + get_uuid16(&p_data->read.descr_type.uuid)); + if(get_uuid16(&p_data->read.descr_type.uuid) != GATT_UUID_CHAR_AGG_FORMAT + && p_data->read.p_value->unformat.len > 0 + && p_data->read.p_value->unformat.p_value != NULL) + { + LOG_ERROR("read the value: len=%d, value=%d\n", p_data->read.p_value->unformat.len, + *(p_data->read.p_value->unformat.p_value)); + } + } + break; + + default: + LOG_ERROR("unsettled event: %d\n", event); + } + +} + +/*************************************************************** +** +** Function bac_register +** +** Description register app for battery service +** +****************************************************************/ +void bac_register(void) +{ + BTA_GATTC_AppRegister(&bas_uuid, bas_gattc_callback); + +} + diff --git a/components/bt/bluedroid/app/app_core/bt_app.c b/components/bt/bluedroid/app/app_core/bt_app.c new file mode 100644 index 0000000000..854dab47a6 --- /dev/null +++ b/components/bt/bluedroid/app/app_core/bt_app.c @@ -0,0 +1,186 @@ +/** + **************************************************************************************** + * + * @file bt_app.c + * + * @brief Application entry point + * + * Copyright (C) Espressif 2016 + * Created by Yulong at 2016/9/9 + * + * + **************************************************************************************** + */ + +#include "bt_app_defs.h" + + + /******************************************************************************* + ** + ** Function ESP_AppConfigadvData + ** + ** Description This function is called to override the BTA default ADV parameters. + ** + ** adv_data: Pointer to User defined ADV data structure. This + ** memory space can not be freed until p_adv_data_cback + ** is received. + ** p_adv_data_cback: set adv data complete callback. + ** + ** Returns None + ** + *******************************************************************************/ + void ESP_AppBleConfigadvData(tESP_BLE_ADV_DATA *adv_data, + tBTA_SET_ADV_DATA_CMPL_CBACK *p_adv_data_cback) +{ + tBTA_BLE_AD_MASK data_mask = 0; + if(adv_data->adv_name != NULL) + { + data_mask |= BTM_BLE_AD_BIT_DEV_NAME; + BTA_DmSetDeviceName(adv_data->adv_name); + } + if(adv_data->ble_adv_data.int_range.low != 0 || + adv_data->ble_adv_data.int_range.hi != 0) + data_mask |= BTM_BLE_AD_BIT_INT_RANGE; + + if(adv_data->ble_adv_data.p_manu != NULL) + { + data_mask |= BTM_BLE_AD_BIT_MANU; + } + + if(adv_data->ble_adv_data.p_services != NULL) + { + data_mask |= BTM_BLE_AD_BIT_SERVICE; + } + + if(adv_data->ble_adv_data.p_service_32b != NULL) + { + data_mask |= BTM_BLE_AD_BIT_SERVICE_32; + } + + if(adv_data->ble_adv_data.p_services_128b != NULL) + { + data_mask |= BTM_BLE_AD_BIT_SERVICE_128; + } + + if(adv_data->ble_adv_data.p_sol_services != NULL) + { + data_mask |= BTM_BLE_AD_BIT_SERVICE_SOL; + } + + if(adv_data->ble_adv_data.p_sol_service_32b != NULL) + { + data_mask |= BTM_BLE_AD_BIT_SERVICE_32SOL; + } + + if(adv_data->ble_adv_data.p_sol_service_128b != NULL) + { + data_mask |= BTM_BLE_AD_BIT_SERVICE_128SOL; + } + + if(adv_data->ble_adv_data.p_service_data != NULL) + { + data_mask |= BTM_BLE_AD_BIT_SERVICE_DATA; + } + + if(adv_data->ble_adv_data.appearance != 0) + { + data_mask |= BTM_BLE_AD_BIT_APPEARANCE; + } + + if(adv_data->ble_adv_data.p_proprietary != NULL) + { + data_mask |= BTM_BLE_AD_BIT_PROPRIETARY; + } + + if(adv_data->ble_adv_data.tx_power != 0) + { + data_mask |= BTM_BLE_AD_BIT_TX_PWR; + } + + BTA_DmBleSetAdvConfig(data_mask, &(adv_data->ble_adv_data), p_adv_data_cback); +} + + +/******************************************************************************* +** +** Function ESP_BleSetScanRsp +** +** Description This function is called to override the app scan response. +** +** Parameters Pointer to User defined ADV data structure +** +** Returns None +** +*******************************************************************************/ +void ESP_AppBleSetScanRsp(tESP_BLE_ADV_DATA *scan_rsp_data, + tBTA_SET_ADV_DATA_CMPL_CBACK *p_scan_rsp_data_cback) +{ + tBTA_BLE_AD_MASK data_mask = 0; + if(scan_rsp_data->adv_name != NULL) + { + data_mask |= BTM_BLE_AD_BIT_DEV_NAME; + BTA_DmSetDeviceName(scan_rsp_data->adv_name); + } + if(scan_rsp_data->ble_adv_data.int_range.low != 0 || + scan_rsp_data->ble_adv_data.int_range.hi != 0) + data_mask |= BTM_BLE_AD_BIT_INT_RANGE; + + if(scan_rsp_data->ble_adv_data.p_manu != NULL) + { + data_mask |= BTM_BLE_AD_BIT_MANU; + } + + if(scan_rsp_data->ble_adv_data.p_services != NULL) + { + data_mask |= BTM_BLE_AD_BIT_SERVICE; + } + + if(scan_rsp_data->ble_adv_data.p_service_32b != NULL) + { + data_mask |= BTM_BLE_AD_BIT_SERVICE_32; + } + + if(scan_rsp_data->ble_adv_data.p_services_128b != NULL) + { + data_mask |= BTM_BLE_AD_BIT_SERVICE_128; + } + + if(scan_rsp_data->ble_adv_data.p_sol_services != NULL) + { + data_mask |= BTM_BLE_AD_BIT_SERVICE_SOL; + } + + if(scan_rsp_data->ble_adv_data.p_sol_service_32b != NULL) + { + data_mask |= BTM_BLE_AD_BIT_SERVICE_32SOL; + } + + if(scan_rsp_data->ble_adv_data.p_sol_service_128b != NULL) + { + data_mask |= BTM_BLE_AD_BIT_SERVICE_128SOL; + } + + if(scan_rsp_data->ble_adv_data.p_service_data != NULL) + { + data_mask |= BTM_BLE_AD_BIT_SERVICE_DATA; + } + + if(scan_rsp_data->ble_adv_data.appearance != 0) + { + data_mask |= BTM_BLE_AD_BIT_APPEARANCE; + } + + if(scan_rsp_data->ble_adv_data.p_proprietary != NULL) + { + data_mask |= BTM_BLE_AD_BIT_PROPRIETARY; + } + + if(scan_rsp_data->ble_adv_data.tx_power != 0) + { + data_mask |= BTM_BLE_AD_BIT_TX_PWR; + } + + BTA_DmBleSetScanRsp(data_mask, &(scan_rsp_data->ble_adv_data), p_scan_rsp_data_cback); +} + + diff --git a/components/bt/bluedroid/app/app_core/bt_app_core.c b/components/bt/bluedroid/app/app_core/bt_app_core.c new file mode 100644 index 0000000000..40c64778a3 --- /dev/null +++ b/components/bt/bluedroid/app/app_core/bt_app_core.c @@ -0,0 +1,384 @@ +#include +#include +#include + +#include "fixed_queue.h" +#include "gki.h" +#include "bt_defs.h" +#include "bt_trace.h" +#include "bt_types.h" +#include "allocator.h" + +#include "bta_api.h" +#include "bta_gatt_api.h" +#include "bt_app_common.h" + +#include "controller.h" + +#include "hash_map.h" +#include "hash_functions.h" +#include "alarm.h" +#include "app_button.h" +#include "button_pro.h" +#include "thread.h" +#include "bt_app_common.h" +#include "gatt_profile.h" +#include "gattc_profile.h" +#include "smp_int.h" +#include "smp_api.h" + +static fixed_queue_t *bta_app1_msg_queue; +fixed_queue_t *bt_app1_general_alarm_queue; +hash_map_t *bt_app1_general_alarm_hash_map; +pthread_mutex_t bt_app1_general_alarm_lock; +static const size_t BT_APP1_GENERAL_ALARM_HASH_MAP_SIZE = 10; + +xQueueHandle xBtaApp1Queue; +xTaskHandle xBtaApp1TaskHandle; + +#define BT_APP1_TTYPE_MAIN_ENTRY (1) +static TIMER_LIST_ENT main_boot_tle; + +tSMP_CB smp_cmd; + +static void bt_app1_context_switched(void *p_msg); +static void bt_app1_send_msg(void *p_msg); +static void bt_app1_task_handler(void *arg); +static void bta_app1_msg_ready(fixed_queue_t *queue); +static void bt_app1_task_shut_down(void); + +static void bt_app1_general_alarm_ready(fixed_queue_t *queue); +static void bt_app1_general_alarm_process(TIMER_LIST_ENT *p_tle); +void bt_app1_start_timer(TIMER_LIST_ENT *p_tle, UINT16 type, UINT32 timeout_sec); + +//extern void ble_test_conn(void); +//extern void bt_test_start_inquiry(void); +extern void ble_server_test(void); + +static void bt_app1_task_handler(void *arg) +{ + TaskEvt_t *e; + UINT8 button_msg[2] = {0x01,0x00}; + for (;;) { + if (pdTRUE == xQueueReceive(xBtaApp1Queue, &e, (portTickType)portMAX_DELAY)) { + if (e->sig == 0xff) { + fixed_queue_process(bta_app1_msg_queue); + fixed_queue_process(bt_app1_general_alarm_queue); + }else if(e->sig == BUTTON_PRESS_EVT){ + LOG_ERROR("button_press_event come in,button_value=%x\n",e->par); + button_msg[1] = e->par; + button_msg_notify(2,button_msg); +} + } + osi_free(e); + } +} + +static void bt_app1_task_post(void) +{ + + TaskEvt_t *evt = (TaskEvt_t *)osi_malloc(sizeof(TaskEvt_t)); + if (evt == NULL) + return; + + evt->sig = 0xff; + evt->par = 0; + + if (xQueueSend(xBtaApp1Queue, &evt, 10/portTICK_RATE_MS) != pdTRUE) { + ets_printf("btdm_post failed\n"); + } + +} + + +static void bta_app1_msg_ready(fixed_queue_t *queue) { + BT_HDR *p_msg; + while (!fixed_queue_is_empty(queue)) { + p_msg = (BT_HDR *)fixed_queue_dequeue(queue); + LOG_ERROR("bta_app1_msg_ready, evt: %d\n", p_msg->event); + switch (p_msg->event) { + case BT_EVT_APP1_CONTEXT_SWITCH: + bt_app1_context_switched(p_msg); + break; + default: + LOG_ERROR("unhandled BT_APP1 event (%d)\n", p_msg->event & BT_EVT_MASK); + break; + } + GKI_freebuf(p_msg); + } +} + +static void bt_app1_context_switched(void *p_msg) +{ + tBTAPP1_CONTEXT_SWITCH_CBACK *p = (tBTAPP1_CONTEXT_SWITCH_CBACK *) p_msg; + + if (p->p_cb) + p->p_cb(p->event, p->p_param); +} + +static void bt_app1_send_msg(void *p_msg) +{ + if (bta_app1_msg_queue) { + fixed_queue_enqueue(bta_app1_msg_queue, p_msg); + //ke_event_set(KE_EVENT_BT_APP1_TASK); + bt_app1_task_post(); + } +} + +bt_status_t bt_app1_transfer_context (tBTAPP1_CBACK *p_cback, UINT16 event, char* p_params, int param_len, tBTAPP1_COPY_CBACK *p_copy_cback) +{ + tBTAPP1_CONTEXT_SWITCH_CBACK *p_msg; + + LOG_ERROR("btapp1_transfer_context evt %d, len %d", event, param_len); + + /* allocate and send message that will be executed in btif context */ + if ((p_msg = (tBTAPP1_CONTEXT_SWITCH_CBACK *) GKI_getbuf(sizeof(tBTAPP1_CONTEXT_SWITCH_CBACK) + param_len)) != NULL) + { + p_msg->hdr.event = BT_EVT_APP1_CONTEXT_SWITCH; /* internal event */ + p_msg->p_cb = p_cback; + + p_msg->event = event; /* callback event */ + + /* check if caller has provided a copy callback to do the deep copy */ + if (p_copy_cback) + { + p_copy_cback(event, p_msg->p_param, p_params); + } + else if (p_params) + { + memcpy(p_msg->p_param, p_params, param_len); /* callback parameter data */ + } + + bt_app1_send_msg(p_msg); + return BT_STATUS_SUCCESS; + } + else + { + /* let caller deal with a failed allocation */ + return BT_STATUS_NOMEM; + } +} + +void bt_app1_task_start_up(void) +{ + bta_app1_msg_queue = fixed_queue_new(SIZE_MAX); + if (bta_app1_msg_queue == NULL) + goto error_exit; + //ke_event_callback_set(KE_EVENT_BT_APP1_TASK, &bt_app1_task_handler); + + xBtaApp1Queue = xQueueCreate(3, sizeof(void *)); + xTaskCreate(bt_app1_task_handler, "BtaApp1T", 8192, NULL, configMAX_PRIORITIES - 3, xBtaApp1TaskHandle); + + fixed_queue_register_dequeue(bta_app1_msg_queue, bta_app1_msg_ready); + + bt_app1_general_alarm_hash_map = hash_map_new(BT_APP1_GENERAL_ALARM_HASH_MAP_SIZE, + hash_function_pointer, NULL, (data_free_fn)osi_alarm_free, NULL); + if (bt_app1_general_alarm_hash_map == NULL) + goto error_exit; + + pthread_mutex_init(&bt_app1_general_alarm_lock, NULL); + + bt_app1_general_alarm_queue = fixed_queue_new(SIZE_MAX); + if (bt_app1_general_alarm_queue == NULL) + goto error_exit; + fixed_queue_register_dequeue(bt_app1_general_alarm_queue, bt_app1_general_alarm_ready); + + memset(&main_boot_tle, 0, sizeof(TIMER_LIST_ENT)); + return; + +error_exit: + LOG_ERROR("%s Unable to allocate resources for bt_app1", __func__); + bt_app1_task_shut_down(); +} + +static void bt_app1_task_shut_down(void) +{ + fixed_queue_unregister_dequeue(bta_app1_msg_queue); + fixed_queue_free(bta_app1_msg_queue, NULL); + bta_app1_msg_queue = NULL; + + // todo: hash map, pthread_mutex... + fixed_queue_unregister_dequeue(bt_app1_general_alarm_queue); + + vTaskDelete(xBtaApp1TaskHandle); + vTaskDelete(xBtaApp1Queue); +} + + +static void bt_app1_dm_data_copy(uint16_t event, char *dst, char *src) +{ + tBTA_DM_SEC *dst_dm_sec = (tBTA_DM_SEC*)dst; + tBTA_DM_SEC *src_dm_sec = (tBTA_DM_SEC*)src; + + if (!src_dm_sec) + return; + + assert(dst_dm_sec); + memcpy(dst_dm_sec, src_dm_sec, sizeof(tBTA_DM_SEC)); + + if (event == BTA_DM_BLE_KEY_EVT) + { + dst_dm_sec->ble_key.p_key_value = osi_malloc(sizeof(tBTM_LE_KEY_VALUE)); + assert(src_dm_sec->ble_key.p_key_value); + assert(dst_dm_sec->ble_key.p_key_value); + memcpy(dst_dm_sec->ble_key.p_key_value, src_dm_sec->ble_key.p_key_value, sizeof(tBTM_LE_KEY_VALUE)); + } +} + +static void bt_app1_dm_data_free(uint16_t event, tBTA_DM_SEC *dm_sec) +{ + if (event == BTA_DM_BLE_KEY_EVT) + osi_free(dm_sec->ble_key.p_key_value); +} + +static void bt_app1_dm_upstreams_evt(UINT16 event, char *p_param) +{ + tBTA_DM_SEC *p_data = (tBTA_DM_SEC*)p_param; + switch (event) { + case BTA_DM_ENABLE_EVT: { + +// BTA_DmSetDeviceName("ijiazu"); + + + + + /*set connectable,discoverable, pairable and paired only modes of local device*/ + tBTA_DM_DISC disc_mode = BTA_DM_GENERAL_DISC | BTA_DM_BLE_GENERAL_DISCOVERABLE; + tBTA_DM_CONN conn_mode = BTA_DM_CONN | BTA_DM_BLE_CONNECTABLE; + BTA_DmSetVisibility(disc_mode, conn_mode, BTA_DM_IGNORE, BTA_DM_IGNORE); + +#if (defined(BLE_INCLUDED) && (BLE_INCLUDED == TRUE)) + /* Enable local privacy */ + BTA_DmBleConfigLocalPrivacy(BLE_LOCAL_PRIVACY_ENABLED); + do { + const controller_t *controller = controller_get_interface(); + char bdstr[18]; + bdaddr_to_string(controller->get_address(), bdstr, sizeof(bdstr)); + LOG_ERROR("BDA is: %s\n", bdstr); + } while (0); +#endif + } + break; + case BTA_DM_BLE_SEC_REQ_EVT: + + smp_cmd.local_io_capability = 0x03; //no input no output + smp_cmd.loc_oob_flag = 0x00; //oob data not present + smp_cmd.loc_auth_req = 0x05; + smp_cmd.loc_enc_size = 0x10; + smp_cmd.local_i_key = 0x07; + smp_cmd.local_r_key = 0x07; + memcpy(smp_cmd.pairing_bda,p_data->ble_req.bd_addr,0x06); + smp_send_cmd(SMP_OPCODE_PAIRING_RSP,&smp_cmd); + smp_set_state(SMP_STATE_WAIT_CONFIRM); + //BTA_DmConfirm(p_data->ble_req.bd_addr,true); + break; + default: + break; + } + + bt_app1_dm_data_free(event, p_data); +} + +static void bte_dm_evt(tBTA_DM_SEC_EVT event, tBTA_DM_SEC* p_data) +{ + LOG_ERROR("bte_dm_evt: %d\n", (uint16_t)event); + bt_app1_transfer_context(bt_app1_dm_upstreams_evt, (uint16_t)event, + (void *)p_data, sizeof(tBTA_DM_SEC), bt_app1_dm_data_copy); +} + +void bt_app1_init_ok(UNUSED_ATTR uint16_t event, UNUSED_ATTR char *p_param) +{ + BTA_EnableBluetooth(bte_dm_evt); + vTaskDelay(1000 / portTICK_PERIOD_MS); + bt_app1_start_timer(&main_boot_tle, BT_APP1_TTYPE_MAIN_ENTRY, 8); +} + +/* Alarm timer */ +static void bt_app1_general_alarm_cb(void *data) { + assert(data != NULL); + TIMER_LIST_ENT *p_tle = (TIMER_LIST_ENT *)data; + + fixed_queue_enqueue(bt_app1_general_alarm_queue, p_tle); + //ke_event_set(KE_EVENT_BT_APP1_TASK); + bt_app1_task_post(); +} + +void bt_app1_start_timer(TIMER_LIST_ENT *p_tle, UINT16 type, UINT32 timeout_sec) { + osi_alarm_t *alarm = NULL; + + assert(p_tle != NULL); + + // Get the alarm for the timer list entry. + pthread_mutex_lock(&bt_app1_general_alarm_lock); + if (!hash_map_has_key(bt_app1_general_alarm_hash_map, p_tle)) { + alarm = osi_alarm_new("bt_app1", bt_app1_general_alarm_cb, (void *)p_tle, 0); + hash_map_set(bt_app1_general_alarm_hash_map, p_tle, alarm); + } + pthread_mutex_unlock(&bt_app1_general_alarm_lock); + + pthread_mutex_lock(&bt_app1_general_alarm_lock); + alarm = hash_map_get(bt_app1_general_alarm_hash_map, p_tle); + pthread_mutex_unlock(&bt_app1_general_alarm_lock); + if (alarm == NULL) { + LOG_ERROR("%s Unable to create alarm", __func__); + + return; + } + + osi_alarm_cancel(alarm); + + p_tle->event = type; + // NOTE: This value is in seconds but stored in a ticks field. + p_tle->ticks = timeout_sec; + p_tle->in_use = TRUE; + osi_alarm_set(alarm, (period_ms_t)(timeout_sec * 1000)); +} + +void bt_app1_stop_timer(TIMER_LIST_ENT *p_tle) +{ + assert(p_tle != NULL); + + if (p_tle->in_use == FALSE) + return; + p_tle->in_use = FALSE; + + // Get the alarm for the timer list entry. + osi_alarm_t *alarm = hash_map_get(bt_app1_general_alarm_hash_map, p_tle); + if (alarm == NULL) { + LOG_WARN("%s Unable to find expected alarm in hashmap", __func__); + return; + } + osi_alarm_cancel(alarm); +} + +static void bt_app1_general_alarm_process(TIMER_LIST_ENT *p_tle) +{ + assert(p_tle != NULL); + LOG_ERROR("general_alarm_process\n"); + switch (p_tle->event) { + case BT_APP1_TTYPE_MAIN_ENTRY: + LOG_ERROR("BT_APP1 main boot**********\n"); + + // ble_test_conn(); + // ble_server_test(); + + + // bt_test_start_inquiry(); + + gatts_server_test(); + //gattc_client_test(); + break; + } + +} + +static void bt_app1_general_alarm_ready(fixed_queue_t *queue) +{ + TIMER_LIST_ENT *p_tle; + + while (!fixed_queue_is_empty(queue)) { + p_tle = (TIMER_LIST_ENT *)fixed_queue_dequeue(queue); + bt_app1_general_alarm_process(p_tle); + } +} + diff --git a/components/bt/bluedroid/app/app_profiles/app_sample_button/app_button.c b/components/bt/bluedroid/app/app_profiles/app_sample_button/app_button.c new file mode 100644 index 0000000000..38f5f950ea --- /dev/null +++ b/components/bt/bluedroid/app/app_profiles/app_sample_button/app_button.c @@ -0,0 +1,225 @@ +/** + +******************************************************************************* +********* + * + * @file app_button.c + * + * @brief button Service Application entry point + * + * Copyright (C) ESPRESSSIF 2016 + * Created by Yulong at 2016/08/24 + * + * + +******************************************************************************* +********* +*/ +#if 0 +#include +#include +#include +#include + + +#include "rom/gpio.h" +#include "app_button.h" +#include "bt_trace.h" +#include "freertos/FreeRTOS.h" +#include "freertos/timers.h" +#include "freertos/task.h" +#include "freertos/xtensa_api.h" +#include "thread.h" + +#include "allocator.h" +#include "button_pro.h" +#define GPIO_INUM 8 +#define TABLE_ELEMENT_CNT(table) ((sizeof(table))/(sizeof(table[0]))); +app_key_env key_press; + +uint8_t gpio_test_table[]={0,2,4,5,12,13,14,15,16,17,18,19,20,21,22,23,25,26,27,33,34,35,36,37,38,39}; + +struct gpio_test_info{ + uint8_t *gpio_test_table; + uint8_t gpio_test_num; + void *time_s; +}; + +static void gpio_irq_init(uint64_t gpio_num); + +void gpio_check_register(enum_gpio_num_t gpio_num) +{ + if(gpio_num>=GPIO_PIN_COUNT||0==GPIO_PIN_MUX_REG[gpio_num]){ + ets_printf("io_num=%d not exits\n",gpio_num); + return; + } + LOG_ERROR("---------gpio_num %d reg----------\n",gpio_num); +LOG_ERROR("GPIO_IOMUX_%d=0x%08x\n",gpio_num,READ_PERI_REG(GPIO_PIN_MUX_REG[gpio_num])); + LOG_ERROR("GPIO_PIN%d_ADDR=0x%08x\n",gpio_num,READ_PERI_REG(GPIO_PIN_ADDR(gpio_num))); + LOG_ERROR("GPIO_OUT_REG=0x%08x\n",READ_PERI_REG(GPIO_OUT_REG)); + LOG_ERROR("GPIO_OUT1_REG=0x%08x\n",READ_PERI_REG(GPIO_OUT1_REG)); + LOG_ERROR("GPIO_ENABLE_REG=0x%08x\n",READ_PERI_REG(GPIO_ENABLE_REG)); + LOG_ERROR("GPIO_ENABLE1_REG=0x%08x\n",READ_PERI_REG(GPIO_ENABLE1_REG)); + LOG_ERROR("GPIO_IN_REG=0x%08x\n",READ_PERI_REG(GPIO_IN_REG)); + LOG_ERROR("GPIO_IN1_REG=0x%08x\n",READ_PERI_REG(GPIO_IN1_REG)); + LOG_ERROR("GPIO_STATUS_REG=0x%08x\n",READ_PERI_REG(GPIO_STATUS_REG)); + LOG_ERROR("GPIO_STATUS1_REG=0x%08x\n",READ_PERI_REG(GPIO_STATUS1_REG)); +} + +void t1_callback(void *arg) +{ + static uint8_t level=0; + static uint8_t cnt=0; + uint8_t err_flag=0; + struct gpio_test_info *gpio_test=(struct gpio_test_info*)(arg); + uint8_t i=0; + while(1){ + gpio_check_register(35); + vTaskDelay(2*1000); + /* + level=~level; + LOG_ERROR("Test cnt %u, level %u\n",cnt+1,level&0x01); + for(i=0;igpio_test_num;i++){ + gpio_set_output_level(gpio_test->gpio_test_table[i],level&0x01); + if(gpio_get_input_level(gpio_test->gpio_test_table[i])!=(level&0x01)) + { + err_flag=1; + LOG_ERROR("[ERR] GPIO%u set_level %u get_level %u\n",gpio_test->gpio_test_table[i],level&0x01,gpio_get_input_level(gpio_test->gpio_test_table[i])); + } + else{ + LOG_ERROR("GPIO%u OK\n",gpio_test->gpio_test_table[i]); + } + } + cnt++; + if(err_flag==0){ + LOG_ERROR("cnt %u test ok\n",cnt); + } + err_flag=0; + if(cnt>=10){ + LOG_ERROR("Gpio input and output test end\n"); + vTaskDelete(NULL);*/ + // } + + //vTaskDelay(2*1000); + + } +} + + void app_button_init(void) +{ + uint64_t gpio_num = GPIO_Pin_27|GPIO_Pin_35|GPIO_Pin_34|GPIO_Pin_36|GPIO_Pin_39; + // Reset environment + memset(&key_press, 0, sizeof(key_press)); + gpio_irq_init(gpio_num); + static struct gpio_test_info gpio_test_infor; + LOG_ERROR("app_button_init."); +/* TimerHandle_t t1=NULL; + t1=xTimerCreate("t1_time",(1000/portTICK_PERIOD_MS),pdTRUE,&gpio_test_infor,t1_callback); + do{ + gpio_test_infor.gpio_test_table=gpio_test_table; + gpio_test_infor.gpio_test_num=TABLE_ELEMENT_CNT(gpio_test_table); + gpio_test_infor.time_s=t1; + }while(0);*/ + + // xTaskCreate(t1_callback,"t1_callback",1024,&gpio_test_infor,30,NULL); + LOG_ERROR("gpio_input_output_demo\n"); + return; +} + +static void gpio_irq_init(uint64_t gpio_num) +{ + gpio_config_t gpio_config_prot; + memset(&gpio_config_prot,0,sizeof(gpio_config_prot)); + gpio_config_prot.GPIO_Pin= gpio_num; + + gpio_config_prot.GPIO_Mode=GPIO_Mode_Input; + gpio_config_prot.GPIO_IntrType=GPIO_PIN_INTR_NEGEDGE; + gpio_config_prot.GPIO_Pullup=GPIO_PullUp_EN; + gpio_config_prot.GPIO_Pulldown=GPIO_PullDown_DIS; + gpio_config(&gpio_config_prot); + //Register gpio handler + gpio_intr_handler_register(GPIO_isr_callback,NULL); + //Enable gpio intr + xt_ints_on(1<par = Button_Voice; + break; + case GPIO_NUM_34: + evt->par = Button_OK; + break; + case GPIO_NUM_39: + evt->par = Button_Down; + break; + case GPIO_NUM_36: + evt->par = Button_Up; + break; + default: + evt->par = Button_Back; + break; + } + evt->sig = BUTTON_PRESS_EVT; + if(xQueueSend(xBtaApp1Queue,&evt,10/portTICK_RATE_MS)!=pdTRUE){ + LOG_ERROR("btdm_post_failed\n"); + } + //enable the interrupt + xt_ints_on(1< +#include +#include +#include + +#include "bta_api.h" +#include "bta_gatt_api.h" +#include "controller.h" + +#include "gatt_int.h" +#include "bt_trace.h" +#include "btm_api.h" +#include "bt_types.h" +#include "gatt_profile.h" +#include "bt_app_common.h" + +//#include "app_button.h" +//#include "button_pro.h" +#include "hid_le_prf.h" +#include "prf_defs.h" +#include "hcimsgs.h" +#include "bt_app_defs.h" + + +#define BT_BD_ADDR_STR "%02x:%02x:%02x:%02x:%02x:%02x" +#define BT_BD_ADDR_HEX(addr) addr[0], addr[1], addr[2], addr[3], addr[4], addr[5] +tBTA_GATTS_IF server_if; + +static unsigned char DIS_UUID[16] = { + 0xfb, 0x34, 0x9b, 0x5f, 0x80, 0x00, 0x00, 0x80, + 0x00, 0x10, 0x00, 0x00, 0x0a, 0x18, 0x00, 0x00 + }; +static unsigned char BASE_UUID[16] = { + 0xfb, 0x34, 0x9b, 0x5f, 0x80, 0x00, 0x00, 0x80, + 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }; + +UINT16 ijiazu_uuid = 0xffff; +tBTA_BLE_SERVICE ijiazu_service = { + 0x01, //only one service in the ijiazu button profile + false, + &ijiazu_uuid + }; /* 16 bits services */ + + +UINT8 beacon_manu[25] = {0x4c, 0x00,0x02, 0x15, 0xfd, 0xa5, 0x06, 0x93, 0xa4, 0xe2, + 0x4f, 0xb1, 0xaf, 0xcf, 0xc6, 0xeb, 0x07, 0x64, 0x78, 0x25, + 0x27, 0x32, 0xe6, 0x08, 0xc5}; + +//UINT8 ijiazu_manu[17] = {0xff,0x20,0x14,0x07,0x22,0x00,0x02,0x5B,0x00,0x33,0x49,0x31,0x30,0x4a,0x30,0x30,0x31}; +UINT8 ijiazu_manu[17] = {0xff,0x20,0x14,0x07,0x22,0x00,0x02,0x5B,0x00,0x33,0x49,0x31,0x30,0x4a,0x30,0x30,0x31}; +tBTA_BLE_MANU p_ijiazu_manu = {sizeof(ijiazu_manu),ijiazu_manu}; /* manufacturer data */ + + +BD_ADDR rand_ijiazu_addr = {0x00,0x02,0x5B,0x00,0x32,0x55}; + +tESP_BLE_ADV_DATA ijiazu_adv_data[ADV_SCAN_IDX_MAX] = +{ + [BLE_ADV_DATA_IDX] = { + .adv_name = "esp_server", + { + {0,0}, + NULL, //no manufature data to be setting in the ijiazu adervetisiing datas + &ijiazu_service, + NULL, //the 128 bits service uuid set to null(not used) + NULL, //the 32 bits Service UUID set to null(not used) + NULL, //16 bits services Solicitation UUIDs set to null(not used) + NULL, //List of 32 bit Service Solicitation UUIDs set to null(not used) + NULL, //List of 128 bit Service Solicitation UUIDs set to null(not used) + NULL, //proprietary data set to null(not used) + NULL, //service data set not null(no service data to be sent) + 0x0200, //device type : generic display + BTA_DM_GENERAL_DISC, // General discoverable. + 0xFE //the tx power value,defult value is 0 + }, + + }, + [BLE_SCAN_RSP_DATA_IDX] = { + .adv_name = NULL, + { + {0,0}, + &p_ijiazu_manu, + NULL, + NULL, //the 128 bits service uuid set to null(not used) + NULL, //the 32 bits Service UUID set to null(not used) + NULL, //16 bits services Solicitation UUIDs set to null(not used) + NULL, //List of 32 bit Service Solicitation UUIDs set to null(not used) + NULL, //List of 128 bit Service Solicitation UUIDs set to null(not used) + NULL, //proprietary data set to null(not used) + NULL, //service data set not null(no service data to be sent) + 0x0000, //device type : generic display + 0x00, // General discoverable. + 0x00}, //the tx power value,defult value is 0 + + } +}; + + +typedef struct { + uint8_t uu[16]; +} bt_uuid_t; + +int uuidType(unsigned char* p_uuid) +{ + int i = 0; + int match = 0; + int all_zero = 1; + + for(i = 0; i != 16; ++i) + { + if (i == 12 || i == 13) + continue; + + if (p_uuid[i] == BASE_UUID[i]) + ++match; + + if (p_uuid[i] != 0) + all_zero = 0; + } + if (all_zero) + return 0; + if (match == 12) + return LEN_UUID_32; + if (match == 14) + return LEN_UUID_16; + return LEN_UUID_128; +} + +/*16-bits uuid to the structure of holding any type of UUID*/ +void btif_to_bta_uuid(tBT_UUID *p_dest, bt_uuid_t *p_src) +{ + char *p_byte = (char*)p_src; + + int i = 0; + + p_dest->len = uuidType(p_src->uu); + + switch (p_dest->len) + { + case LEN_UUID_16: + p_dest->uu.uuid16 = (p_src->uu[13] << 8) + p_src->uu[12]; + break; + + case LEN_UUID_32: + p_dest->uu.uuid32 = (p_src->uu[13] << 8) + p_src->uu[12]; + p_dest->uu.uuid32 += (p_src->uu[15] << 24) + (p_src->uu[14] << 16); + break; + + case LEN_UUID_128: + for(i = 0; i != 16; ++i) + p_dest->uu.uuid128[i] = p_byte[i]; + break; + + default: + LOG_ERROR("%s: Unknown UUID length %d!", __FUNCTION__, p_dest->len); + break; + } +} +/*set advertising config callback*/ +static void bta_gatts_set_adv_data_cback(tBTA_STATUS call_status) +{ + LOG_ERROR("set advertising config:status=%d\n", call_status); + /*dis init*/ +/* tDIS_ATTR_MASK dis_attr_mask; + dis_attr_mask = DIS_ATTR_SYS_ID_BIT | DIS_ATTR_MODEL_NUM_BIT | DIS_ATTR_SERIAL_NUM_BIT | + DIS_ATTR_FW_NUM_BIT | DIS_ATTR_HW_NUM_BIT | DIS_ATTR_SW_NUM_BIT | DIS_ATTR_MANU_NAME_BIT | + DIS_ATTR_IEEE_DATA_BIT | DIS_ATTR_PNP_ID_BIT; + DIS_SrInit(dis_attr_mask); +*/ + /*instantiate a battery service*/ + bas_register(); + /*instantiate the driver for button profile*/ + //app_button_init(); + /*instantiate a button service*/ + //button_init(); + /*instantiate a hid device service*/ + hidd_le_init(); + /*start advetising*/ +// BTA_GATTS_Listen(server_if, true, NULL); +} + +/*register callback*/ +void bta_gatts_callback(tBTA_GATTS_EVT event, tBTA_GATTS* p_data) +{ + switch (event) + { + case BTA_GATTS_REG_EVT: + { + tBTA_GATT_STATUS status = p_data->reg_oper.status; + server_if = p_data->reg_oper.server_if; + LOG_ERROR("register complete: event=%d, status=%d, server_if=%d\n", + event, status, server_if); + + LOG_ERROR("set advertising parameters\n"); + //set the advertising data to the btm layer + ESP_AppBleConfigadvData(&ijiazu_adv_data[BLE_ADV_DATA_IDX], + bta_gatts_set_adv_data_cback); + //set the adversting data to the btm layer + ESP_AppBleSetScanRsp(&ijiazu_adv_data[BLE_SCAN_RSP_DATA_IDX],NULL); + + } + break; + /*connect callback*/ + case BTA_GATTS_CONNECT_EVT: + { + LOG_ERROR("\ndevice is connected "BT_BD_ADDR_STR", server_if=%d,reason=0x%x,connect_id=%d\n", + BT_BD_ADDR_HEX(p_data->conn.remote_bda), p_data->conn.server_if, + p_data->conn.reason, p_data->conn.conn_id); + /*return whether the remote device is currently connected*/ + int is_connected = BTA_DmGetConnectionState(p_data->conn.remote_bda); + LOG_ERROR("is_connected=%d\n",is_connected); + } + break; + + default: + LOG_ERROR("unsettled event: %d\n", event); + } + +} + +static void ble_server_appRegister(void) +{ + bt_uuid_t uuid; + tBT_UUID t_uuid; + memcpy(&uuid, BASE_UUID, sizeof(bt_uuid_t)); + //memcpy(&uuid, DIS_UUID, sizeof(bt_uuid_t)); + btif_to_bta_uuid(&t_uuid, &uuid); + + LOG_ERROR("register gatts application\n"); + BTA_GATTS_AppRegister(&t_uuid, bta_gatts_callback); +} + +void gatts_server_test(void) +{ + BTM_SetTraceLevel(BT_TRACE_LEVEL_DEBUG); + + ble_server_appRegister(); +} diff --git a/components/bt/bluedroid/app/app_project/SampleClientProject.c b/components/bt/bluedroid/app/app_project/SampleClientProject.c new file mode 100644 index 0000000000..639e732606 --- /dev/null +++ b/components/bt/bluedroid/app/app_project/SampleClientProject.c @@ -0,0 +1,381 @@ +/**************************************************************************** +* +* This file is for gatt client. It can scan ble device, connect one device, +* +****************************************************************************/ + +#include +#include +#include +#include + +#include "bta_api.h" +#include "bta_gatt_api.h" +#include "controller.h" + +#include "bt_trace.h" +#include "btm_api.h" +#include "bt_types.h" +#include "gattc_profile.h" + +#define BT_BD_ADDR_STR "%02x:%02x:%02x:%02x:%02x:%02x" +#define BT_BD_ADDR_HEX(addr) addr[0], addr[1], addr[2], addr[3], addr[4], addr[5] + +tBTA_GATTC_IF client_if; +BD_ADDR obj_addr; +static unsigned char BASE_UUID[16] = { + 0xfb, 0x34, 0x9b, 0x5f, 0x80, 0x00, 0x00, 0x80, + 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }; + +typedef struct { + uint8_t uu[16]; +} bt_uuid_t; + +int uuidType(unsigned char* p_uuid) +{ + int i = 0; + int match = 0; + int all_zero = 1; + + for(i = 0; i != 16; ++i) + { + if (i == 12 || i == 13) + continue; + + if (p_uuid[i] == BASE_UUID[i]) + ++match; + + if (p_uuid[i] != 0) + all_zero = 0; + } + if (all_zero) + return 0; + if (match == 12) + return LEN_UUID_32; + if (match == 14) + return LEN_UUID_16; + return LEN_UUID_128; +} + +static void btif_to_bta_uuid(tBT_UUID *p_dest, bt_uuid_t *p_src) +{ + char *p_byte = (char*)p_src; + + int i = 0; + + p_dest->len = uuidType(p_src->uu); + + switch (p_dest->len) + { + case LEN_UUID_16: + p_dest->uu.uuid16 = (p_src->uu[13] << 8) + p_src->uu[12]; + break; + + case LEN_UUID_32: + p_dest->uu.uuid32 = (p_src->uu[13] << 8) + p_src->uu[12]; + p_dest->uu.uuid32 += (p_src->uu[15] << 24) + (p_src->uu[14] << 16); + break; + + case LEN_UUID_128: + for(i = 0; i != 16; ++i) + p_dest->uu.uuid128[i] = p_byte[i]; + break; + + default: + LOG_ERROR("%s: Unknown UUID length %d!", __FUNCTION__, p_dest->len); + break; + } +} +/* +uint16_t get_uuid16(tBT_UUID* p_uuid) +{ + if(p_uuid->len == LEN_UUID_16) + { + return p_uuid->uu.uuid16; + } + else if(p_uuid->len == LEN_UUID_128) + { + UINT16 u16; + UINT8 *p = &p_uuid->uu.uuid128[LEN_UUID_128 - 4]; + STREAM_TO_UINT16(u16, p); + return u16; + } + else + { + return (UINT16)p_uuid->uu.uuid32; + } +} + +//fill a GATT ID structure +void bta_le_fill_16bits_gatt_id(UINT8 inst_id, UINT16 uuid, tBTA_GATT_ID* p_output) +{ + p_output->inst_id = inst_id; + p_output->uuid.len = LEN_UUID_16; + p_output->uuid.uu.uuid16 = uuid; +} + +//fill a service ID structure with a 16 bits service UUID +void bta_le_fill_16bits_srvc_id(bool is_pri, UINT8 inst_id, UINT16 srvc_uuid, tBTA_GATT_SRVC_ID* p_output) +{ + memset((void *)p_output, 0, sizeof(tBTA_GATT_SRVC_ID)); + p_output->is_primary = is_pri; + bta_le_fill_16bits_gatt_id(inst_id, srvc_uuid, &p_output->id); +} + +//fill a char ID structure with a 16 bits char UUID +void bta_le_fill_16bits_char_id(UINT8 inst_id, UINT16 char_uuid, tBTA_GATT_ID* p_output) +{ + memset((void *)p_output, 0, sizeof(tBTA_GATT_ID)); + bta_le_fill_16bits_gatt_id(inst_id, char_uuid, p_output); +} +*/ +/*get remote name*/ +static bool check_remote_name(tBTA_DM_INQ_RES* result, uint8_t* rmt_name, uint8_t* rmt_name_len) +{ + uint8_t *p_rmt_name = NULL; + uint8_t remote_name_len = 0; + + if (result->p_eir) { + p_rmt_name = BTM_CheckEirData(result->p_eir, + BTM_EIR_COMPLETE_LOCAL_NAME_TYPE, + &remote_name_len); + if (!p_rmt_name) + p_rmt_name = BTM_CheckEirData(result->p_eir, + BTM_EIR_SHORTENED_LOCAL_NAME_TYPE, + &remote_name_len); + if (p_rmt_name) { + if (remote_name_len > BD_NAME_LEN) + remote_name_len = BD_NAME_LEN; + if (rmt_name && rmt_name_len) { + memcpy(rmt_name, p_rmt_name, remote_name_len); + *(rmt_name + remote_name_len) = 0; + *rmt_name_len = remote_name_len; + } + return true; + } + } + return false; +} + +/************************************************************************************ +* * Function bta_scan_recult_callback +* * +* * Description scan result.it will be called when device scaned a peer device +* * +* * Return NULL +**************************************************************************************/ +static void bta_scan_result_callback(tBTA_DM_SEARCH_EVT event, tBTA_DM_SEARCH* p_data) +{ + uint8_t len; + BD_ADDR bd_addr; + char dev_name[32]; + tBTA_GATT_TRANSPORT transport = BTA_GATT_TRANSPORT_LE; + //char obj_name[] = "Find Me"; + char obj_name[] = "SimpleBLEPeripheral"; + uint8_t dev_name_len; + + switch (event) + { + case BTA_DM_INQ_RES_EVT: + { + LOG_ERROR("scan result: event=%d, "BT_BD_ADDR_STR", device_type=%d\n", + event, BT_BD_ADDR_HEX(p_data->inq_res.bd_addr), p_data->inq_res.device_type); + + bdcpy(bd_addr, p_data->inq_res.bd_addr); + if (p_data->inq_res.p_eir) + { + if (BTM_CheckEirData(p_data->inq_res.p_eir, BTM_EIR_COMPLETE_LOCAL_NAME_TYPE, &len)) + { + p_data->inq_res.remt_name_not_required = TRUE; + } + } + + if(check_remote_name(&(p_data->inq_res), dev_name, &dev_name_len)) + { + LOG_ERROR("scan device name len=%d, name = %s\n", dev_name_len, dev_name); + } + + if(strcmp(dev_name, obj_name) == 0) + { + bdcpy(obj_addr, bd_addr); + LOG_ERROR("find the device, obj_addr="BT_BD_ADDR_STR"\n", BT_BD_ADDR_HEX(obj_addr)); +// BTA_GATTC_Open(client_if, obj_addr, true, transport); + } + } + break; + + case BTA_DM_INQ_CMPL_EVT: + { + LOG_ERROR("%s-BLE observe complete. Num Resp %d\n", __FUNCTION__, p_data->inq_cmpl.num_resps); + + LOG_ERROR("connect the device "BT_BD_ADDR_STR", client_if=%d\n", + BT_BD_ADDR_HEX(obj_addr), client_if); + +/* scan complete, start connect*/ + BTA_GATTC_Open(client_if, obj_addr, true, transport); + } + break; + + default: + LOG_ERROR("%s : unknown event 0x%x", __FUNCTION__, event); + } +} + +/************************************************************************************ +* * Function bta_scan_param_setup_cback +* * +* * Description set scan param callback.it will be called after setting scan parameter +* * +* * Return NULL +**************************************************************************************/ +static void bta_scan_param_setup_cback(tGATT_IF c_client_if, tBTM_STATUS status) +{ + client_if = c_client_if; + LOG_ERROR("\nset scan params complete: status=%d, client_if=%d\n", status, client_if); + /*start scan*/ + BTA_DmBleObserve(true, 8, bta_scan_result_callback); +} + +/************************************************************************************ +* * Function bta_gattc_callback +* * +* * Description app register callback +* * +* * Return NULL +**************************************************************************************/ +static void bta_gattc_callback(tBTA_GATTC_EVT event, tBTA_GATTC* p_data) +{ + switch (event) + { + case BTA_GATTC_REG_EVT: + { + tBTA_GATT_STATUS status = p_data->reg_oper.status; + client_if = p_data->reg_oper.client_if; + LOG_ERROR("%s:register complete: event=%d, status=%d, client_if=%d\n", __FUNCTION__, event, status, client_if); + UINT8 scan_interval = 0x50; + UINT8 scan_window = 0x30; + tBLE_SCAN_MODE scan_mode = BTM_BLE_SCAN_MODE_ACTI; + + bac_register(); + /*register complete,set scan parameter*/ + BTA_DmSetBleScanParams(client_if, scan_interval, scan_window, scan_mode, + bta_scan_param_setup_cback); + + } + break; + + /*connect callback*/ + case BTA_GATTC_OPEN_EVT: + { + + LOG_ERROR("\n%s:device is connected "BT_BD_ADDR_STR", client_if=%d, status=%d, connect_id=%d\n", + __FUNCTION__, BT_BD_ADDR_HEX(p_data->open.remote_bda), p_data->open.client_if, + p_data->open.status, p_data->open.conn_id); + /*return whether the remote device is currently connected*/ + int is_connected = BTA_DmGetConnectionState(p_data->open.remote_bda); + LOG_ERROR("is_connected=%d\n",is_connected); + /*get the energy info of the controller*/ + + /*read battery level*/ + int conn_id = p_data->open.conn_id; + + /*discover service*/ + // BTA_GATTC_ServiceSearchRequest(conn_id, NULL); + + } + break; +/* + case BTA_GATTC_SEARCH_RES_EVT: + { + // tBTA_GATTC_SRVC_RES service_result; + LOG_ERROR("find the service,uuid=0x%x, is_primary=%d\n", + get_uuid16(&p_data->srvc_res.service_uuid.id.uuid), + p_data->srvc_res.service_uuid.is_primary); + } + break; + + case BTA_GATTC_SEARCH_CMPL_EVT: + { + LOG_ERROR("search service complete, conn_id=%d,status=%d\n", p_data->search_cmpl.conn_id, + p_data->search_cmpl.status); + + //get first characteristic of battey service + LOG_ERROR("get first characteristic of battery service\n"); + tBTA_GATT_STATUS status; + tBTA_GATT_SRVC_ID battery_srvc_id; + tBTA_GATTC_CHAR_ID out_char_id; + tGATT_CHAR_PROP out_char_prop; + bta_le_fill_16bits_srvc_id(TRUE, 0, UUID_SERVCLASS_BATTERY, &battery_srvc_id); + status = BTA_GATTC_GetFirstChar(p_data->search_cmpl.conn_id, &battery_srvc_id, NULL, + &out_char_id, &out_char_prop); + if(status == 0) + { + LOG_ERROR("the first char:srvc_id=0x%x,char_id=0x%x, property = %d\n", + get_uuid16(&out_char_id.srvc_id.id.uuid), get_uuid16(&out_char_id.char_id.uuid), + out_char_prop); + //read battery level + tBTA_GATTC_CHAR_ID battery_char_id; + bta_le_fill_16bits_srvc_id(TRUE, 0, UUID_SERVCLASS_BATTERY, &battery_char_id.srvc_id); + bta_le_fill_16bits_char_id(0, GATT_UUID_BATTERY_LEVEL, &battery_char_id.char_id); + + BTA_GATTC_ReadCharacteristic(p_data->search_cmpl.conn_id, &battery_char_id, + BTA_GATT_AUTH_REQ_NONE); + } + } + break; + + case BTA_GATTC_READ_CHAR_EVT: + { + + LOG_ERROR("\nread characteristic:connect_id=%d, status=%d\n", + p_data->read.conn_id, p_data->read.status); + LOG_ERROR("srvc_id=0x%x,char_id=0x%x,descr_type=0x%x\n", + get_uuid16(&p_data->read.srvc_id.id.uuid), + get_uuid16(&p_data->read.char_id.uuid), + get_uuid16(&p_data->read.descr_type.uuid)); + if(get_uuid16(&p_data->read.descr_type.uuid) != GATT_UUID_CHAR_AGG_FORMAT + && p_data->read.p_value->unformat.len > 0 + && p_data->read.p_value->unformat.p_value != NULL) + { + LOG_ERROR("read the value: len=%d, value=%d\n", p_data->read.p_value->unformat.len, + *(p_data->read.p_value->unformat.p_value)); + } + } + break; +*/ + default: + LOG_ERROR("%s:unknown event: %d\n", __FUNCTION__, event); + } + +} + +/************************************************************************************ +* * Function ble_client_appRegister +* * +* * Description app register function +* * +* * Return NULL +**************************************************************************************/ +void ble_client_appRegister(void) +{ + + bt_uuid_t uuid; + tBT_UUID t_uuid; + memcpy(&uuid, BASE_UUID, sizeof(bt_uuid_t)); + btif_to_bta_uuid(&t_uuid, &uuid); + + LOG_ERROR("register application\n"); + BTA_GATTC_AppRegister(&t_uuid, bta_gattc_callback); + + /*battery service register*/ +// bac_register(); + +} + +void gattc_client_test(void) +{ + BTM_SetTraceLevel(BT_TRACE_LEVEL_DEBUG); + + ble_client_appRegister(); +} diff --git a/components/bt/bluedroid/app/include/app_button.h b/components/bt/bluedroid/app/include/app_button.h new file mode 100644 index 0000000000..cde5c9efe0 --- /dev/null +++ b/components/bt/bluedroid/app/include/app_button.h @@ -0,0 +1,62 @@ +/** + **************************************************************************************** + * + * @file app_button.h + * + * @brief button Service Application entry point + * + * Copyright (C) ESPRESSIF 2016 + * Created by Yulong at 2016/02/24 + * + * + **************************************************************************************** + */ + + /* + * DEFINES + **************************************************************************************** + */ +#define BUTTON_HEAD (0x01) +#define BUTTON_PRESS_EVT (0x10) + +//the key value enum +enum +{ + Button_Up = 0x01, + Button_Voice = 0x02, + Button_OK = 0x04, + Button_Down = 0x08, + Button_Back = 0x10, +}; + + +typedef struct { + uint8_t key_val; //button val + uint8_t head; //the head of the frame +}key_frame; + + +typedef struct +{ + bool button_press; + key_frame key_msg; +}app_key_env; + + + +extern app_key_env key_press; + +/* + * FUNCTIONS DECLARATION + **************************************************************************************** + */ + + void app_button_init(void); + + void GPIO_isr_callback(void* arg); + + uint8_t check_sum(uint8_t *check_array,uint8_t len); + + + + diff --git a/components/bt/bluedroid/app/include/bt_app_common.h b/components/bt/bluedroid/app/include/bt_app_common.h new file mode 100644 index 0000000000..8983e0c769 --- /dev/null +++ b/components/bt/bluedroid/app/include/bt_app_common.h @@ -0,0 +1,46 @@ +#ifndef __BT_APP_COMMON_H__ +#define __BT_APP_COMMON_H__ + +#include +#include "osi.h" + +/** Bluetooth Error Status */ +/** originally defined in bluetooth.h */ +typedef enum { + BT_STATUS_SUCCESS, + BT_STATUS_FAIL, + BT_STATUS_NOT_READY, + BT_STATUS_NOMEM, + BT_STATUS_BUSY, + BT_STATUS_DONE, + BT_STATUS_UNSUPPORTED, + BT_STATUS_PARAM_INVALID, + BT_STATUS_UNHANDLED, + BT_STATUS_AUTH_FAILURE, + BT_STATUS_RMT_DEV_DOWN + +} bt_status_t; + +/* BT APP1 Events */ +#define BT_EVT_APP1 (0xB000) +#define BT_EVT_APP1_CONTEXT_SWITCH (0x0001 | BT_EVT_APP1) + +typedef void (tBTAPP1_CBACK) (UINT16 event, char *p_param); +typedef void (tBTAPP1_COPY_CBACK) (UINT16 event, char *p_dest, char *p_src); + +typedef struct +{ + BT_HDR hdr; + tBTAPP1_CBACK* p_cb; /* context switch callback */ + + /* parameters passed to callback */ + UINT16 event; /* message event id */ + char p_param[0]; /* parameter area needs to be last */ +} tBTAPP1_CONTEXT_SWITCH_CBACK; + +bt_status_t bt_app1_transfer_context (tBTAPP1_CBACK *p_cback, UINT16 event, char* p_params, int param_len, tBTAPP1_COPY_CBACK *p_copy_cback); + +void bt_app1_init_ok(UNUSED_ATTR uint16_t event, UNUSED_ATTR char *p_param); + +void bt_app1_task_start_up(void); +#endif /* __BT_APP_COMMON_H__ */ diff --git a/components/bt/bluedroid/app/include/bt_app_defs.h b/components/bt/bluedroid/app/include/bt_app_defs.h new file mode 100644 index 0000000000..1405cb091f --- /dev/null +++ b/components/bt/bluedroid/app/include/bt_app_defs.h @@ -0,0 +1,23 @@ +#include "bta_api.h" +#include "btm_ble_api.h" + +enum +{ + BLE_ADV_DATA_IDX, + BLE_SCAN_RSP_DATA_IDX, + ADV_SCAN_IDX_MAX +}; + +typedef struct +{ + char *adv_name; //set the device name to be sent on the advertising + tBTA_BLE_ADV_DATA ble_adv_data; +}tESP_BLE_ADV_DATA; + +extern void ESP_AppBleConfigadvData(tESP_BLE_ADV_DATA *adv_data, + tBTA_SET_ADV_DATA_CMPL_CBACK *p_adv_data_cback); + +extern void ESP_AppBleSetScanRsp(tESP_BLE_ADV_DATA *scan_rsp_data, + tBTA_SET_ADV_DATA_CMPL_CBACK *p_scan_rsp_data_cback); + + diff --git a/components/bt/bluedroid/app/include/gattc_profile.h b/components/bt/bluedroid/app/include/gattc_profile.h new file mode 100644 index 0000000000..95b82c909d --- /dev/null +++ b/components/bt/bluedroid/app/include/gattc_profile.h @@ -0,0 +1,46 @@ +/****************************************************************************** + * + * Copyright (C) 1999-2013 Broadcom Corporation + * + * 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. + * + ******************************************************************************/ + +/******************************************************************************* +** +** Header file for gatt client. +** +********************************************************************************/ + +#include "bt_target.h" +#include "gatt_api.h" +#include "gattdefs.h" + +/******************************************************************************* +** BATTERY CLIENT API +*******************************************************************************/ +/*************************************************************** +** +** Function bac_register +** +** Description register app for battery service +** +****************************************************************/ +extern void bac_register(void); + +extern void gattc_client_test(void); +#ifdef __cplusplus + +} +#endif + diff --git a/components/bt/bluedroid/bta/dm/bta_dm_act.c b/components/bt/bluedroid/bta/dm/bta_dm_act.c new file mode 100755 index 0000000000..ca673df094 --- /dev/null +++ b/components/bt/bluedroid/bta/dm/bta_dm_act.c @@ -0,0 +1,5797 @@ +/****************************************************************************** + * + * Copyright (C) 2003-2014 Broadcom Corporation + * + * 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 action functions for device manager state + * machine. + * + ******************************************************************************/ + +#include "bt_target.h" +#include "bt_types.h" +#include "gki.h" +#include "bta_sys.h" +#include "bta_api.h" +#include "bta_dm_int.h" +#include "bta_dm_co.h" +#include "btm_api.h" +#include "btm_int.h" +#include "btu.h" +#include "sdp_api.h" +#include "l2c_api.h" +#include "utl.h" +#include "gap_api.h" /* For GAP_BleReadPeerPrefConnParams */ +#include + +#define LOG_TAG "bt_bta_dm" +// #include "osi/include/log.h" + +#if (GAP_INCLUDED == TRUE) +#include "gap_api.h" +#endif + +static void bta_dm_inq_results_cb (tBTM_INQ_RESULTS *p_inq, UINT8 *p_eir); +static void bta_dm_inq_cmpl_cb (void * p_result); +static void bta_dm_service_search_remname_cback (BD_ADDR bd_addr, DEV_CLASS dc, BD_NAME bd_name); +static void bta_dm_remname_cback (tBTM_REMOTE_DEV_NAME *p_remote_name); +static void bta_dm_find_services ( BD_ADDR bd_addr); +static void bta_dm_discover_next_device(void); +static void bta_dm_sdp_callback (UINT16 sdp_status); +static UINT8 bta_dm_authorize_cback (BD_ADDR bd_addr, DEV_CLASS dev_class, BD_NAME bd_name, UINT8 *service_name, UINT8 service_id, BOOLEAN is_originator); +static UINT8 bta_dm_pin_cback (BD_ADDR bd_addr, DEV_CLASS dev_class, BD_NAME bd_name, BOOLEAN min_16_digit); +static UINT8 bta_dm_new_link_key_cback(BD_ADDR bd_addr, DEV_CLASS dev_class, BD_NAME bd_name, LINK_KEY key, UINT8 key_type); +static UINT8 bta_dm_authentication_complete_cback(BD_ADDR bd_addr, DEV_CLASS dev_class,BD_NAME bd_name, int result); +static void bta_dm_local_name_cback(BD_ADDR bd_addr); +static BOOLEAN bta_dm_check_av(UINT16 event); +static void bta_dm_bl_change_cback (tBTM_BL_EVENT_DATA *p_data); + + +#if BLE_INCLUDED == TRUE +static void bta_dm_acl_change_cback(BD_ADDR p_bda, DEV_CLASS p_dc, + BD_NAME p_bdn, UINT8 *features, + BOOLEAN is_new, UINT16 handle, + tBT_TRANSPORT transport); +#else +static void bta_dm_acl_change_cback(BD_ADDR p_bda, DEV_CLASS p_dc, + BD_NAME p_bdn, UINT8 *features, + BOOLEAN is_new); +#endif + + +static void bta_dm_policy_cback(tBTA_SYS_CONN_STATUS status, UINT8 id, UINT8 app_id, BD_ADDR peer_addr); + +/* Extended Inquiry Response */ +static UINT8 bta_dm_sp_cback (tBTM_SP_EVT event, tBTM_SP_EVT_DATA *p_data); + +static void bta_dm_set_eir (char *local_name); + +static void bta_dm_eir_search_services( tBTM_INQ_RESULTS *p_result, + tBTA_SERVICE_MASK *p_services_to_search, + tBTA_SERVICE_MASK *p_services_found); + +static void bta_dm_search_timer_cback (TIMER_LIST_ENT *p_tle); +static void bta_dm_disable_conn_down_timer_cback (TIMER_LIST_ENT *p_tle); +static void bta_dm_rm_cback(tBTA_SYS_CONN_STATUS status, UINT8 id, UINT8 app_id, BD_ADDR peer_addr); +static void bta_dm_adjust_roles(BOOLEAN delay_role_switch); +static char *bta_dm_get_remname(void); +static void bta_dm_bond_cancel_complete_cback(tBTM_STATUS result); + +static BOOLEAN bta_dm_read_remote_device_name (BD_ADDR bd_addr,tBT_TRANSPORT transport); +static void bta_dm_discover_device(BD_ADDR remote_bd_addr); + +static void bta_dm_sys_hw_cback( tBTA_SYS_HW_EVT status ); +static void bta_dm_disable_search_and_disc(void); + +#if ((defined BLE_INCLUDED) && (BLE_INCLUDED == TRUE)) + #if ((defined SMP_INCLUDED) && (SMP_INCLUDED == TRUE)) +static UINT8 bta_dm_ble_smp_cback (tBTM_LE_EVT event, BD_ADDR bda, tBTM_LE_EVT_DATA *p_data); + #endif +static void bta_dm_ble_id_key_cback (UINT8 key_type, tBTM_BLE_LOCAL_KEYS *p_key); + #if ((defined BTA_GATT_INCLUDED) && (BTA_GATT_INCLUDED == TRUE)) +static void bta_dm_gattc_register(void); +static void btm_dm_start_gatt_discovery(BD_ADDR bd_addr); +static void bta_dm_cancel_gatt_discovery(BD_ADDR bd_addr); +static void bta_dm_gattc_callback(tBTA_GATTC_EVT event, tBTA_GATTC *p_data); +extern tBTA_DM_CONTRL_STATE bta_dm_pm_obtain_controller_state(void); + #endif + +#if BLE_VND_INCLUDED == TRUE +static void bta_dm_ctrl_features_rd_cmpl_cback(tBTM_STATUS result); +#endif + +#ifndef BTA_DM_BLE_ADV_CHNL_MAP +#define BTA_DM_BLE_ADV_CHNL_MAP (BTM_BLE_ADV_CHNL_37|BTM_BLE_ADV_CHNL_38|BTM_BLE_ADV_CHNL_39) +#endif +#endif + +static void bta_dm_remove_sec_dev_entry(BD_ADDR remote_bd_addr); +static void bta_dm_observe_results_cb(tBTM_INQ_RESULTS *p_inq, UINT8 *p_eir); +static void bta_dm_observe_cmpl_cb(void * p_result); +static void bta_dm_delay_role_switch_cback(TIMER_LIST_ENT *p_tle); +extern void sdpu_uuid16_to_uuid128(UINT16 uuid16, UINT8* p_uuid128); +static void bta_dm_disable_timer_cback(TIMER_LIST_ENT *p_tle); + + +const UINT16 bta_service_id_to_uuid_lkup_tbl [BTA_MAX_SERVICE_ID] = +{ + UUID_SERVCLASS_PNP_INFORMATION, /* Reserved */ + UUID_SERVCLASS_SERIAL_PORT, /* BTA_SPP_SERVICE_ID */ + UUID_SERVCLASS_DIALUP_NETWORKING, /* BTA_DUN_SERVICE_ID */ + UUID_SERVCLASS_AUDIO_SOURCE, /* BTA_A2DP_SOURCE_SERVICE_ID */ + UUID_SERVCLASS_LAN_ACCESS_USING_PPP, /* BTA_LAP_SERVICE_ID */ + UUID_SERVCLASS_HEADSET, /* BTA_HSP_HS_SERVICE_ID */ + UUID_SERVCLASS_HF_HANDSFREE, /* BTA_HFP_HS_SERVICE_ID */ + UUID_SERVCLASS_OBEX_OBJECT_PUSH, /* BTA_OPP_SERVICE_ID */ + UUID_SERVCLASS_OBEX_FILE_TRANSFER, /* BTA_FTP_SERVICE_ID */ + UUID_SERVCLASS_CORDLESS_TELEPHONY, /* BTA_CTP_SERVICE_ID */ + UUID_SERVCLASS_INTERCOM, /* BTA_ICP_SERVICE_ID */ + UUID_SERVCLASS_IRMC_SYNC, /* BTA_SYNC_SERVICE_ID */ + UUID_SERVCLASS_DIRECT_PRINTING, /* BTA_BPP_SERVICE_ID */ + UUID_SERVCLASS_IMAGING_RESPONDER, /* BTA_BIP_SERVICE_ID */ + UUID_SERVCLASS_PANU, /* BTA_PANU_SERVICE_ID */ + UUID_SERVCLASS_NAP, /* BTA_NAP_SERVICE_ID */ + UUID_SERVCLASS_GN, /* BTA_GN_SERVICE_ID */ + UUID_SERVCLASS_SAP, /* BTA_SAP_SERVICE_ID */ + UUID_SERVCLASS_AUDIO_SINK, /* BTA_A2DP_SERVICE_ID */ + UUID_SERVCLASS_AV_REMOTE_CONTROL, /* BTA_AVRCP_SERVICE_ID */ + UUID_SERVCLASS_HUMAN_INTERFACE, /* BTA_HID_SERVICE_ID */ + UUID_SERVCLASS_VIDEO_SINK, /* BTA_VDP_SERVICE_ID */ + UUID_SERVCLASS_PBAP_PSE, /* BTA_PBAP_SERVICE_ID */ + UUID_SERVCLASS_HEADSET_AUDIO_GATEWAY, /* BTA_HSP_SERVICE_ID */ + UUID_SERVCLASS_AG_HANDSFREE, /* BTA_HFP_SERVICE_ID */ + UUID_SERVCLASS_MESSAGE_ACCESS, /* BTA_MAP_SERVICE_ID */ + UUID_SERVCLASS_MESSAGE_NOTIFICATION, /* BTA_MN_SERVICE_ID */ + UUID_SERVCLASS_HDP_PROFILE, /* BTA_HDP_SERVICE_ID */ + UUID_SERVCLASS_PBAP_PCE /* BTA_PCE_SERVICE_ID */ +#if BLE_INCLUDED && BTA_GATT_INCLUDED + ,UUID_PROTOCOL_ATT /* BTA_GATT_SERVICE_ID */ +#endif +}; + +/* + * NOTE : The number of element in bta_service_id_to_btm_srv_id_lkup_tbl should be matching with + * the value BTA_MAX_SERVICE_ID in bta_api.h + * + * i.e., If you add new Service ID for BTA, the correct security ID of the new service + * from Security service definitions (btm_api.h) should be added to this lookup table. + */ +const UINT32 bta_service_id_to_btm_srv_id_lkup_tbl [BTA_MAX_SERVICE_ID] = +{ + 0, /* Reserved */ + BTM_SEC_SERVICE_SERIAL_PORT, /* BTA_SPP_SERVICE_ID */ + BTM_SEC_SERVICE_DUN, /* BTA_DUN_SERVICE_ID */ + BTM_SEC_SERVICE_AVDTP, /* BTA_AUDIO_SOURCE_SERVICE_ID */ + BTM_SEC_SERVICE_LAN_ACCESS, /* BTA_LAP_SERVICE_ID */ + BTM_SEC_SERVICE_HEADSET_AG, /* BTA_HSP_SERVICE_ID */ + BTM_SEC_SERVICE_AG_HANDSFREE, /* BTA_HFP_SERVICE_ID */ + BTM_SEC_SERVICE_OBEX, /* BTA_OPP_SERVICE_ID */ + BTM_SEC_SERVICE_OBEX_FTP, /* BTA_FTP_SERVICE_ID */ + BTM_SEC_SERVICE_CORDLESS, /* BTA_CTP_SERVICE_ID */ + BTM_SEC_SERVICE_INTERCOM, /* BTA_ICP_SERVICE_ID */ + BTM_SEC_SERVICE_IRMC_SYNC, /* BTA_SYNC_SERVICE_ID */ + BTM_SEC_SERVICE_BPP_JOB, /* BTA_BPP_SERVICE_ID */ + BTM_SEC_SERVICE_BIP, /* BTA_BIP_SERVICE_ID */ + BTM_SEC_SERVICE_BNEP_PANU, /* BTA_PANU_SERVICE_ID */ + BTM_SEC_SERVICE_BNEP_NAP, /* BTA_NAP_SERVICE_ID */ + BTM_SEC_SERVICE_BNEP_GN, /* BTA_GN_SERVICE_ID */ + BTM_SEC_SERVICE_SAP, /* BTA_SAP_SERVICE_ID */ + BTM_SEC_SERVICE_AVDTP, /* BTA_A2DP_SERVICE_ID */ + BTM_SEC_SERVICE_AVCTP, /* BTA_AVRCP_SERVICE_ID */ + BTM_SEC_SERVICE_HIDH_SEC_CTRL, /* BTA_HID_SERVICE_ID */ + BTM_SEC_SERVICE_AVDTP, /* BTA_VDP_SERVICE_ID */ + BTM_SEC_SERVICE_PBAP, /* BTA_PBAP_SERVICE_ID */ + BTM_SEC_SERVICE_HEADSET, /* BTA_HSP_HS_SERVICE_ID */ + BTM_SEC_SERVICE_HF_HANDSFREE, /* BTA_HFP_HS_SERVICE_ID */ + BTM_SEC_SERVICE_MAP, /* BTA_MAP_SERVICE_ID */ + BTM_SEC_SERVICE_MAP, /* BTA_MN_SERVICE_ID */ + BTM_SEC_SERVICE_HDP_SNK, /* BTA_HDP_SERVICE_ID */ + BTM_SEC_SERVICE_PBAP /* BTA_PCE_SERVICE_ID */ +#if BLE_INCLUDED && BTA_GATT_INCLUDED + ,BTM_SEC_SERVICE_ATT /* BTA_GATT_SERVICE_ID */ +#endif + +}; + +/* bta security callback */ +const tBTM_APPL_INFO bta_security = +{ + &bta_dm_authorize_cback, + &bta_dm_pin_cback, + &bta_dm_new_link_key_cback, + &bta_dm_authentication_complete_cback, + &bta_dm_bond_cancel_complete_cback, +#if (BTM_LOCAL_IO_CAPS != BTM_IO_CAP_NONE) + &bta_dm_sp_cback +#else + NULL +#endif +#if BLE_INCLUDED == TRUE +#if SMP_INCLUDED == TRUE + ,&bta_dm_ble_smp_cback +#endif + ,&bta_dm_ble_id_key_cback +#endif + +}; + +#define MAX_DISC_RAW_DATA_BUF (4096) +UINT8 g_disc_raw_data_buf[MAX_DISC_RAW_DATA_BUF]; + +extern DEV_CLASS local_device_default_class; + +/******************************************************************************* +** +** Function bta_dm_enable +** +** Description Initialises the BT device manager +** +** +** Returns void +** +*******************************************************************************/ +void bta_dm_enable(tBTA_DM_MSG *p_data) +{ + tBTA_SYS_HW_MSG *sys_enable_event; + tBTA_DM_ENABLE enable_event; + + /* if already in use, return an error */ + if( bta_dm_cb.is_bta_dm_active == TRUE ) + { + APPL_TRACE_WARNING("%s Device already started by another application", __func__); + memset(&enable_event, 0, sizeof(tBTA_DM_ENABLE)); + enable_event.status = BTA_FAILURE; + if (p_data->enable.p_sec_cback != NULL) + p_data->enable.p_sec_cback(BTA_DM_ENABLE_EVT, (tBTA_DM_SEC *)&enable_event); + return; + } + + /* first, register our callback to SYS HW manager */ + bta_sys_hw_register( BTA_SYS_HW_BLUETOOTH, bta_dm_sys_hw_cback ); + + /* make sure security callback is saved - if no callback, do not erase the previous one, + it could be an error recovery mechanism */ + if( p_data->enable.p_sec_cback != NULL ) + bta_dm_cb.p_sec_cback = p_data->enable.p_sec_cback; + /* notify BTA DM is now active */ + bta_dm_cb.is_bta_dm_active = TRUE; + + /* send a message to BTA SYS */ + if ((sys_enable_event = (tBTA_SYS_HW_MSG *) GKI_getbuf(sizeof(tBTA_SYS_HW_MSG))) != NULL) + { + sys_enable_event->hdr.event = BTA_SYS_API_ENABLE_EVT; + sys_enable_event->hw_module = BTA_SYS_HW_BLUETOOTH; + + bta_sys_sendmsg(sys_enable_event); + } +} + +/******************************************************************************* +** +** Function bta_dm_sys_hw_cback +** +** Description callback register to SYS to get HW status updates +** +** +** Returns void +** +*******************************************************************************/ +static void bta_dm_sys_hw_cback( tBTA_SYS_HW_EVT status ) +{ + DEV_CLASS dev_class; + tBTA_DM_SEC_CBACK *temp_cback; +#if BLE_INCLUDED == TRUE + UINT8 key_mask = 0; + BT_OCTET16 er; + tBTA_BLE_LOCAL_ID_KEYS id_key; +#endif + + APPL_TRACE_DEBUG("%s with event: %i", __func__, status); + + /* On H/W error evt, report to the registered DM application callback */ + if (status == BTA_SYS_HW_ERROR_EVT) { + if( bta_dm_cb.p_sec_cback != NULL ) + bta_dm_cb.p_sec_cback(BTA_DM_HW_ERROR_EVT, NULL); + return; + } + + if( status == BTA_SYS_HW_OFF_EVT ) + { + if( bta_dm_cb.p_sec_cback != NULL ) + bta_dm_cb.p_sec_cback(BTA_DM_DISABLE_EVT, NULL); + + /* reinitialize the control block */ + memset(&bta_dm_cb, 0, sizeof(bta_dm_cb)); + + /* unregister from SYS */ + bta_sys_hw_unregister( BTA_SYS_HW_BLUETOOTH ); + /* notify BTA DM is now unactive */ + bta_dm_cb.is_bta_dm_active = FALSE; + } + else + if( status == BTA_SYS_HW_ON_EVT ) + { + /* FIXME: We should not unregister as the SYS shall invoke this callback on a H/W error. + * We need to revisit when this platform has more than one BLuetooth H/W chip */ + //bta_sys_hw_unregister( BTA_SYS_HW_BLUETOOTH); + + /* save security callback */ + temp_cback = bta_dm_cb.p_sec_cback; + /* make sure the control block is properly initialized */ + memset(&bta_dm_cb, 0, sizeof(bta_dm_cb)); + /* and retrieve the callback */ + bta_dm_cb.p_sec_cback=temp_cback; + bta_dm_cb.is_bta_dm_active = TRUE; + + /* hw is ready, go on with BTA DM initialization */ + memset(&bta_dm_search_cb, 0x00, sizeof(bta_dm_search_cb)); + memset(&bta_dm_conn_srvcs, 0x00, sizeof(bta_dm_conn_srvcs)); + memset(&bta_dm_di_cb, 0, sizeof(tBTA_DM_DI_CB)); + + memcpy(dev_class, p_bta_dm_cfg->dev_class, sizeof(dev_class)); + BTM_SetDeviceClass (dev_class); + +#if (defined BLE_INCLUDED && BLE_INCLUDED == TRUE) + /* load BLE local information: ID keys, ER if available */ + bta_dm_co_ble_load_local_keys(&key_mask, er, &id_key); + + if (key_mask & BTA_BLE_LOCAL_KEY_TYPE_ER) + { + BTM_BleLoadLocalKeys(BTA_BLE_LOCAL_KEY_TYPE_ER, (tBTM_BLE_LOCAL_KEYS *)&er); + } + if (key_mask & BTA_BLE_LOCAL_KEY_TYPE_ID) + { + BTM_BleLoadLocalKeys(BTA_BLE_LOCAL_KEY_TYPE_ID, (tBTM_BLE_LOCAL_KEYS *)&id_key); + } +#if ((defined BTA_GATT_INCLUDED) && (BTA_GATT_INCLUDED == TRUE)) + bta_dm_search_cb.conn_id = BTA_GATT_INVALID_CONN_ID; +#endif +#endif + + BTM_SecRegister((tBTM_APPL_INFO*)&bta_security); + BTM_SetDefaultLinkSuperTout(p_bta_dm_cfg->link_timeout); + BTM_WritePageTimeout(p_bta_dm_cfg->page_timeout); + bta_dm_cb.cur_policy = p_bta_dm_cfg->policy_settings; + BTM_SetDefaultLinkPolicy(bta_dm_cb.cur_policy); + BTM_RegBusyLevelNotif (bta_dm_bl_change_cback, NULL, BTM_BL_UPDATE_MASK|BTM_BL_ROLE_CHG_MASK); + +#if BLE_VND_INCLUDED == TRUE + BTM_BleReadControllerFeatures (bta_dm_ctrl_features_rd_cmpl_cback); +#endif + + /* Earlier, we used to invoke BTM_ReadLocalAddr which was just copying the bd_addr + from the control block and invoking the callback which was sending the DM_ENABLE_EVT. + But then we have a few HCI commands being invoked above which were still in progress + when the ENABLE_EVT was sent. So modified this to fetch the local name which forces + the DM_ENABLE_EVT to be sent only after all the init steps are complete */ + BTM_ReadLocalDeviceNameFromController((tBTM_CMPL_CB *)bta_dm_local_name_cback); + + bta_sys_rm_register((tBTA_SYS_CONN_CBACK*)bta_dm_rm_cback); + + /* initialize bluetooth low power manager */ + bta_dm_init_pm(); + + bta_sys_policy_register((tBTA_SYS_CONN_CBACK*)bta_dm_policy_cback); + +#if (BLE_INCLUDED == TRUE && BTA_GATT_INCLUDED == TRUE) + bta_dm_gattc_register(); +#endif + + } + else + APPL_TRACE_DEBUG(" --- ignored event"); + +} + + +/******************************************************************************* +** +** Function bta_dm_disable +** +** Description Disables the BT device manager +** +** +** Returns void +** +*******************************************************************************/ +void bta_dm_disable (tBTA_DM_MSG *p_data) +{ + UNUSED(p_data); + + /* Set l2cap idle timeout to 0 (so BTE immediately disconnects ACL link after last channel is closed) */ + L2CA_SetIdleTimeoutByBdAddr((UINT8 *)BT_BD_ANY, 0, BT_TRANSPORT_BR_EDR); + L2CA_SetIdleTimeoutByBdAddr((UINT8 *)BT_BD_ANY, 0, BT_TRANSPORT_LE); + + /* disable all active subsystems */ + bta_sys_disable(BTA_SYS_HW_BLUETOOTH); + + BTM_SetDiscoverability(BTM_NON_DISCOVERABLE, 0, 0); + BTM_SetConnectability(BTM_NON_CONNECTABLE, 0, 0); + + bta_dm_disable_pm(); + bta_dm_disable_search_and_disc(); + bta_dm_cb.disabling = TRUE; + +#if BLE_INCLUDED == TRUE && BTA_GATT_INCLUDED == TRUE + BTM_BleClearBgConnDev(); +#endif + + if(BTM_GetNumAclLinks()==0) + { +#if (defined(BTA_DISABLE_DELAY) && BTA_DISABLE_DELAY > 0) + /* If BTA_DISABLE_DELAY is defined and greater than zero, then delay the shutdown by + * BTA_DISABLE_DELAY milliseconds + */ + APPL_TRACE_WARNING("%s BTA_DISABLE_DELAY set to %d ms", + __FUNCTION__, BTA_DISABLE_DELAY); + bta_sys_stop_timer(&bta_dm_cb.disable_timer); + bta_dm_cb.disable_timer.p_cback = (TIMER_CBACK*)&bta_dm_disable_conn_down_timer_cback; + bta_sys_start_timer(&bta_dm_cb.disable_timer, 0, BTA_DISABLE_DELAY); +#else + bta_dm_disable_conn_down_timer_cback(NULL); +#endif + } + else + { + bta_dm_cb.disable_timer.p_cback = (TIMER_CBACK*)&bta_dm_disable_timer_cback; + bta_dm_cb.disable_timer.param = 0; + bta_sys_start_timer(&bta_dm_cb.disable_timer, 0, 5000); + } + +} + +/******************************************************************************* +** +** Function bta_dm_disable_timer_cback +** +** Description Called if the disable timer expires +** Used to close ACL connections which are still active +** +** +** +** Returns void +** +*******************************************************************************/ +static void bta_dm_disable_timer_cback (TIMER_LIST_ENT *p_tle) +{ + UNUSED(p_tle); + UINT8 i; + tBT_TRANSPORT transport = BT_TRANSPORT_BR_EDR; + BOOLEAN trigger_disc = FALSE; + + + APPL_TRACE_EVENT(" bta_dm_disable_timer_cback trial %d ", p_tle->param); + + if(BTM_GetNumAclLinks() && p_tle->param == 0) + { + for(i=0; iset_name.name); + bta_dm_set_eir ((char*)p_data->set_name.name); +} + +/******************************************************************************* +** +** Function bta_dm_set_visibility +** +** Description Sets discoverability, connectability and pairability +** +** +** Returns void +** +*******************************************************************************/ +void bta_dm_set_visibility(tBTA_DM_MSG *p_data) +{ + UINT16 window, interval; + UINT16 le_disc_mode = BTM_BleReadDiscoverability(); + UINT16 disc_mode = BTM_ReadDiscoverability(&window, &interval); + UINT16 le_conn_mode = BTM_BleReadConnectability(); + UINT16 conn_mode = BTM_ReadConnectability(&window, &interval); + + /* set modes for Discoverability and connectability if not ignore */ + if (p_data->set_visibility.disc_mode != (BTA_DM_IGNORE | BTA_DM_LE_IGNORE)) + { + if ((p_data->set_visibility.disc_mode & BTA_DM_LE_IGNORE) == BTA_DM_LE_IGNORE) + p_data->set_visibility.disc_mode = + ((p_data->set_visibility.disc_mode & ~BTA_DM_LE_IGNORE) | le_disc_mode); + + if ((p_data->set_visibility.disc_mode & BTA_DM_IGNORE) == BTA_DM_IGNORE) + p_data->set_visibility.disc_mode = + ((p_data->set_visibility.disc_mode & ~BTA_DM_IGNORE) | disc_mode); + + BTM_SetDiscoverability(p_data->set_visibility.disc_mode, + bta_dm_cb.inquiry_scan_window, + bta_dm_cb.inquiry_scan_interval); + } + + if (p_data->set_visibility.conn_mode != (BTA_DM_IGNORE | BTA_DM_LE_IGNORE)) + { + if ((p_data->set_visibility.conn_mode & BTA_DM_LE_IGNORE) == BTA_DM_LE_IGNORE) + p_data->set_visibility.conn_mode = + ((p_data->set_visibility.conn_mode & ~BTA_DM_LE_IGNORE) | le_conn_mode); + + if ((p_data->set_visibility.conn_mode & BTA_DM_IGNORE) == BTA_DM_IGNORE) + p_data->set_visibility.conn_mode = + ((p_data->set_visibility.conn_mode & ~BTA_DM_IGNORE) | conn_mode); + + BTM_SetConnectability(p_data->set_visibility.conn_mode, + bta_dm_cb.page_scan_window, + bta_dm_cb.page_scan_interval); + } + + /* Send False or True if not ignore */ + if (p_data->set_visibility.pair_mode != BTA_DM_IGNORE ) + { + + if (p_data->set_visibility.pair_mode == BTA_DM_NON_PAIRABLE) + bta_dm_cb.disable_pair_mode = TRUE; + else + bta_dm_cb.disable_pair_mode = FALSE; + + } + + /* Send False or True if not ignore */ + if (p_data->set_visibility.conn_paired_only != BTA_DM_IGNORE) + { + + if (p_data->set_visibility.conn_paired_only == BTA_DM_CONN_ALL) + bta_dm_cb.conn_paired_only = FALSE; + else + bta_dm_cb.conn_paired_only = TRUE; + + } + + /* Change mode if either mode is not ignore */ + if (p_data->set_visibility.pair_mode != BTA_DM_IGNORE || p_data->set_visibility.conn_paired_only != BTA_DM_IGNORE) + BTM_SetPairableMode((BOOLEAN)(!(bta_dm_cb.disable_pair_mode)),bta_dm_cb.conn_paired_only); + +} + +/******************************************************************************* +** +** Function bta_dm_process_remove_device +** +** Description Removes device, Disconnects ACL link if required. +**** +*******************************************************************************/ +void bta_dm_process_remove_device(BD_ADDR bd_addr) +{ +#if (BLE_INCLUDED == TRUE && BTA_GATT_INCLUDED == TRUE) + /* need to remove all pending background connection before unpair */ + BTA_GATTC_CancelOpen(0, bd_addr, FALSE); +#endif + + BTM_SecDeleteDevice(bd_addr); + +#if (BLE_INCLUDED == TRUE && BTA_GATT_INCLUDED == TRUE) + /* remove all cached GATT information */ + BTA_GATTC_Refresh(bd_addr); +#endif + + if (bta_dm_cb.p_sec_cback) + { + tBTA_DM_SEC sec_event; + bdcpy(sec_event.link_down.bd_addr, bd_addr); + /* No connection, set status to success (acl disc code not valid) */ + sec_event.link_down.status = HCI_SUCCESS; + bta_dm_cb.p_sec_cback(BTA_DM_DEV_UNPAIRED_EVT, &sec_event); + } +} + +/******************************************************************************* +** +** Function bta_dm_remove_device +** +** Description Removes device, disconnects ACL link if required. +**** +*******************************************************************************/ +void bta_dm_remove_device(tBTA_DM_MSG *p_data) +{ + tBTA_DM_API_REMOVE_DEVICE *p_dev = &p_data->remove_dev; + if (p_dev == NULL) + return; + + BD_ADDR other_address; + bdcpy(other_address, p_dev->bd_addr); + + /* If ACL exists for the device in the remove_bond message*/ + BOOLEAN continue_delete_dev = FALSE; + UINT8 other_transport = BT_TRANSPORT_INVALID; + + if (BTM_IsAclConnectionUp(p_dev->bd_addr, BT_TRANSPORT_LE) || + BTM_IsAclConnectionUp(p_dev->bd_addr, BT_TRANSPORT_BR_EDR)) + { + APPL_TRACE_DEBUG("%s: ACL Up count %d", __func__, bta_dm_cb.device_list.count); + continue_delete_dev = FALSE; + + /* Take the link down first, and mark the device for removal when disconnected */ + for(int i=0; i < bta_dm_cb.device_list.count; i++) + { + if (!bdcmp(bta_dm_cb.device_list.peer_device[i].peer_bdaddr, p_dev->bd_addr)) + { + bta_dm_cb.device_list.peer_device[i].conn_state = BTA_DM_UNPAIRING; + btm_remove_acl( p_dev->bd_addr, bta_dm_cb.device_list.peer_device[i].transport); + APPL_TRACE_DEBUG("%s:transport = %d", __func__, + bta_dm_cb.device_list.peer_device[i].transport); + + /* save the other transport to check if device is connected on other_transport */ + if(bta_dm_cb.device_list.peer_device[i].transport == BT_TRANSPORT_LE) + other_transport = BT_TRANSPORT_BR_EDR; + else + other_transport = BT_TRANSPORT_LE; + break; + } + } + } + else + { + continue_delete_dev = TRUE; + } + + // If it is DUMO device and device is paired as different address, unpair that device + // if different address + BOOLEAN continue_delete_other_dev = FALSE; + if ((other_transport && (BTM_ReadConnectedTransportAddress(other_address, other_transport))) || + (!other_transport && (BTM_ReadConnectedTransportAddress(other_address, BT_TRANSPORT_BR_EDR) || + BTM_ReadConnectedTransportAddress(other_address, BT_TRANSPORT_LE)))) + { + continue_delete_other_dev = FALSE; + /* Take the link down first, and mark the device for removal when disconnected */ + for(int i=0; i < bta_dm_cb.device_list.count; i++) + { + if (!bdcmp(bta_dm_cb.device_list.peer_device[i].peer_bdaddr, other_address)) + { + bta_dm_cb.device_list.peer_device[i].conn_state = BTA_DM_UNPAIRING; + btm_remove_acl(other_address,bta_dm_cb.device_list.peer_device[i].transport); + break; + } + } + } + else + { + APPL_TRACE_DEBUG("%s: continue to delete the other dev ", __func__); + continue_delete_other_dev = TRUE; + } + + /* Delete the device mentioned in the msg */ + if (continue_delete_dev) + bta_dm_process_remove_device(p_dev->bd_addr); + + /* Delete the other paired device too */ + BD_ADDR dummy_bda = {0}; + if (continue_delete_other_dev && (bdcmp(other_address, dummy_bda) != 0)) + bta_dm_process_remove_device(other_address); +} + +/******************************************************************************* +** +** Function bta_dm_add_device +** +** Description This function adds a Link Key to an security database entry. +** It is normally called during host startup to restore all required information +** stored in the NVRAM. +**** +*******************************************************************************/ +void bta_dm_add_device (tBTA_DM_MSG *p_data) +{ + tBTA_DM_API_ADD_DEVICE *p_dev = &p_data->add_dev; + UINT8 *p_dc = NULL; + UINT8 *p_lc = NULL; + UINT32 trusted_services_mask[BTM_SEC_SERVICE_ARRAY_SIZE]; + UINT8 index = 0; + UINT8 btm_mask_index = 0; + + memset (trusted_services_mask, 0, sizeof(trusted_services_mask)); + + /* If not all zeros, the device class has been specified */ + if (p_dev->dc_known) + p_dc = (UINT8 *)p_dev->dc; + + if (p_dev->link_key_known) + p_lc = (UINT8 *)p_dev->link_key; + + if (p_dev->is_trusted) + { + /* covert BTA service mask to BTM mask */ + while (p_dev->tm && (index < BTA_MAX_SERVICE_ID)) + { + if (p_dev->tm & (UINT32)(1<tm &= (UINT32)(~(1<bd_addr, p_dc, p_dev->bd_name, p_dev->features, + trusted_services_mask, p_lc, p_dev->key_type, p_dev->io_cap, + p_dev->pin_length)) + { + APPL_TRACE_ERROR ("BTA_DM: Error adding device %08x%04x", + (p_dev->bd_addr[0]<<24)+(p_dev->bd_addr[1]<<16)+(p_dev->bd_addr[2]<<8)+p_dev->bd_addr[3], + (p_dev->bd_addr[4]<<8)+p_dev->bd_addr[5]); + } +} + +/******************************************************************************* +** +** Function bta_dm_close_acl +** +** Description This function forces to close the connection to a remote device +** and optionaly remove the device from security database if +** required. +**** +*******************************************************************************/ +void bta_dm_close_acl(tBTA_DM_MSG *p_data) +{ + tBTA_DM_API_REMOVE_ACL *p_remove_acl = &p_data->remove_acl; + UINT8 index; + + APPL_TRACE_DEBUG("bta_dm_close_acl"); + + if (BTM_IsAclConnectionUp(p_remove_acl->bd_addr, p_remove_acl->transport)) + { + for (index = 0; index < bta_dm_cb.device_list.count; index ++) + { + if (!bdcmp( bta_dm_cb.device_list.peer_device[index].peer_bdaddr, p_remove_acl->bd_addr)) + break; + } + if (index != bta_dm_cb.device_list.count) + { + if (p_remove_acl->remove_dev) + bta_dm_cb.device_list.peer_device[index].remove_dev_pending = TRUE; + } + else + { + APPL_TRACE_ERROR("unknown device, remove ACL failed"); + } + /* Disconnect the ACL link */ + btm_remove_acl(p_remove_acl->bd_addr, p_remove_acl->transport); + } + /* if to remove the device from security database ? do it now */ + else if (p_remove_acl->remove_dev) + { + if (!BTM_SecDeleteDevice(p_remove_acl->bd_addr)) + { + APPL_TRACE_ERROR("delete device from security database failed."); + } +#if (BLE_INCLUDED == TRUE && BTA_GATT_INCLUDED == TRUE) + /* need to remove all pending background connection if any */ + BTA_GATTC_CancelOpen(0, p_remove_acl->bd_addr, FALSE); + /* remove all cached GATT information */ + BTA_GATTC_Refresh(p_remove_acl->bd_addr); +#endif + } + /* otherwise, no action needed */ + +} + +/******************************************************************************* +** +** Function bta_dm_remove_all_acl +** +** Description This function forces to close all the ACL links specified by link type +**** +*******************************************************************************/ +void bta_dm_remove_all_acl(tBTA_DM_MSG *p_data) +{ + const tBTA_DM_LINK_TYPE link_type = p_data->remove_all_acl.link_type; + tBT_TRANSPORT transport = BT_TRANSPORT_BR_EDR; + + APPL_TRACE_DEBUG("%s link type = %d", __func__, link_type); + + for (UINT8 i=0; i < bta_dm_cb.device_list.count; i++) + { + BD_ADDR addr = {0}; + bdcpy(addr, bta_dm_cb.device_list.peer_device[i].peer_bdaddr); +#if defined (BLE_INCLUDED) && (BLE_INCLUDED == TRUE) + transport = bta_dm_cb.device_list.peer_device[i].transport; +#endif + if ((link_type == BTA_DM_LINK_TYPE_ALL) || + ((link_type == BTA_DM_LINK_TYPE_LE) && (transport == BT_TRANSPORT_LE)) || + ((link_type == BTA_DM_LINK_TYPE_BR_EDR) && (transport == BT_TRANSPORT_BR_EDR))) + { + /* Disconnect the ACL link */ + btm_remove_acl(addr, transport); + } + } +} + + +/******************************************************************************* +** +** Function bta_dm_bond +** +** Description Bonds with peer device +** +** +** Returns void +** +*******************************************************************************/ +void bta_dm_bond (tBTA_DM_MSG *p_data) +{ + tBTM_STATUS status; + tBTA_DM_SEC sec_event; + char *p_name; + + if (p_data->bond.transport == BTA_TRANSPORT_UNKNOWN) + status = BTM_SecBond ( p_data->bond.bd_addr, 0, NULL, 0 ); + else + status = BTM_SecBondByTransport ( p_data->bond.bd_addr, p_data->bond.transport, 0, NULL, 0 ); + + + if (bta_dm_cb.p_sec_cback && (status != BTM_CMD_STARTED)) + { + + memset(&sec_event, 0, sizeof(tBTA_DM_SEC)); + bdcpy(sec_event.auth_cmpl.bd_addr, p_data->bond.bd_addr); + p_name = BTM_SecReadDevName(p_data->bond.bd_addr); + if (p_name != NULL) + { + memcpy(sec_event.auth_cmpl.bd_name, p_name, (BD_NAME_LEN-1)); + sec_event.auth_cmpl.bd_name[BD_NAME_LEN-1] = 0; + } + +/* taken care of by memset [above] + sec_event.auth_cmpl.key_present = FALSE; + sec_event.auth_cmpl.success = FALSE; +*/ + sec_event.auth_cmpl.fail_reason = HCI_ERR_ILLEGAL_COMMAND; + if (status == BTM_SUCCESS) + { + sec_event.auth_cmpl.success = TRUE; + } + else + { + /* delete this device entry from Sec Dev DB */ + bta_dm_remove_sec_dev_entry(p_data->bond.bd_addr); + } + bta_dm_cb.p_sec_cback(BTA_DM_AUTH_CMPL_EVT, &sec_event); + } + +} + +/******************************************************************************* +** +** Function bta_dm_bond_cancel +** +** Description Cancels bonding with a peer device +** +** +** Returns void +** +*******************************************************************************/ +void bta_dm_bond_cancel (tBTA_DM_MSG *p_data) +{ + tBTM_STATUS status; + tBTA_DM_SEC sec_event; + + APPL_TRACE_EVENT(" bta_dm_bond_cancel "); + status = BTM_SecBondCancel ( p_data->bond_cancel.bd_addr ); + + if (bta_dm_cb.p_sec_cback && (status != BTM_CMD_STARTED && status != BTM_SUCCESS)) + { + sec_event.bond_cancel_cmpl.result = BTA_FAILURE; + + bta_dm_cb.p_sec_cback(BTA_DM_BOND_CANCEL_CMPL_EVT, &sec_event); + } + +} + +/******************************************************************************* +** +** Function bta_dm_pin_reply +** +** Description Send the pin_reply to a request from BTM +** +** +** Returns void +** +*******************************************************************************/ +void bta_dm_pin_reply (tBTA_DM_MSG *p_data) +{ + UINT32 trusted_mask[BTM_SEC_SERVICE_ARRAY_SIZE]; + UINT32 * current_trusted_mask; + + current_trusted_mask = BTM_ReadTrustedMask(p_data->pin_reply.bd_addr); + + if(current_trusted_mask) + { + memcpy(trusted_mask, current_trusted_mask, sizeof(trusted_mask)); + } + else + { + memset(trusted_mask, 0, sizeof(trusted_mask)); + } + + if(p_data->pin_reply.accept) + { + + BTM_PINCodeReply(p_data->pin_reply.bd_addr, BTM_SUCCESS, p_data->pin_reply.pin_len, p_data->pin_reply.p_pin, trusted_mask ); + } + else + { + BTM_PINCodeReply(p_data->pin_reply.bd_addr, BTM_NOT_AUTHORIZED, 0, NULL, trusted_mask ); + } + +} + +/******************************************************************************* +** +** Function bta_dm_policy_cback +** +** Description process the link policy changes +** +** Returns void +** +*******************************************************************************/ +static void bta_dm_policy_cback(tBTA_SYS_CONN_STATUS status, UINT8 id, UINT8 app_id, BD_ADDR peer_addr) +{ + tBTA_DM_PEER_DEVICE *p_dev = NULL; + UINT16 policy = app_id; + UINT32 mask = (UINT32)(1 << id); + + if(peer_addr) + p_dev = bta_dm_find_peer_device(peer_addr); + + APPL_TRACE_DEBUG(" bta_dm_policy_cback cmd:%d, policy:0x%x", + status, policy); + switch(status) + { + case BTA_SYS_PLCY_SET: + if(!p_dev) + return; + /* restore the default link policy */ + p_dev->link_policy |= policy; + BTM_SetLinkPolicy(p_dev->peer_bdaddr, &(p_dev->link_policy)); + break; + + case BTA_SYS_PLCY_CLR: + if(!p_dev) + return; + /* clear the policy from the default link policy */ + p_dev->link_policy &= (~policy); + BTM_SetLinkPolicy(p_dev->peer_bdaddr, &(p_dev->link_policy)); + + if(policy & (HCI_ENABLE_SNIFF_MODE | HCI_ENABLE_PARK_MODE)) + { + /* if clearing sniff/park, wake the link */ + bta_dm_pm_active(p_dev->peer_bdaddr); + } + break; + + case BTA_SYS_PLCY_DEF_SET: + /* want to restore/set the role switch policy */ + bta_dm_cb.role_policy_mask &= ~mask; + if(0 == bta_dm_cb.role_policy_mask) + { + /* if nobody wants to insist on the role */ + bta_dm_cb.cur_policy |= HCI_ENABLE_MASTER_SLAVE_SWITCH; + BTM_SetDefaultLinkPolicy(bta_dm_cb.cur_policy); + } + break; + + case BTA_SYS_PLCY_DEF_CLR: + /* want to remove the role switch policy */ + bta_dm_cb.role_policy_mask |= mask; + bta_dm_cb.cur_policy &= ~HCI_ENABLE_MASTER_SLAVE_SWITCH; + BTM_SetDefaultLinkPolicy(bta_dm_cb.cur_policy); + break; + } +} + +/******************************************************************************* +** +** Function bta_dm_confirm +** +** Description Send the user confirm request reply in response to a +** request from BTM +** +** Returns void +** +*******************************************************************************/ +void bta_dm_confirm(tBTA_DM_MSG *p_data) +{ + tBTM_STATUS res = BTM_NOT_AUTHORIZED; + + if(p_data->confirm.accept == TRUE) + res = BTM_SUCCESS; + BTM_ConfirmReqReply(res, p_data->confirm.bd_addr); +} + +/******************************************************************************* +** +** Function bta_dm_loc_oob +** +** Description Retrieve the OOB data from the local LM +** +** Returns void +** +*******************************************************************************/ +#if (BTM_OOB_INCLUDED == TRUE) +void bta_dm_loc_oob(tBTA_DM_MSG *p_data) +{ + UNUSED(p_data); + BTM_ReadLocalOobData(); +} + +/******************************************************************************* +** +** Function bta_dm_ci_io_req_act +** +** Description respond to the IO capabilities request from BTM +** +** Returns void +** +*******************************************************************************/ +void bta_dm_ci_io_req_act(tBTA_DM_MSG *p_data) +{ + tBTM_AUTH_REQ auth_req = BTM_AUTH_AP_NO; + if(p_data->ci_io_req.auth_req) + auth_req = BTM_AUTH_AP_YES; + BTM_IoCapRsp(p_data->ci_io_req.bd_addr, p_data->ci_io_req.io_cap, + p_data->ci_io_req.oob_data, auth_req); +} + +/******************************************************************************* +** +** Function bta_dm_ci_rmt_oob_act +** +** Description respond to the OOB data request for the remote device from BTM +** +** +** Returns void +** +*******************************************************************************/ +void bta_dm_ci_rmt_oob_act(tBTA_DM_MSG *p_data) +{ + tBTM_STATUS res = BTM_NOT_AUTHORIZED; + + if(p_data->ci_rmt_oob.accept == TRUE) + res = BTM_SUCCESS; + BTM_RemoteOobDataReply(res, p_data->ci_rmt_oob.bd_addr, + p_data->ci_rmt_oob.c, p_data->ci_rmt_oob.r ); +} +#endif /* BTM_OOB_INCLUDED */ + +/******************************************************************************* +** +** Function bta_dm_search_start +** +** Description Starts an inquiry +** +** +** Returns void +** +*******************************************************************************/ +void bta_dm_search_start (tBTA_DM_MSG *p_data) +{ + tBTM_INQUIRY_CMPL result; + +#if (BLE_INCLUDED == TRUE && BTA_GATT_INCLUDED == TRUE) + UINT16 len = (UINT16)(sizeof(tBT_UUID) * p_data->search.num_uuid); + bta_dm_gattc_register(); +#endif + + APPL_TRACE_DEBUG("%s avoid_scatter=%d", __func__, p_bta_dm_cfg->avoid_scatter); + + if (p_bta_dm_cfg->avoid_scatter && + (p_data->search.rs_res == BTA_DM_RS_NONE) && bta_dm_check_av(BTA_DM_API_SEARCH_EVT)) + { + memcpy(&bta_dm_cb.search_msg, &p_data->search, sizeof(tBTA_DM_API_SEARCH)); + return; + } + + BTM_ClearInqDb(NULL); + /* save search params */ + bta_dm_search_cb.p_search_cback = p_data->search.p_cback; + bta_dm_search_cb.services = p_data->search.services; + +#if (BLE_INCLUDED == TRUE && BTA_GATT_INCLUDED == TRUE) + utl_freebuf((void **)&bta_dm_search_cb.p_srvc_uuid); + + if ((bta_dm_search_cb.num_uuid = p_data->search.num_uuid) != 0 && + p_data->search.p_uuid != NULL) + { + if ((bta_dm_search_cb.p_srvc_uuid = (tBT_UUID *)GKI_getbuf(len)) == NULL) + { + APPL_TRACE_ERROR("%s no resources", __func__); + + result.status = BTA_FAILURE; + result.num_resp = 0; + bta_dm_inq_cmpl_cb ((void *)&result); + return; + } + + memcpy(bta_dm_search_cb.p_srvc_uuid, p_data->search.p_uuid, len); + } +#endif + result.status = BTM_StartInquiry( (tBTM_INQ_PARMS*)&p_data->search.inq_params, + bta_dm_inq_results_cb, + (tBTM_CMPL_CB*) bta_dm_inq_cmpl_cb); + + APPL_TRACE_EVENT("%s status=%d", __func__, result.status); + if (result.status != BTM_CMD_STARTED) + { + result.num_resp = 0; + bta_dm_inq_cmpl_cb ((void *)&result); + } +} + +/******************************************************************************* +** +** Function bta_dm_search_cancel +** +** Description Cancels an ongoing search for devices +** +** +** Returns void +** +*******************************************************************************/ +void bta_dm_search_cancel (tBTA_DM_MSG *p_data) +{ + UNUSED(p_data); + tBTA_DM_MSG * p_msg; + + if (BTM_IsInquiryActive()) + { + if (BTM_CancelInquiry() != BTM_CMD_STARTED) + { + bta_dm_search_cancel_notify(NULL); + p_msg = (tBTA_DM_MSG *) GKI_getbuf(sizeof(tBTA_DM_MSG)); + if (p_msg != NULL) + { + p_msg->hdr.event = BTA_DM_SEARCH_CMPL_EVT; + p_msg->hdr.layer_specific = BTA_DM_API_DISCOVER_EVT; + bta_sys_sendmsg(p_msg); + } + } else { + /* flag a search cancel is pending */ + bta_dm_search_cb.cancel_pending = TRUE; + } + } + /* If no Service Search going on then issue cancel remote name in case it is active */ + else if (!bta_dm_search_cb.name_discover_done) + { + BTM_CancelRemoteDeviceName(); + + if ((p_msg = (tBTA_DM_MSG *) GKI_getbuf(sizeof(tBTA_DM_MSG))) != NULL) + { + p_msg->hdr.event = BTA_DM_SEARCH_CMPL_EVT; + p_msg->hdr.layer_specific = BTA_DM_API_DISCOVER_EVT; + bta_sys_sendmsg(p_msg); + } + + } + else { + if ((p_msg = (tBTA_DM_MSG *) GKI_getbuf(sizeof(tBTA_DM_MSG))) != NULL) + { + p_msg->hdr.event = BTA_DM_INQUIRY_CMPL_EVT; + p_msg->hdr.layer_specific = BTA_DM_API_DISCOVER_EVT; + bta_sys_sendmsg(p_msg); + } + } + +#if BLE_INCLUDED == TRUE && BTA_GATT_INCLUDED == TRUE + if (bta_dm_search_cb.gatt_disc_active) + { + bta_dm_cancel_gatt_discovery(bta_dm_search_cb.peer_bdaddr); + } +#endif +} + +/******************************************************************************* +** +** Function bta_dm_discover +** +** Description Discovers services on a remote device +** +** +** Returns void +** +*******************************************************************************/ +void bta_dm_discover (tBTA_DM_MSG *p_data) +{ +#if BLE_INCLUDED == TRUE && BTA_GATT_INCLUDED == TRUE + UINT16 len = (UINT16)(sizeof(tBT_UUID) * p_data->discover.num_uuid); +#endif + APPL_TRACE_EVENT("%s services_to_search=0x%04X, sdp_search=%d", __func__, + p_data->discover.services, p_data->discover.sdp_search); + + /* save the search condition */ + bta_dm_search_cb.services = p_data->discover.services; + +#if BLE_INCLUDED == TRUE && BTA_GATT_INCLUDED == TRUE + bta_dm_gattc_register(); + utl_freebuf((void **)&bta_dm_search_cb.p_srvc_uuid); + if ((bta_dm_search_cb.num_uuid = p_data->discover.num_uuid) != 0 && + p_data->discover.p_uuid != NULL) + { + if ((bta_dm_search_cb.p_srvc_uuid = (tBT_UUID *)GKI_getbuf(len)) == NULL) + { + p_data->discover.p_cback(BTA_DM_DISC_CMPL_EVT, NULL); + return; + } + memcpy(bta_dm_search_cb.p_srvc_uuid, p_data->discover.p_uuid, len); + } + bta_dm_search_cb.uuid_to_search = bta_dm_search_cb.num_uuid; +#endif + + bta_dm_search_cb.p_search_cback = p_data->discover.p_cback; + bta_dm_search_cb.sdp_search = p_data->discover.sdp_search; + bta_dm_search_cb.services_to_search = bta_dm_search_cb.services; + bta_dm_search_cb.service_index = 0; + bta_dm_search_cb.services_found = 0; + bta_dm_search_cb.peer_name[0] = 0; + bta_dm_search_cb.sdp_search = p_data->discover.sdp_search; + bta_dm_search_cb.p_btm_inq_info = BTM_InqDbRead (p_data->discover.bd_addr); + bta_dm_search_cb.transport = p_data->discover.transport; + + bta_dm_search_cb.name_discover_done = FALSE; + memcpy(&bta_dm_search_cb.uuid, &p_data->discover.uuid, sizeof(tSDP_UUID)); + bta_dm_discover_device(p_data->discover.bd_addr); +} + +/******************************************************************************* +** +** Function bta_dm_di_disc_cmpl +** +** Description Sends event to application when DI discovery complete +** +** Returns void +** +*******************************************************************************/ +void bta_dm_di_disc_cmpl(tBTA_DM_MSG *p_data) +{ + tBTA_DM_DI_DISC_CMPL di_disc; + + memset(&di_disc, 0, sizeof(tBTA_DM_DI_DISC_CMPL)); + bdcpy(di_disc.bd_addr, bta_dm_search_cb.peer_bdaddr); + + if((p_data->hdr.offset == SDP_SUCCESS) + || (p_data->hdr.offset == SDP_DB_FULL)) + { + di_disc.num_record = SDP_GetNumDiRecords(bta_dm_di_cb.p_di_db); + } + else + di_disc.result = BTA_FAILURE; + + bta_dm_di_cb.p_di_db = NULL; + bta_dm_search_cb.p_search_cback(BTA_DM_DI_DISC_CMPL_EVT, (tBTA_DM_SEARCH *) &di_disc); +} + +/******************************************************************************* +** +** Function bta_dm_di_disc_callback +** +** Description This function queries a remote device for DI information. +** +** +** Returns void +** +*******************************************************************************/ +static void bta_dm_di_disc_callback(UINT16 result) +{ + tBTA_DM_MSG * p_msg; + + if ((p_msg = (tBTA_DM_MSG *) GKI_getbuf(sizeof(tBTA_DM_MSG))) != NULL) + { + p_msg->hdr.event = BTA_DM_SEARCH_CMPL_EVT; + p_msg->hdr.layer_specific = BTA_DM_API_DI_DISCOVER_EVT; + p_msg->hdr.offset = result; + bta_sys_sendmsg(p_msg); + } +} + +/******************************************************************************* +** +** Function bta_dm_disable_search_and_disc +** +** Description Cancels an ongoing search or discovery for devices in case of +** a Bluetooth disable +** +** +** Returns void +** +*******************************************************************************/ +static void bta_dm_disable_search_and_disc (void) +{ + tBTA_DM_DI_DISC_CMPL di_disc; + + if (bta_dm_search_cb.state != BTA_DM_SEARCH_IDLE) + bta_dm_search_cancel(NULL); + + if (bta_dm_di_cb.p_di_db != NULL) + { + memset(&di_disc, 0, sizeof(tBTA_DM_DI_DISC_CMPL)); + bdcpy(di_disc.bd_addr, bta_dm_search_cb.peer_bdaddr); + di_disc.result = BTA_FAILURE; + + bta_dm_di_cb.p_di_db = NULL; + bta_dm_search_cb.p_search_cback(BTA_DM_DI_DISC_CMPL_EVT, NULL); + } +} + +/******************************************************************************* +** +** Function bta_dm_di_disc +** +** Description This function queries a remote device for DI information. +** +** +** Returns void +** +*******************************************************************************/ +void bta_dm_di_disc (tBTA_DM_MSG *p_data) +{ + UINT16 result = BTA_FAILURE; + tBTA_DM_MSG *p_msg; + + bta_dm_search_cb.p_search_cback = p_data->di_disc.p_cback; + bdcpy(bta_dm_search_cb.peer_bdaddr, p_data->di_disc.bd_addr); + bta_dm_di_cb.p_di_db = p_data->di_disc.p_sdp_db; + + if((bta_dm_search_cb.p_sdp_db = (tSDP_DISCOVERY_DB *)GKI_getbuf(BTA_DM_SDP_DB_SIZE)) != NULL) + { + if ( SDP_DiDiscover(bta_dm_search_cb.peer_bdaddr, p_data->di_disc.p_sdp_db, + p_data->di_disc.len, bta_dm_di_disc_callback) == SDP_SUCCESS) + { + result = BTA_SUCCESS; + } + } + else + { + APPL_TRACE_ERROR("No buffer to start DI discovery"); + } + + if ( result == BTA_FAILURE && + (p_msg = (tBTA_DM_MSG *) GKI_getbuf(sizeof(tBTA_DM_MSG))) != NULL) + { + p_msg->hdr.event = BTA_DM_SEARCH_CMPL_EVT; + p_msg->hdr.layer_specific = BTA_DM_API_DI_DISCOVER_EVT; + p_data->hdr.offset = result; + bta_sys_sendmsg(p_msg); + } +} + +/******************************************************************************* +** +** Function bta_dm_read_remote_device_name +** +** Description Initiate to get remote device name +** +** Returns TRUE if started to get remote name +** +*******************************************************************************/ +static BOOLEAN bta_dm_read_remote_device_name (BD_ADDR bd_addr,tBT_TRANSPORT transport) +{ + tBTM_STATUS btm_status; + + APPL_TRACE_DEBUG("bta_dm_read_remote_device_name"); + + bdcpy(bta_dm_search_cb.peer_bdaddr, bd_addr); + bta_dm_search_cb.peer_name[0] = 0; + + btm_status = BTM_ReadRemoteDeviceName (bta_dm_search_cb.peer_bdaddr, + (tBTM_CMPL_CB *) bta_dm_remname_cback, + transport); + + if ( btm_status == BTM_CMD_STARTED ) + { + APPL_TRACE_DEBUG("bta_dm_read_remote_device_name: BTM_ReadRemoteDeviceName is started"); + + return (TRUE); + } + else if ( btm_status == BTM_BUSY ) + { + APPL_TRACE_DEBUG("bta_dm_read_remote_device_name: BTM_ReadRemoteDeviceName is busy"); + + /* Remote name discovery is on going now so BTM cannot notify through "bta_dm_remname_cback" */ + /* adding callback to get notified that current reading remore name done */ + BTM_SecAddRmtNameNotifyCallback(&bta_dm_service_search_remname_cback); + + return (TRUE); + } + else + { + APPL_TRACE_WARNING("bta_dm_read_remote_device_name: BTM_ReadRemoteDeviceName returns 0x%02X", btm_status); + + return (FALSE); + } +} + +/******************************************************************************* +** +** Function bta_dm_inq_cmpl +** +** Description Process the inquiry complete event from BTM +** +** Returns void +** +*******************************************************************************/ +void bta_dm_inq_cmpl (tBTA_DM_MSG *p_data) +{ + tBTA_DM_MSG * p_msg; + tBTA_DM_SEARCH data; + + APPL_TRACE_DEBUG("bta_dm_inq_cmpl"); + + data.inq_cmpl.num_resps = p_data->inq_cmpl.num; + bta_dm_search_cb.p_search_cback(BTA_DM_INQ_CMPL_EVT, &data); + + if((bta_dm_search_cb.p_btm_inq_info = BTM_InqDbFirst()) != NULL) + { + /* start name and service discovery from the first device on inquiry result */ + bta_dm_search_cb.name_discover_done = FALSE; + bta_dm_search_cb.peer_name[0] = 0; + bta_dm_discover_device(bta_dm_search_cb.p_btm_inq_info->results.remote_bd_addr); + } + else + { + /* no devices, search complete */ + bta_dm_search_cb.services = 0; + + if ((p_msg = (tBTA_DM_MSG *) GKI_getbuf(sizeof(tBTA_DM_MSG))) != NULL) + { + p_msg->hdr.event = BTA_DM_SEARCH_CMPL_EVT; + p_msg->hdr.layer_specific = BTA_DM_API_DISCOVER_EVT; + bta_sys_sendmsg(p_msg); + } + } + } + +/******************************************************************************* +** +** Function bta_dm_rmt_name +** +** Description Process the remote name result from BTM +** +** Returns void +** +*******************************************************************************/ +void bta_dm_rmt_name (tBTA_DM_MSG *p_data) +{ + APPL_TRACE_DEBUG("bta_dm_rmt_name"); + + if( p_data->rem_name.result.disc_res.bd_name[0] && bta_dm_search_cb.p_btm_inq_info) + { + bta_dm_search_cb.p_btm_inq_info->appl_knows_rem_name = TRUE; + } + + bta_dm_discover_device(bta_dm_search_cb.peer_bdaddr); +} + +/******************************************************************************* +** +** Function bta_dm_disc_rmt_name +** +** Description Process the remote name result from BTM when application +** wants to find the name for a bdaddr +** +** Returns void +** +*******************************************************************************/ +void bta_dm_disc_rmt_name (tBTA_DM_MSG *p_data) +{ + tBTM_INQ_INFO *p_btm_inq_info; + + APPL_TRACE_DEBUG("bta_dm_disc_rmt_name"); + + p_btm_inq_info = BTM_InqDbRead (p_data->rem_name.result.disc_res.bd_addr); + if( p_btm_inq_info ) + { + if( p_data->rem_name.result.disc_res.bd_name[0] ) + { + p_btm_inq_info->appl_knows_rem_name = TRUE; + } + } + + bta_dm_discover_device(p_data->rem_name.result.disc_res.bd_addr); +} + +/******************************************************************************* +** +** Function bta_dm_sdp_result +** +** Description Process the discovery result from sdp +** +** Returns void +** +*******************************************************************************/ +void bta_dm_sdp_result (tBTA_DM_MSG *p_data) +{ + + tSDP_DISC_REC *p_sdp_rec = NULL; + tBTA_DM_MSG *p_msg; + BOOLEAN scn_found = FALSE; + UINT16 service = 0xFFFF; + tSDP_PROTOCOL_ELEM pe; + +#if BLE_INCLUDED == TRUE && BTA_GATT_INCLUDED == TRUE + tBT_UUID *p_uuid = bta_dm_search_cb.p_srvc_uuid; + tBTA_DM_SEARCH result; + tBT_UUID service_uuid; +#endif + + UINT32 num_uuids = 0; + UINT8 uuid_list[32][MAX_UUID_SIZE]; // assuming a max of 32 services + + if((p_data->sdp_event.sdp_result == SDP_SUCCESS) + || (p_data->sdp_event.sdp_result == SDP_NO_RECS_MATCH) + || (p_data->sdp_event.sdp_result == SDP_DB_FULL)) + { + APPL_TRACE_DEBUG("sdp_result::0x%x", p_data->sdp_event.sdp_result); + do + { + + p_sdp_rec = NULL; + if( bta_dm_search_cb.service_index == (BTA_USER_SERVICE_ID+1) ) + { + p_sdp_rec = SDP_FindServiceUUIDInDb(bta_dm_search_cb.p_sdp_db, &bta_dm_search_cb.uuid, p_sdp_rec); + + if (p_sdp_rec && SDP_FindProtocolListElemInRec(p_sdp_rec, UUID_PROTOCOL_RFCOMM, &pe)) + { + bta_dm_search_cb.peer_scn = (UINT8) pe.params[0]; + scn_found = TRUE; + } + } + else + { + service = bta_service_id_to_uuid_lkup_tbl[bta_dm_search_cb.service_index-1]; + p_sdp_rec = SDP_FindServiceInDb(bta_dm_search_cb.p_sdp_db, service, p_sdp_rec); + } +#if BLE_INCLUDED == TRUE && BTA_GATT_INCLUDED == TRUE + /* finished with BR/EDR services, now we check the result for GATT based service UUID */ + if (bta_dm_search_cb.service_index == BTA_MAX_SERVICE_ID) + { + if (bta_dm_search_cb.uuid_to_search != 0 && p_uuid != NULL) + { + p_uuid += (bta_dm_search_cb.num_uuid - bta_dm_search_cb.uuid_to_search); + /* only support 16 bits UUID for now */ + service = p_uuid->uu.uuid16; + + } + /* all GATT based services */ + do + { + /* find a service record, report it */ + p_sdp_rec = SDP_FindServiceInDb(bta_dm_search_cb.p_sdp_db, + 0, p_sdp_rec); + if (p_sdp_rec) + { + if (SDP_FindServiceUUIDInRec(p_sdp_rec, &service_uuid)) + { + /* send result back to app now, one by one */ + bdcpy (result.disc_ble_res.bd_addr, bta_dm_search_cb.peer_bdaddr); + BCM_STRNCPY_S((char*)result.disc_ble_res.bd_name, sizeof(BD_NAME), bta_dm_get_remname(), (BD_NAME_LEN)); + result.disc_ble_res.bd_name[BD_NAME_LEN] = 0; + result.disc_ble_res.service.len = service_uuid.len; + result.disc_ble_res.service.uu.uuid16 = service_uuid.uu.uuid16; + + bta_dm_search_cb.p_search_cback(BTA_DM_DISC_BLE_RES_EVT, &result); + } + } + + if (bta_dm_search_cb.uuid_to_search > 0) + break; + + } while (p_sdp_rec); + } + else +#endif + { + /* SDP_DB_FULL means some records with the + required attributes were received */ + if (((p_data->sdp_event.sdp_result == SDP_DB_FULL) && + bta_dm_search_cb.services != BTA_ALL_SERVICE_MASK) || + (p_sdp_rec != NULL)) + { + if (service != UUID_SERVCLASS_PNP_INFORMATION) + { + UINT16 tmp_svc = 0xFFFF; + bta_dm_search_cb.services_found |= + (tBTA_SERVICE_MASK)(BTA_SERVICE_ID_TO_SERVICE_MASK(bta_dm_search_cb.service_index-1)); + tmp_svc = bta_service_id_to_uuid_lkup_tbl[bta_dm_search_cb.service_index-1]; + /* Add to the list of UUIDs */ + sdpu_uuid16_to_uuid128(tmp_svc, uuid_list[num_uuids]); + num_uuids++; + } + } + } + + if(bta_dm_search_cb.services == BTA_ALL_SERVICE_MASK && + bta_dm_search_cb.services_to_search == 0) + { +#if BLE_INCLUDED == TRUE && BTA_GATT_INCLUDED == TRUE + if ( bta_dm_search_cb.service_index == BTA_BLE_SERVICE_ID && + bta_dm_search_cb.uuid_to_search > 0) + bta_dm_search_cb.uuid_to_search --; + + if (bta_dm_search_cb.uuid_to_search == 0 || + bta_dm_search_cb.service_index != BTA_BLE_SERVICE_ID) +#endif + bta_dm_search_cb.service_index++; + } + else /* regular one service per search or PNP search */ + break; + + } + while(bta_dm_search_cb.service_index <= BTA_MAX_SERVICE_ID); + +// GKI_freebuf(bta_dm_search_cb.p_sdp_db); +// bta_dm_search_cb.p_sdp_db = NULL; + APPL_TRACE_DEBUG("%s services_found = %04x", __FUNCTION__, + bta_dm_search_cb.services_found); + + /* Collect the 128-bit services here and put them into the list */ + if(bta_dm_search_cb.services == BTA_ALL_SERVICE_MASK) + { + p_sdp_rec = NULL; + do + { + tBT_UUID temp_uuid; + /* find a service record, report it */ + p_sdp_rec = SDP_FindServiceInDb_128bit(bta_dm_search_cb.p_sdp_db, p_sdp_rec); + if (p_sdp_rec) + { + if (SDP_FindServiceUUIDInRec_128bit(p_sdp_rec, &temp_uuid)) + { + memcpy(uuid_list[num_uuids], temp_uuid.uu.uuid128, MAX_UUID_SIZE); + num_uuids++; + } + } + } while (p_sdp_rec); + } + /* if there are more services to search for */ + if(bta_dm_search_cb.services_to_search) + { + /* Free up the p_sdp_db before checking the next one */ + bta_dm_free_sdp_db(NULL); + bta_dm_find_services(bta_dm_search_cb.peer_bdaddr); + } + else + { + /* callbacks */ + /* start next bd_addr if necessary */ + + BTM_SecDeleteRmtNameNotifyCallback(&bta_dm_service_search_remname_cback); + + + if ((p_msg = (tBTA_DM_MSG *) GKI_getbuf(sizeof(tBTA_DM_MSG))) != NULL) + { + p_msg->hdr.event = BTA_DM_DISCOVERY_RESULT_EVT; + p_msg->disc_result.result.disc_res.result = BTA_SUCCESS; + p_msg->disc_result.result.disc_res.p_raw_data = NULL; + p_msg->disc_result.result.disc_res.raw_data_size = 0; + p_msg->disc_result.result.disc_res.num_uuids = num_uuids; + p_msg->disc_result.result.disc_res.p_uuid_list = NULL; + if (num_uuids > 0) { + p_msg->disc_result.result.disc_res.p_uuid_list = (UINT8*)GKI_getbuf(num_uuids*MAX_UUID_SIZE); + if (p_msg->disc_result.result.disc_res.p_uuid_list) { + memcpy(p_msg->disc_result.result.disc_res.p_uuid_list, uuid_list, + num_uuids*MAX_UUID_SIZE); + } else { + p_msg->disc_result.result.disc_res.num_uuids = 0; + APPL_TRACE_ERROR("%s: Unable to allocate memory for uuid_list", __func__); + } + } + //copy the raw_data to the discovery result structure + // + + if ( bta_dm_search_cb.p_sdp_db != NULL && bta_dm_search_cb.p_sdp_db->raw_used != 0 && + bta_dm_search_cb.p_sdp_db->raw_data != NULL) { + APPL_TRACE_DEBUG( + "%s raw_data used = 0x%x raw_data_ptr = 0x%x", __func__, + bta_dm_search_cb.p_sdp_db->raw_used, + bta_dm_search_cb.p_sdp_db->raw_data); + + p_msg->disc_result.result.disc_res.p_raw_data = GKI_getbuf(bta_dm_search_cb.p_sdp_db->raw_used); + if ( NULL != p_msg->disc_result.result.disc_res.p_raw_data ) { + memcpy( p_msg->disc_result.result.disc_res.p_raw_data, + bta_dm_search_cb.p_sdp_db->raw_data, + bta_dm_search_cb.p_sdp_db->raw_used ); + + p_msg->disc_result.result.disc_res.raw_data_size = + bta_dm_search_cb.p_sdp_db->raw_used; + + } else { + APPL_TRACE_DEBUG("%s GKI Alloc failed to allocate %d bytes !!", __func__, + bta_dm_search_cb.p_sdp_db->raw_used); + } + + bta_dm_search_cb.p_sdp_db->raw_data = NULL; //no need to free this - it is a global assigned. + bta_dm_search_cb.p_sdp_db->raw_used = 0; + bta_dm_search_cb.p_sdp_db->raw_size = 0; + } + else { + APPL_TRACE_DEBUG("%s raw data size is 0 or raw_data is null!!", __func__); + } + /* Done with p_sdp_db. Free it */ + bta_dm_free_sdp_db(NULL); + p_msg->disc_result.result.disc_res.services = bta_dm_search_cb.services_found; + + //Piggy back the SCN over result field + if( scn_found ) + { + p_msg->disc_result.result.disc_res.result = (3 + bta_dm_search_cb.peer_scn); + p_msg->disc_result.result.disc_res.services |= BTA_USER_SERVICE_MASK; + + APPL_TRACE_EVENT(" Piggy back the SCN over result field SCN=%d", bta_dm_search_cb.peer_scn); + + } + bdcpy (p_msg->disc_result.result.disc_res.bd_addr, bta_dm_search_cb.peer_bdaddr); + BCM_STRNCPY_S((char*)p_msg->disc_result.result.disc_res.bd_name, sizeof(BD_NAME), + bta_dm_get_remname(), (BD_NAME_LEN-1)); + + /* make sure the string is null terminated */ + p_msg->disc_result.result.disc_res.bd_name[BD_NAME_LEN-1] = 0; + + bta_sys_sendmsg(p_msg); + } + } + } else { + /* conn failed. No need for timer */ + if(p_data->sdp_event.sdp_result == SDP_CONN_FAILED || p_data->sdp_event.sdp_result == SDP_CONN_REJECTED + || p_data->sdp_event.sdp_result == SDP_SECURITY_ERR) + bta_dm_search_cb.wait_disc = FALSE; + + /* not able to connect go to next device */ + GKI_freebuf(bta_dm_search_cb.p_sdp_db); + bta_dm_search_cb.p_sdp_db = NULL; + + BTM_SecDeleteRmtNameNotifyCallback(&bta_dm_service_search_remname_cback); + + if ((p_msg = (tBTA_DM_MSG *) GKI_getbuf(sizeof(tBTA_DM_MSG))) != NULL) + { + p_msg->hdr.event = BTA_DM_DISCOVERY_RESULT_EVT; + p_msg->disc_result.result.disc_res.result = BTA_FAILURE; + p_msg->disc_result.result.disc_res.services = bta_dm_search_cb.services_found; + bdcpy (p_msg->disc_result.result.disc_res.bd_addr, bta_dm_search_cb.peer_bdaddr); + BCM_STRNCPY_S((char*)p_msg->disc_result.result.disc_res.bd_name, sizeof(BD_NAME), + bta_dm_get_remname(), (BD_NAME_LEN-1)); + + /* make sure the string is null terminated */ + p_msg->disc_result.result.disc_res.bd_name[BD_NAME_LEN-1] = 0; + + bta_sys_sendmsg(p_msg); + } + } +} + +/******************************************************************************* +** +** Function bta_dm_search_cmpl +** +** Description Sends event to application +** +** Returns void +** +*******************************************************************************/ +void bta_dm_search_cmpl (tBTA_DM_MSG *p_data) +{ + APPL_TRACE_EVENT("%s", __func__); + +#if (BLE_INCLUDED == TRUE && BTA_GATT_INCLUDED == TRUE) + utl_freebuf((void **)&bta_dm_search_cb.p_srvc_uuid); +#endif + + if (p_data->hdr.layer_specific == BTA_DM_API_DI_DISCOVER_EVT) + bta_dm_di_disc_cmpl(p_data); + else + bta_dm_search_cb.p_search_cback(BTA_DM_DISC_CMPL_EVT, NULL); +} + +/******************************************************************************* +** +** Function bta_dm_disc_result +** +** Description Service discovery result when discovering services on a device +** +** Returns void +** +*******************************************************************************/ +void bta_dm_disc_result (tBTA_DM_MSG *p_data) +{ + APPL_TRACE_EVENT("%s", __func__); + +#if BLE_INCLUDED == TRUE && BTA_GATT_INCLUDED == TRUE + /* if any BR/EDR service discovery has been done, report the event */ + if ((bta_dm_search_cb.services & ((BTA_ALL_SERVICE_MASK | BTA_USER_SERVICE_MASK ) & ~BTA_BLE_SERVICE_MASK))) +#endif + bta_dm_search_cb.p_search_cback(BTA_DM_DISC_RES_EVT, &p_data->disc_result.result); + + tBTA_DM_MSG *p_msg = (tBTA_DM_MSG *) GKI_getbuf(sizeof(tBTA_DM_MSG)); + + /* send a message to change state */ + if (p_msg != NULL) + { + p_msg->hdr.event = BTA_DM_SEARCH_CMPL_EVT; + p_msg->hdr.layer_specific = BTA_DM_API_DISCOVER_EVT; + bta_sys_sendmsg(p_msg); + } +} + +/******************************************************************************* +** +** Function bta_dm_search_result +** +** Description Service discovery result while searching for devices +** +** Returns void +** +*******************************************************************************/ +void bta_dm_search_result (tBTA_DM_MSG *p_data) +{ + APPL_TRACE_DEBUG("%s searching:0x%04x, result:0x%04x", __func__, + bta_dm_search_cb.services, + p_data->disc_result.result.disc_res.services); + + /* call back if application wants name discovery or found services that application is searching */ + if (( !bta_dm_search_cb.services ) + ||(( bta_dm_search_cb.services ) && ( p_data->disc_result.result.disc_res.services ))) + { + bta_dm_search_cb.p_search_cback(BTA_DM_DISC_RES_EVT, &p_data->disc_result.result); + } + + /* if searching did not initiate to create link */ + if(!bta_dm_search_cb.wait_disc ) + { + /* if service searching is done with EIR, don't search next device */ + if( bta_dm_search_cb.p_btm_inq_info ) + bta_dm_discover_next_device(); + } + else + { + /* wait until link is disconnected or timeout */ + bta_dm_search_cb.sdp_results = TRUE; + bta_dm_search_cb.search_timer.p_cback = (TIMER_CBACK*)&bta_dm_search_timer_cback; + bta_sys_start_timer(&bta_dm_search_cb.search_timer, 0, 1000*(L2CAP_LINK_INACTIVITY_TOUT+1) ); + } + +} + +/******************************************************************************* +** +** Function bta_dm_search_timer_cback +** +** Description Called when ACL disconnect time is over +** +** +** Returns void +** +*******************************************************************************/ +static void bta_dm_search_timer_cback (TIMER_LIST_ENT *p_tle) +{ + UNUSED(p_tle); + + APPL_TRACE_EVENT("%s", __func__); + bta_dm_search_cb.wait_disc = FALSE; + + /* proceed with next device */ + bta_dm_discover_next_device(); + +} + + +/******************************************************************************* +** +** Function bta_dm_free_sdp_db +** +** Description Frees SDP data base +** +** Returns void +** +*******************************************************************************/ +void bta_dm_free_sdp_db (tBTA_DM_MSG *p_data) +{ + UNUSED(p_data); + if(bta_dm_search_cb.p_sdp_db) + { + GKI_freebuf(bta_dm_search_cb.p_sdp_db); + bta_dm_search_cb.p_sdp_db = NULL; + } + +} + +/******************************************************************************* +** +** Function bta_dm_queue_search +** +** Description Queues search command while search is being cancelled +** +** Returns void +** +*******************************************************************************/ +void bta_dm_queue_search (tBTA_DM_MSG *p_data) +{ + if(bta_dm_search_cb.p_search_queue) + { + GKI_freebuf(bta_dm_search_cb.p_search_queue); + } + + bta_dm_search_cb.p_search_queue = (tBTA_DM_MSG *)GKI_getbuf(sizeof(tBTA_DM_API_SEARCH)); + memcpy(bta_dm_search_cb.p_search_queue, p_data, sizeof(tBTA_DM_API_SEARCH)); + +} + +/******************************************************************************* +** +** Function bta_dm_queue_disc +** +** Description Queues discovery command while search is being cancelled +** +** Returns void +** +*******************************************************************************/ +void bta_dm_queue_disc (tBTA_DM_MSG *p_data) +{ + if(bta_dm_search_cb.p_search_queue) + { + GKI_freebuf(bta_dm_search_cb.p_search_queue); + } + + bta_dm_search_cb.p_search_queue = (tBTA_DM_MSG *)GKI_getbuf(sizeof(tBTA_DM_API_DISCOVER)); + memcpy(bta_dm_search_cb.p_search_queue, p_data, sizeof(tBTA_DM_API_DISCOVER)); + +} + +/******************************************************************************* +** +** Function bta_dm_search_clear_queue +** +** Description Clears the queue if API search cancel is called +** +** Returns void +** +*******************************************************************************/ +void bta_dm_search_clear_queue (tBTA_DM_MSG *p_data) +{ + UNUSED(p_data); + if(bta_dm_search_cb.p_search_queue) + { + GKI_freebuf(bta_dm_search_cb.p_search_queue); + bta_dm_search_cb.p_search_queue = NULL; + } +} + +/******************************************************************************* +** +** Function bta_dm_search_cancel_cmpl +** +** Description Search cancel is complete +** +** Returns void +** +*******************************************************************************/ +void bta_dm_search_cancel_cmpl (tBTA_DM_MSG *p_data) +{ + UNUSED(p_data); + if(bta_dm_search_cb.p_search_queue) + { + bta_sys_sendmsg(bta_dm_search_cb.p_search_queue); + bta_dm_search_cb.p_search_queue = NULL; + } + +} + +/******************************************************************************* +** +** Function bta_dm_search_cancel_transac_cmpl +** +** Description Current Service Discovery or remote name procedure is +** completed after search cancellation +** +** Returns void +** +*******************************************************************************/ +void bta_dm_search_cancel_transac_cmpl(tBTA_DM_MSG *p_data) +{ + UNUSED(p_data); + if(bta_dm_search_cb.p_sdp_db) + { + GKI_freebuf(bta_dm_search_cb.p_sdp_db); + bta_dm_search_cb.p_sdp_db = NULL; + } + + bta_dm_search_cancel_notify(NULL); +} + + +/******************************************************************************* +** +** Function bta_dm_search_cancel_notify +** +** Description Notify application that search has been cancelled +** +** Returns void +** +*******************************************************************************/ +void bta_dm_search_cancel_notify (tBTA_DM_MSG *p_data) +{ + UNUSED(p_data); + if (bta_dm_search_cb.p_search_cback) + { + bta_dm_search_cb.p_search_cback(BTA_DM_SEARCH_CANCEL_CMPL_EVT, NULL); + } + if (!bta_dm_search_cb.name_discover_done) + { + BTM_CancelRemoteDeviceName(); + } +#if (BLE_INCLUDED == TRUE) && (BTA_GATT_INCLUDED == TRUE) + if (bta_dm_search_cb.gatt_disc_active) + { + bta_dm_cancel_gatt_discovery(bta_dm_search_cb.peer_bdaddr); + } +#endif + +} + +/******************************************************************************* +** +** Function bta_dm_find_services +** +** Description Starts discovery on a device +** +** Returns void +** +*******************************************************************************/ +static void bta_dm_find_services ( BD_ADDR bd_addr) +{ + + tSDP_UUID uuid; + UINT16 num_attrs = 1; + tBTA_DM_MSG *p_msg; + + memset (&uuid, 0, sizeof(tSDP_UUID)); + + while(bta_dm_search_cb.service_index < BTA_MAX_SERVICE_ID) + { + if( bta_dm_search_cb.services_to_search + & (tBTA_SERVICE_MASK)(BTA_SERVICE_ID_TO_SERVICE_MASK(bta_dm_search_cb.service_index))) + { + if((bta_dm_search_cb.p_sdp_db = (tSDP_DISCOVERY_DB *)GKI_getbuf(BTA_DM_SDP_DB_SIZE)) != NULL) + { + APPL_TRACE_DEBUG("bta_dm_search_cb.services = %04x***********", bta_dm_search_cb.services); + /* try to search all services by search based on L2CAP UUID */ + if(bta_dm_search_cb.services == BTA_ALL_SERVICE_MASK ) + { + LOG_INFO("%s services_to_search=%08x", __func__, bta_dm_search_cb.services_to_search); + if (bta_dm_search_cb.services_to_search & BTA_RES_SERVICE_MASK) + { + uuid.uu.uuid16 = bta_service_id_to_uuid_lkup_tbl[0]; + bta_dm_search_cb.services_to_search &= ~BTA_RES_SERVICE_MASK; + } + else + { + uuid.uu.uuid16 = UUID_PROTOCOL_L2CAP; + bta_dm_search_cb.services_to_search = 0; + } + } + else + { +#if BLE_INCLUDED == TRUE && BTA_GATT_INCLUDED == TRUE + /* for LE only profile */ + if (bta_dm_search_cb.service_index == BTA_BLE_SERVICE_ID) + { + if (bta_dm_search_cb.uuid_to_search > 0 && bta_dm_search_cb.p_srvc_uuid) + { + memcpy(&uuid, + (const void *)(bta_dm_search_cb.p_srvc_uuid + \ + bta_dm_search_cb.num_uuid - bta_dm_search_cb.uuid_to_search), + sizeof(tBT_UUID)); + + bta_dm_search_cb.uuid_to_search -- ; + } + else + uuid.uu.uuid16 = bta_service_id_to_uuid_lkup_tbl[bta_dm_search_cb.service_index]; + + /* last one? clear the BLE service bit if all discovery has been done */ + if (bta_dm_search_cb.uuid_to_search == 0) + bta_dm_search_cb.services_to_search &= + (tBTA_SERVICE_MASK)(~(BTA_SERVICE_ID_TO_SERVICE_MASK(bta_dm_search_cb.service_index))); + + } + else +#endif + { + /* remove the service from services to be searched */ + bta_dm_search_cb.services_to_search &= + (tBTA_SERVICE_MASK)(~(BTA_SERVICE_ID_TO_SERVICE_MASK(bta_dm_search_cb.service_index))); + uuid.uu.uuid16 = bta_service_id_to_uuid_lkup_tbl[bta_dm_search_cb.service_index]; + } + } + + if (uuid.len == 0) + uuid.len = LEN_UUID_16; + + if (bta_dm_search_cb.service_index == BTA_USER_SERVICE_ID) + { + memcpy(&uuid, &bta_dm_search_cb.uuid, sizeof(tSDP_UUID)); + } + + LOG_INFO("%s search UUID = %04x", __func__, uuid.uu.uuid16); + SDP_InitDiscoveryDb (bta_dm_search_cb.p_sdp_db, BTA_DM_SDP_DB_SIZE, 1, &uuid, 0, NULL); + + memset(g_disc_raw_data_buf, 0, sizeof(g_disc_raw_data_buf)); + bta_dm_search_cb.p_sdp_db->raw_data = g_disc_raw_data_buf; + + bta_dm_search_cb.p_sdp_db->raw_size = MAX_DISC_RAW_DATA_BUF; + + if (!SDP_ServiceSearchAttributeRequest (bd_addr, bta_dm_search_cb.p_sdp_db, &bta_dm_sdp_callback)) + { + /* if discovery not successful with this device + proceed to next one */ + GKI_freebuf(bta_dm_search_cb.p_sdp_db); + bta_dm_search_cb.p_sdp_db = NULL; + bta_dm_search_cb.service_index = BTA_MAX_SERVICE_ID; + + } + else + { +#if BLE_INCLUDED == TRUE && BTA_GATT_INCLUDED == TRUE + if ((bta_dm_search_cb.service_index == BTA_BLE_SERVICE_ID && + bta_dm_search_cb.uuid_to_search == 0) || + bta_dm_search_cb.service_index != BTA_BLE_SERVICE_ID) +#endif + bta_dm_search_cb.service_index++; + return; + } + } + else + { + APPL_TRACE_ERROR("#### Failed to allocate SDP DB buffer! ####"); + } + } + + bta_dm_search_cb.service_index++; + } + + /* no more services to be discovered */ + if(bta_dm_search_cb.service_index >= BTA_MAX_SERVICE_ID) + { + if ((p_msg = (tBTA_DM_MSG *) GKI_getbuf(sizeof(tBTA_DM_MSG))) != NULL) + { + p_msg->hdr.event = BTA_DM_DISCOVERY_RESULT_EVT; + p_msg->disc_result.result.disc_res.services = bta_dm_search_cb.services_found; + bdcpy (p_msg->disc_result.result.disc_res.bd_addr, bta_dm_search_cb.peer_bdaddr); + BCM_STRNCPY_S((char*)p_msg->disc_result.result.disc_res.bd_name, sizeof(BD_NAME), + bta_dm_get_remname(), (BD_NAME_LEN-1)); + + /* make sure the string is terminated */ + p_msg->disc_result.result.disc_res.bd_name[BD_NAME_LEN-1] = 0; + + bta_sys_sendmsg(p_msg); + } + } +} + +/******************************************************************************* +** +** Function bta_dm_discover_next_device +** +** Description Starts discovery on the next device in Inquiry data base +** +** Returns void +** +*******************************************************************************/ +static void bta_dm_discover_next_device(void) +{ + + tBTA_DM_MSG * p_msg; + + APPL_TRACE_DEBUG("bta_dm_discover_next_device"); + + /* searching next device on inquiry result */ + if((bta_dm_search_cb.p_btm_inq_info = BTM_InqDbNext(bta_dm_search_cb.p_btm_inq_info)) != NULL) + { + bta_dm_search_cb.name_discover_done = FALSE; + bta_dm_search_cb.peer_name[0] = 0; + bta_dm_discover_device(bta_dm_search_cb.p_btm_inq_info->results.remote_bd_addr); + } + else + { + /* no devices, search complete */ + bta_dm_search_cb.services = 0; + + if ((p_msg = (tBTA_DM_MSG *) GKI_getbuf(sizeof(tBTA_DM_MSG))) != NULL) + { + p_msg->hdr.event = BTA_DM_SEARCH_CMPL_EVT; + p_msg->hdr.layer_specific = BTA_DM_API_DISCOVER_EVT; + bta_sys_sendmsg(p_msg); + } + } +} + +/******************************************************************************* +** +** Function bta_dm_discover_device +** +** Description Starts name and service discovery on the device +** +** Returns void +** +*******************************************************************************/ +static void bta_dm_discover_device(BD_ADDR remote_bd_addr) +{ + tBTA_DM_MSG * p_msg; + tBT_TRANSPORT transport = BT_TRANSPORT_BR_EDR; + +#if BLE_INCLUDED == TRUE + if (bta_dm_search_cb.transport == BTA_TRANSPORT_UNKNOWN) + { + tBT_DEVICE_TYPE dev_type; + tBLE_ADDR_TYPE addr_type; + + BTM_ReadDevInfo(remote_bd_addr, &dev_type, &addr_type); + if (dev_type == BT_DEVICE_TYPE_BLE || addr_type == BLE_ADDR_RANDOM) + transport = BT_TRANSPORT_LE; + } else { + transport = bta_dm_search_cb.transport; + } +#endif + + /* Reset transport state for next discovery */ + bta_dm_search_cb.transport = BTA_TRANSPORT_UNKNOWN; + + APPL_TRACE_DEBUG("%s BDA:0x%02X%02X%02X%02X%02X%02X", __func__, + remote_bd_addr[0],remote_bd_addr[1], + remote_bd_addr[2],remote_bd_addr[3], + remote_bd_addr[4],remote_bd_addr[5]); + + bdcpy(bta_dm_search_cb.peer_bdaddr, remote_bd_addr); + + APPL_TRACE_DEBUG("%s name_discover_done = %d p_btm_inq_info 0x%x state = %d, transport=%d", + __func__, + bta_dm_search_cb.name_discover_done, + bta_dm_search_cb.p_btm_inq_info, + bta_dm_search_cb.state, + transport); + + if (bta_dm_search_cb.p_btm_inq_info) + { + APPL_TRACE_DEBUG("%s appl_knows_rem_name %d", __func__, + bta_dm_search_cb.p_btm_inq_info->appl_knows_rem_name); + } + + if((bta_dm_search_cb.p_btm_inq_info) + && (bta_dm_search_cb.p_btm_inq_info->results.device_type == BT_DEVICE_TYPE_BLE) + && (bta_dm_search_cb.state == BTA_DM_SEARCH_ACTIVE)) + { + /* Do not perform RNR for LE devices at inquiry complete*/ + bta_dm_search_cb.name_discover_done = TRUE; + } + + /* if name discovery is not done and application needs remote name */ + if ((!bta_dm_search_cb.name_discover_done) + && (( bta_dm_search_cb.p_btm_inq_info == NULL ) + ||(bta_dm_search_cb.p_btm_inq_info && (!bta_dm_search_cb.p_btm_inq_info->appl_knows_rem_name)))) + { + if (bta_dm_read_remote_device_name(bta_dm_search_cb.peer_bdaddr, transport) == TRUE) + return; + + /* starting name discovery failed */ + bta_dm_search_cb.name_discover_done = TRUE; + } + + /* if application wants to discover service */ + if ( bta_dm_search_cb.services ) + { + /* initialize variables */ + bta_dm_search_cb.service_index = 0; + bta_dm_search_cb.services_found = 0; + bta_dm_search_cb.services_to_search = bta_dm_search_cb.services; +#if BLE_INCLUDED == TRUE && BTA_GATT_INCLUDED == TRUE + bta_dm_search_cb.uuid_to_search = bta_dm_search_cb.num_uuid; +#endif + if ((bta_dm_search_cb.p_btm_inq_info != NULL) && + bta_dm_search_cb.services != BTA_USER_SERVICE_MASK + &&(bta_dm_search_cb.sdp_search == FALSE)) + { + /* check if EIR provides the information of supported services */ + bta_dm_eir_search_services( &bta_dm_search_cb.p_btm_inq_info->results, + &bta_dm_search_cb.services_to_search, + &bta_dm_search_cb.services_found ); + } + + /* if seaching with EIR is not completed */ + if(bta_dm_search_cb.services_to_search) + { + /* check whether connection already exists to the device + if connection exists, we don't have to wait for ACL + link to go down to start search on next device */ + if (BTM_IsAclConnectionUp(bta_dm_search_cb.peer_bdaddr, BT_TRANSPORT_BR_EDR)) + bta_dm_search_cb.wait_disc = FALSE; + else + bta_dm_search_cb.wait_disc = TRUE; + +#if (BLE_INCLUDED == TRUE && (defined BTA_GATT_INCLUDED) && (BTA_GATT_INCLUDED == TRUE)) + if ( bta_dm_search_cb.p_btm_inq_info ) + { + APPL_TRACE_DEBUG("%s p_btm_inq_info 0x%x results.device_type 0x%x services_to_search 0x%x", + __func__, + bta_dm_search_cb.p_btm_inq_info, + bta_dm_search_cb.p_btm_inq_info->results.device_type, + bta_dm_search_cb.services_to_search); + } + + if (transport == BT_TRANSPORT_LE) + { + if (bta_dm_search_cb.services_to_search & BTA_BLE_SERVICE_MASK) + { + //set the raw data buffer here + memset(g_disc_raw_data_buf, 0, sizeof(g_disc_raw_data_buf)); + bta_dm_search_cb.p_ble_rawdata = g_disc_raw_data_buf; + + bta_dm_search_cb.ble_raw_size = MAX_DISC_RAW_DATA_BUF; + bta_dm_search_cb.ble_raw_used = 0; + + /* start GATT for service discovery */ + btm_dm_start_gatt_discovery(bta_dm_search_cb.peer_bdaddr); + return; + } + } + else +#endif + { + bta_dm_search_cb.sdp_results = FALSE; + bta_dm_find_services(bta_dm_search_cb.peer_bdaddr); + return; + } + } + } + + /* name discovery and service discovery are done for this device */ + if ((p_msg = (tBTA_DM_MSG *) GKI_getbuf(sizeof(tBTA_DM_MSG))) != NULL) + { + p_msg->hdr.event = BTA_DM_DISCOVERY_RESULT_EVT; + /* initialize the data structure - includes p_raw_data and raw_data_size */ + memset(&(p_msg->disc_result.result), 0, sizeof(tBTA_DM_DISC_RES)); + p_msg->disc_result.result.disc_res.result = BTA_SUCCESS; + p_msg->disc_result.result.disc_res.services = bta_dm_search_cb.services_found; + bdcpy (p_msg->disc_result.result.disc_res.bd_addr, bta_dm_search_cb.peer_bdaddr); + BCM_STRNCPY_S((char*)p_msg->disc_result.result.disc_res.bd_name, sizeof(BD_NAME), + (char*)bta_dm_search_cb.peer_name, (BD_NAME_LEN-1)); + + /* make sure the string is terminated */ + p_msg->disc_result.result.disc_res.bd_name[BD_NAME_LEN-1] = 0; + + bta_sys_sendmsg(p_msg); + } +} + +/******************************************************************************* +** +** Function bta_dm_sdp_callback +** +** Description Callback from sdp with discovery status +** +** Returns void +** +*******************************************************************************/ +static void bta_dm_sdp_callback (UINT16 sdp_status) +{ + + tBTA_DM_SDP_RESULT * p_msg; + + if ((p_msg = (tBTA_DM_SDP_RESULT *) GKI_getbuf(sizeof(tBTA_DM_SDP_RESULT))) != NULL) + { + p_msg->hdr.event = BTA_DM_SDP_RESULT_EVT; + p_msg->sdp_result = sdp_status; + bta_sys_sendmsg(p_msg); + + } +} + +/******************************************************************************* +** +** Function bta_dm_inq_results_cb +** +** Description Inquiry results callback from BTM +** +** Returns void +** +*******************************************************************************/ +static void bta_dm_inq_results_cb (tBTM_INQ_RESULTS *p_inq, UINT8 *p_eir) +{ + + tBTA_DM_SEARCH result; + tBTM_INQ_INFO *p_inq_info; + UINT16 service_class; + + bdcpy(result.inq_res.bd_addr, p_inq->remote_bd_addr); + memcpy(result.inq_res.dev_class, p_inq->dev_class, DEV_CLASS_LEN); + BTM_COD_SERVICE_CLASS(service_class, p_inq->dev_class); + result.inq_res.is_limited = (service_class & BTM_COD_SERVICE_LMTD_DISCOVER)?TRUE:FALSE; + result.inq_res.rssi = p_inq->rssi; + +#if (BLE_INCLUDED == TRUE) + result.inq_res.ble_addr_type = p_inq->ble_addr_type; + result.inq_res.inq_result_type = p_inq->inq_result_type; + result.inq_res.device_type = p_inq->device_type; + result.inq_res.flag = p_inq->flag; +#endif + + /* application will parse EIR to find out remote device name */ + result.inq_res.p_eir = p_eir; + + if((p_inq_info = BTM_InqDbRead(p_inq->remote_bd_addr)) != NULL) + { + /* initialize remt_name_not_required to FALSE so that we get the name by default */ + result.inq_res.remt_name_not_required = FALSE; + + } + + if(bta_dm_search_cb.p_search_cback) + bta_dm_search_cb.p_search_cback(BTA_DM_INQ_RES_EVT, &result); + + if(p_inq_info) + { + /* application indicates if it knows the remote name, inside the callback + copy that to the inquiry data base*/ + if(result.inq_res.remt_name_not_required) + p_inq_info->appl_knows_rem_name = TRUE; + + } + + +} + + +/******************************************************************************* +** +** Function bta_dm_inq_cmpl_cb +** +** Description Inquiry complete callback from BTM +** +** Returns void +** +*******************************************************************************/ +static void bta_dm_inq_cmpl_cb (void * p_result) +{ + tBTA_DM_MSG * p_msg; + + if (bta_dm_search_cb.cancel_pending == FALSE) + { + APPL_TRACE_DEBUG("%s", __FUNCTION__); + p_msg = (tBTA_DM_MSG *) GKI_getbuf(sizeof(tBTA_DM_MSG)); + if (p_msg != NULL) { + p_msg->inq_cmpl.hdr.event = BTA_DM_INQUIRY_CMPL_EVT; + p_msg->inq_cmpl.num = ((tBTM_INQUIRY_CMPL *)p_result)->num_resp; + bta_sys_sendmsg(p_msg); + } + } + else + { + bta_dm_search_cb.cancel_pending = FALSE; + bta_dm_search_cancel_notify(NULL); + + p_msg = (tBTA_DM_MSG *) GKI_getbuf(sizeof(tBTA_DM_MSG)); + if (p_msg != NULL) { + p_msg->hdr.event = BTA_DM_SEARCH_CMPL_EVT; + p_msg->hdr.layer_specific = BTA_DM_API_DISCOVER_EVT; + bta_sys_sendmsg(p_msg); + } + } +} + +/******************************************************************************* +** +** Function bta_dm_service_search_remname_cback +** +** Description Remote name call back from BTM during service discovery +** +** Returns void +** +*******************************************************************************/ +static void bta_dm_service_search_remname_cback (BD_ADDR bd_addr, DEV_CLASS dc, BD_NAME bd_name) +{ + tBTM_REMOTE_DEV_NAME rem_name; + tBTM_STATUS btm_status; + UNUSED(dc); + + APPL_TRACE_DEBUG("bta_dm_service_search_remname_cback name=<%s>", bd_name); + + /* if this is what we are looking for */ + if (!bdcmp( bta_dm_search_cb.peer_bdaddr, bd_addr)) + { + rem_name.length = strlen((char*)bd_name); + if (rem_name.length > (BD_NAME_LEN-1)) + { + rem_name.length = (BD_NAME_LEN-1); + rem_name.remote_bd_name[(BD_NAME_LEN-1)] = 0; + } + BCM_STRNCPY_S((char*)rem_name.remote_bd_name, sizeof(BD_NAME), (char*)bd_name, (BD_NAME_LEN-1)); + rem_name.status = BTM_SUCCESS; + + bta_dm_remname_cback(&rem_name); + } + else + { + /* get name of device */ + btm_status = BTM_ReadRemoteDeviceName (bta_dm_search_cb.peer_bdaddr, + (tBTM_CMPL_CB *) bta_dm_remname_cback, + BT_TRANSPORT_BR_EDR); + if ( btm_status == BTM_BUSY ) + { + /* wait for next chance(notification of remote name discovery done) */ + APPL_TRACE_DEBUG("bta_dm_service_search_remname_cback: BTM_ReadRemoteDeviceName is busy"); + } + else if ( btm_status != BTM_CMD_STARTED ) + { + /* if failed to start getting remote name then continue */ + APPL_TRACE_WARNING("bta_dm_service_search_remname_cback: BTM_ReadRemoteDeviceName returns 0x%02X", btm_status); + + rem_name.length = 0; + rem_name.remote_bd_name[0] = 0; + rem_name.status = btm_status; + bta_dm_remname_cback(&rem_name); + } + } +} + + +/******************************************************************************* +** +** Function bta_dm_remname_cback +** +** Description Remote name complete call back from BTM +** +** Returns void +** +*******************************************************************************/ +static void bta_dm_remname_cback (tBTM_REMOTE_DEV_NAME *p_remote_name) +{ + tBTA_DM_REM_NAME * p_msg; + + APPL_TRACE_DEBUG("bta_dm_remname_cback len = %d name=<%s>", p_remote_name->length, + p_remote_name->remote_bd_name); + + /* remote name discovery is done but it could be failed */ + bta_dm_search_cb.name_discover_done = TRUE; + BCM_STRNCPY_S((char*)bta_dm_search_cb.peer_name, sizeof(BD_NAME), (char*)p_remote_name->remote_bd_name, (BD_NAME_LEN)); + bta_dm_search_cb.peer_name[BD_NAME_LEN]=0; + + BTM_SecDeleteRmtNameNotifyCallback(&bta_dm_service_search_remname_cback); + +#if BLE_INCLUDED == TRUE + if (bta_dm_search_cb.transport == BT_TRANSPORT_LE ) + { + GAP_BleReadPeerPrefConnParams (bta_dm_search_cb.peer_bdaddr); + } +#endif + + if ((p_msg = (tBTA_DM_REM_NAME *) GKI_getbuf(sizeof(tBTA_DM_REM_NAME))) != NULL) + { + bdcpy (p_msg->result.disc_res.bd_addr, bta_dm_search_cb.peer_bdaddr); + BCM_STRNCPY_S((char*)p_msg->result.disc_res.bd_name, sizeof(BD_NAME), (char*)p_remote_name->remote_bd_name, (BD_NAME_LEN)); + + /* make sure the string is null terminated */ + p_msg->result.disc_res.bd_name[BD_NAME_LEN] = 0; + + p_msg->hdr.event = BTA_DM_REMT_NAME_EVT; + bta_sys_sendmsg(p_msg); + + } +} + +/******************************************************************************* +** +** Function bta_dm_authorize_cback +** +** Description cback requesting authorization +** +** Returns void +** +*******************************************************************************/ +static UINT8 bta_dm_authorize_cback (BD_ADDR bd_addr, DEV_CLASS dev_class, BD_NAME bd_name, + UINT8 *service_name, UINT8 service_id, BOOLEAN is_originator) +{ + tBTA_DM_SEC sec_event; + UINT8 index = 1; + UNUSED(service_name); + UNUSED(is_originator); + + bdcpy(sec_event.authorize.bd_addr, bd_addr); + memcpy(sec_event.authorize.dev_class, dev_class, DEV_CLASS_LEN); + + BCM_STRNCPY_S((char*)sec_event.authorize.bd_name, sizeof(BD_NAME), (char*)bd_name, (BD_NAME_LEN-1)); + + /* make sure the string is null terminated */ + sec_event.authorize.bd_name[BD_NAME_LEN-1] = 0; + +#if ( defined(BTA_JV_INCLUDED) && BTA_JV_INCLUDED == TRUE ) + sec_event.authorize.service = service_id; +#endif + + while(index < BTA_MAX_SERVICE_ID) + { + /* get the BTA service id corresponding to BTM id */ + if(bta_service_id_to_btm_srv_id_lkup_tbl[index] == service_id) + { + sec_event.authorize.service = index; + break; + } + index++; + } + + + /* if supported service callback otherwise not authorized */ + if(bta_dm_cb.p_sec_cback && (index < BTA_MAX_SERVICE_ID +#if ( defined(BTA_JV_INCLUDED) && BTA_JV_INCLUDED == TRUE ) + /* pass through JV service ID */ + || (service_id >= BTA_FIRST_JV_SERVICE_ID && service_id <= BTA_LAST_JV_SERVICE_ID) +#endif + )) + { + bta_dm_cb.p_sec_cback(BTA_DM_AUTHORIZE_EVT, &sec_event); + return BTM_CMD_STARTED; + } + else + { + return BTM_NOT_AUTHORIZED; + } +} + + + + + +/******************************************************************************* +** +** Function bta_dm_pinname_cback +** +** Description Callback requesting pin_key +** +** Returns void +** +*******************************************************************************/ +static void bta_dm_pinname_cback (void *p_data) +{ + tBTM_REMOTE_DEV_NAME *p_result = (tBTM_REMOTE_DEV_NAME *)p_data; + tBTA_DM_SEC sec_event; + UINT32 bytes_to_copy; + tBTA_DM_SEC_EVT event = bta_dm_cb.pin_evt; + + if (BTA_DM_SP_CFM_REQ_EVT == event) + { + /* Retrieved saved device class and bd_addr */ + bdcpy(sec_event.cfm_req.bd_addr, bta_dm_cb.pin_bd_addr); + BTA_COPY_DEVICE_CLASS(sec_event.cfm_req.dev_class, bta_dm_cb.pin_dev_class); + + if (p_result && p_result->status == BTM_SUCCESS) + { + bytes_to_copy = (p_result->length < (BD_NAME_LEN-1)) + ? p_result->length : (BD_NAME_LEN-1); + memcpy(sec_event.cfm_req.bd_name, p_result->remote_bd_name, bytes_to_copy); + sec_event.pin_req.bd_name[BD_NAME_LEN-1] = 0; + } + else /* No name found */ + sec_event.cfm_req.bd_name[0] = 0; + + sec_event.key_notif.passkey = bta_dm_cb.num_val; /* get PIN code numeric number */ + + /* 1 additional event data fields for this event */ + sec_event.cfm_req.just_works = bta_dm_cb.just_works; + } + else + { + /* Retrieved saved device class and bd_addr */ + bdcpy(sec_event.pin_req.bd_addr, bta_dm_cb.pin_bd_addr); + BTA_COPY_DEVICE_CLASS(sec_event.pin_req.dev_class, bta_dm_cb.pin_dev_class); + + if (p_result && p_result->status == BTM_SUCCESS) + { + bytes_to_copy = (p_result->length < (BD_NAME_LEN-1)) + ? p_result->length : (BD_NAME_LEN-1); + memcpy(sec_event.pin_req.bd_name, p_result->remote_bd_name, bytes_to_copy); + sec_event.pin_req.bd_name[BD_NAME_LEN-1] = 0; + } + else /* No name found */ + sec_event.pin_req.bd_name[0] = 0; + + event = bta_dm_cb.pin_evt; + sec_event.key_notif.passkey = bta_dm_cb.num_val; /* get PIN code numeric number */ + } + + if( bta_dm_cb.p_sec_cback ) + bta_dm_cb.p_sec_cback(event, &sec_event); +} + +/******************************************************************************* +** +** Function bta_dm_pin_cback +** +** Description Callback requesting pin_key +** +** Returns void +** +*******************************************************************************/ +static UINT8 bta_dm_pin_cback (BD_ADDR bd_addr, DEV_CLASS dev_class, BD_NAME bd_name, + BOOLEAN min_16_digit) +{ + tBTA_DM_SEC sec_event; + + if (!bta_dm_cb.p_sec_cback) + return BTM_NOT_AUTHORIZED; + + /* If the device name is not known, save bdaddr and devclass and initiate a name request */ + if (bd_name[0] == 0) + { + bta_dm_cb.pin_evt = BTA_DM_PIN_REQ_EVT; + bdcpy(bta_dm_cb.pin_bd_addr, bd_addr); + BTA_COPY_DEVICE_CLASS(bta_dm_cb.pin_dev_class, dev_class); + if ((BTM_ReadRemoteDeviceName(bd_addr, bta_dm_pinname_cback, BT_TRANSPORT_BR_EDR)) == BTM_CMD_STARTED) + return BTM_CMD_STARTED; + + APPL_TRACE_WARNING(" bta_dm_pin_cback() -> Failed to start Remote Name Request "); + } + + bdcpy(sec_event.pin_req.bd_addr, bd_addr); + BTA_COPY_DEVICE_CLASS(sec_event.pin_req.dev_class, dev_class); + BCM_STRNCPY_S((char*)sec_event.pin_req.bd_name, sizeof(BD_NAME), (char*)bd_name, (BD_NAME_LEN-1)); + sec_event.pin_req.bd_name[BD_NAME_LEN-1] = 0; + sec_event.pin_req.min_16_digit = min_16_digit; + + bta_dm_cb.p_sec_cback(BTA_DM_PIN_REQ_EVT, &sec_event); + return BTM_CMD_STARTED; +} + +/******************************************************************************* +** +** Function bta_dm_new_link_key_cback +** +** Description Callback from BTM to notify new link key +** +** Returns void +** +*******************************************************************************/ +static UINT8 bta_dm_new_link_key_cback(BD_ADDR bd_addr, DEV_CLASS dev_class, + BD_NAME bd_name, LINK_KEY key, UINT8 key_type) +{ + tBTA_DM_SEC sec_event; + tBTA_DM_AUTH_CMPL *p_auth_cmpl; + UINT8 event; + UNUSED(dev_class); + + memset (&sec_event, 0, sizeof(tBTA_DM_SEC)); + + /* Not AMP Key type */ + if (key_type != HCI_LKEY_TYPE_AMP_WIFI && key_type != HCI_LKEY_TYPE_AMP_UWB) + { + event = BTA_DM_AUTH_CMPL_EVT; + p_auth_cmpl = &sec_event.auth_cmpl; + + bdcpy(p_auth_cmpl->bd_addr, bd_addr); + + memcpy(p_auth_cmpl->bd_name, bd_name, (BD_NAME_LEN-1)); + p_auth_cmpl->bd_name[BD_NAME_LEN-1] = 0; + + p_auth_cmpl->key_present = TRUE; + p_auth_cmpl->key_type = key_type; + p_auth_cmpl->success = TRUE; + + memcpy(p_auth_cmpl->key, key, LINK_KEY_LEN); + sec_event.auth_cmpl.fail_reason = HCI_SUCCESS; + +#if BLE_INCLUDED == TRUE + // Report the BR link key based on the BR/EDR address and type + BTM_ReadDevInfo(bd_addr, &sec_event.auth_cmpl.dev_type, &sec_event.auth_cmpl.addr_type); +#endif + if(bta_dm_cb.p_sec_cback) + bta_dm_cb.p_sec_cback(event, &sec_event); + } + else + { + APPL_TRACE_WARNING("%s() Received AMP Key", __func__); + } + + return BTM_CMD_STARTED; +} + + +/******************************************************************************* +** +** Function bta_dm_authentication_complete_cback +** +** Description Authentication complete callback from BTM +** +** Returns void +** +*******************************************************************************/ +static UINT8 bta_dm_authentication_complete_cback(BD_ADDR bd_addr, DEV_CLASS dev_class,BD_NAME bd_name, int result) +{ + tBTA_DM_SEC sec_event; + UNUSED(dev_class); + + if(result != BTM_SUCCESS) + { + memset(&sec_event, 0, sizeof(tBTA_DM_SEC)); + bdcpy(sec_event.auth_cmpl.bd_addr, bd_addr); + + memcpy(sec_event.auth_cmpl.bd_name, bd_name, (BD_NAME_LEN-1)); + sec_event.auth_cmpl.bd_name[BD_NAME_LEN-1] = 0; + +#if BLE_INCLUDED == TRUE + // Report the BR link key based on the BR/EDR address and type + BTM_ReadDevInfo(bd_addr, &sec_event.auth_cmpl.dev_type, &sec_event.auth_cmpl.addr_type); +#endif + sec_event.auth_cmpl.fail_reason = (UINT8)result; + + if(bta_dm_cb.p_sec_cback) + bta_dm_cb.p_sec_cback(BTA_DM_AUTH_CMPL_EVT, &sec_event); + + bta_dm_remove_sec_dev_entry(bd_addr); + } + + return BTM_SUCCESS; +} + +/******************************************************************************* +** +** Function bta_dm_sp_cback +** +** Description simple pairing callback from BTM +** +** Returns void +** +*******************************************************************************/ +static UINT8 bta_dm_sp_cback (tBTM_SP_EVT event, tBTM_SP_EVT_DATA *p_data) +{ + tBTM_STATUS status = BTM_CMD_STARTED; + tBTA_DM_SEC sec_event; + tBTA_DM_SEC_EVT pin_evt = BTA_DM_SP_KEY_NOTIF_EVT; + + APPL_TRACE_EVENT("bta_dm_sp_cback: %d", event); + if (!bta_dm_cb.p_sec_cback) + return BTM_NOT_AUTHORIZED; + + /* TODO_SP */ + switch(event) + { + case BTM_SP_IO_REQ_EVT: +#if (BTM_LOCAL_IO_CAPS != BTM_IO_CAP_NONE) + /* translate auth_req */ + bta_dm_co_io_req(p_data->io_req.bd_addr, &p_data->io_req.io_cap, + &p_data->io_req.oob_data, &p_data->io_req.auth_req, p_data->io_req.is_orig); +#endif +#if BTM_OOB_INCLUDED == FALSE + status = BTM_SUCCESS; +#endif + + APPL_TRACE_EVENT("io mitm: %d oob_data:%d", p_data->io_req.auth_req, p_data->io_req.oob_data); + break; + case BTM_SP_IO_RSP_EVT: +#if (BTM_LOCAL_IO_CAPS != BTM_IO_CAP_NONE) + bta_dm_co_io_rsp(p_data->io_rsp.bd_addr, p_data->io_rsp.io_cap, + p_data->io_rsp.oob_data, p_data->io_rsp.auth_req ); +#endif + break; + + case BTM_SP_CFM_REQ_EVT: + pin_evt = BTA_DM_SP_CFM_REQ_EVT; + bta_dm_cb.just_works = sec_event.cfm_req.just_works = p_data->cfm_req.just_works; + sec_event.cfm_req.loc_auth_req = p_data->cfm_req.loc_auth_req; + sec_event.cfm_req.rmt_auth_req = p_data->cfm_req.rmt_auth_req; + sec_event.cfm_req.loc_io_caps = p_data->cfm_req.loc_io_caps; + sec_event.cfm_req.rmt_io_caps = p_data->cfm_req.rmt_io_caps; + + /* continue to next case */ +#if (BTM_LOCAL_IO_CAPS != BTM_IO_CAP_NONE) + /* Passkey entry mode, mobile device with output capability is very + unlikely to receive key request, so skip this event */ + /*case BTM_SP_KEY_REQ_EVT: */ + case BTM_SP_KEY_NOTIF_EVT: +#endif + if(BTM_SP_CFM_REQ_EVT == event) + { + /* Due to the switch case falling through below to BTM_SP_KEY_NOTIF_EVT, + call remote name request using values from cfm_req */ + if(p_data->cfm_req.bd_name[0] == 0) + { + bta_dm_cb.pin_evt = pin_evt; + bdcpy(bta_dm_cb.pin_bd_addr, p_data->cfm_req.bd_addr); + BTA_COPY_DEVICE_CLASS(bta_dm_cb.pin_dev_class, p_data->cfm_req.dev_class); + if ((BTM_ReadRemoteDeviceName(p_data->cfm_req.bd_addr, bta_dm_pinname_cback, + BT_TRANSPORT_BR_EDR)) == BTM_CMD_STARTED) + return BTM_CMD_STARTED; + APPL_TRACE_WARNING(" bta_dm_sp_cback() -> Failed to start Remote Name Request "); + } + else + { + /* Due to the switch case falling through below to BTM_SP_KEY_NOTIF_EVT, + copy these values into key_notif from cfm_req */ + bdcpy(sec_event.key_notif.bd_addr, p_data->cfm_req.bd_addr); + BTA_COPY_DEVICE_CLASS(sec_event.key_notif.dev_class, p_data->cfm_req.dev_class); + BCM_STRNCPY_S((char*)sec_event.key_notif.bd_name, sizeof(BD_NAME), + (char*)p_data->cfm_req.bd_name, (BD_NAME_LEN-1)); + sec_event.key_notif.bd_name[BD_NAME_LEN-1] = 0; + } + } + + bta_dm_cb.num_val = sec_event.key_notif.passkey = p_data->key_notif.passkey; + if (BTM_SP_KEY_NOTIF_EVT == event) + { + /* If the device name is not known, save bdaddr and devclass + and initiate a name request with values from key_notif */ + if(p_data->key_notif.bd_name[0] == 0) + { + bta_dm_cb.pin_evt = pin_evt; + bdcpy(bta_dm_cb.pin_bd_addr, p_data->key_notif.bd_addr); + BTA_COPY_DEVICE_CLASS(bta_dm_cb.pin_dev_class, p_data->key_notif.dev_class); + if ((BTM_ReadRemoteDeviceName(p_data->key_notif.bd_addr, bta_dm_pinname_cback, + BT_TRANSPORT_BR_EDR)) == BTM_CMD_STARTED) + return BTM_CMD_STARTED; + APPL_TRACE_WARNING(" bta_dm_sp_cback() -> Failed to start Remote Name Request "); + } + else + { + bdcpy(sec_event.key_notif.bd_addr, p_data->key_notif.bd_addr); + BTA_COPY_DEVICE_CLASS(sec_event.key_notif.dev_class, p_data->key_notif.dev_class); + BCM_STRNCPY_S((char*)sec_event.key_notif.bd_name, sizeof(BD_NAME), + (char*)p_data->key_notif.bd_name, (BD_NAME_LEN-1)); + sec_event.key_notif.bd_name[BD_NAME_LEN-1] = 0; + } + } + + bta_dm_cb.p_sec_cback(pin_evt, &sec_event); + + break; + +#if BTM_OOB_INCLUDED == TRUE + case BTM_SP_LOC_OOB_EVT: + bta_dm_co_loc_oob((BOOLEAN)(p_data->loc_oob.status == BTM_SUCCESS), + p_data->loc_oob.c, p_data->loc_oob.r); + break; + + case BTM_SP_RMT_OOB_EVT: + /* If the device name is not known, save bdaddr and devclass and initiate a name request */ + if (p_data->rmt_oob.bd_name[0] == 0) + { + bta_dm_cb.pin_evt = BTA_DM_SP_RMT_OOB_EVT; + bdcpy(bta_dm_cb.pin_bd_addr, p_data->rmt_oob.bd_addr); + BTA_COPY_DEVICE_CLASS(bta_dm_cb.pin_dev_class, p_data->rmt_oob.dev_class); + if ((BTM_ReadRemoteDeviceName(p_data->rmt_oob.bd_addr, bta_dm_pinname_cback, + BT_TRANSPORT_BR_EDR)) == BTM_CMD_STARTED) + return BTM_CMD_STARTED; + APPL_TRACE_WARNING(" bta_dm_sp_cback() -> Failed to start Remote Name Request "); + } + + bdcpy(sec_event.rmt_oob.bd_addr, p_data->rmt_oob.bd_addr); + BTA_COPY_DEVICE_CLASS(sec_event.rmt_oob.dev_class, p_data->rmt_oob.dev_class); + BCM_STRNCPY_S((char*)sec_event.rmt_oob.bd_name, sizeof(BD_NAME), (char*)p_data->rmt_oob.bd_name, (BD_NAME_LEN-1)); + sec_event.rmt_oob.bd_name[BD_NAME_LEN-1] = 0; + + bta_dm_cb.p_sec_cback(BTA_DM_SP_RMT_OOB_EVT, &sec_event); + + bta_dm_co_rmt_oob(p_data->rmt_oob.bd_addr); + break; +#endif + case BTM_SP_COMPLT_EVT: + /* do not report this event - handled by link_key_callback or auth_complete_callback */ + break; + + case BTM_SP_KEYPRESS_EVT: + memcpy(&sec_event.key_press, &p_data->key_press, sizeof(tBTM_SP_KEYPRESS)); + bta_dm_cb.p_sec_cback(BTA_DM_SP_KEYPRESS_EVT, &sec_event); + break; + + case BTM_SP_UPGRADE_EVT: + bta_dm_co_lk_upgrade(p_data->upgrade.bd_addr, &p_data->upgrade.upgrade ); + break; + + default: + status = BTM_NOT_AUTHORIZED; + break; + } + APPL_TRACE_EVENT("dm status: %d", status); + return status; +} + +/******************************************************************************* +** +** Function bta_dm_local_name_cback +** +** Description Callback from btm after local name is read +** +** +** Returns void +** +*******************************************************************************/ +static void bta_dm_local_name_cback(UINT8 *p_name) +{ + tBTA_DM_SEC sec_event; + UNUSED(p_name); + + sec_event.enable.status = BTA_SUCCESS; + + if(bta_dm_cb.p_sec_cback) + bta_dm_cb.p_sec_cback(BTA_DM_ENABLE_EVT, &sec_event); + +} + +/******************************************************************************* +** +** Function bta_dm_bl_change_cback +** +** Description Callback from btm when acl connection goes up or down +** +** +** Returns void +** +*******************************************************************************/ +static void bta_dm_bl_change_cback (tBTM_BL_EVENT_DATA *p_data) +{ + tBTA_DM_ACL_CHANGE * p_msg; + + if ((p_msg = (tBTA_DM_ACL_CHANGE *) GKI_getbuf(sizeof(tBTA_DM_ACL_CHANGE))) != NULL) + { + p_msg->event = p_data->event; + p_msg->is_new = FALSE; + + switch(p_msg->event) + { + case BTM_BL_CONN_EVT: + p_msg->is_new = TRUE; + bdcpy(p_msg->bd_addr, p_data->conn.p_bda); +#if BLE_INCLUDED == TRUE + p_msg->transport = p_data->conn.transport; + p_msg->handle = p_data->conn.handle; +#endif + break; + case BTM_BL_DISCN_EVT: + bdcpy(p_msg->bd_addr, p_data->discn.p_bda); +#if BLE_INCLUDED == TRUE + p_msg->transport = p_data->discn.transport; + p_msg->handle = p_data->discn.handle; +#endif + break; + case BTM_BL_UPDATE_EVT: + p_msg->busy_level = p_data->update.busy_level; + p_msg->busy_level_flags = p_data->update.busy_level_flags; + break; + case BTM_BL_ROLE_CHG_EVT: + p_msg->new_role = p_data->role_chg.new_role; + p_msg->hci_status = p_data->role_chg.hci_status; + bdcpy(p_msg->bd_addr, p_data->role_chg.p_bda); + break; + case BTM_BL_COLLISION_EVT: + bdcpy(p_msg->bd_addr, p_data->conn.p_bda); + break; + } + + p_msg->hdr.event = BTA_DM_ACL_CHANGE_EVT; + bta_sys_sendmsg(p_msg); + + } + +} + +/******************************************************************************* +** +** Function bta_dm_acl_change_cback +** +** Description Callback from btm when acl connection goes up or down +** +** +** Returns void +** +*******************************************************************************/ +#if BLE_INCLUDED == TRUE +static void bta_dm_acl_change_cback(BD_ADDR p_bda, DEV_CLASS p_dc, BD_NAME p_bdn, + UINT8 *features, BOOLEAN is_new,UINT16 handle, + tBT_TRANSPORT transport) +#else +static void bta_dm_acl_change_cback(BD_ADDR p_bda, DEV_CLASS p_dc, BD_NAME p_bdn, + UINT8 *features, BOOLEAN is_new) +#endif +{ + tBTA_DM_ACL_CHANGE *p_msg = (tBTA_DM_ACL_CHANGE *) GKI_getbuf(sizeof(tBTA_DM_ACL_CHANGE)); + if (p_msg != NULL) + { + memset(p_msg, 0, sizeof(tBTA_DM_ACL_CHANGE)); + + bdcpy(p_msg->bd_addr, p_bda); + p_msg->is_new = is_new; +#if BLE_INCLUDED == TRUE + p_msg->handle = handle; + p_msg->transport = transport; +#endif + /* This is collision case */ + if (features != NULL) + { + if ((features[0] == 0xFF) && !is_new) + p_msg->event = BTM_BL_COLLISION_EVT; + } + + p_msg->hdr.event = BTA_DM_ACL_CHANGE_EVT; + bta_sys_sendmsg(p_msg); + } +} + + +/******************************************************************************* +** +** Function bta_dm_rs_cback +** +** Description Receives the role switch complete event +** +** Returns +** +*******************************************************************************/ +static void bta_dm_rs_cback (tBTM_ROLE_SWITCH_CMPL *p1) +{ + UNUSED(p1); + APPL_TRACE_WARNING("bta_dm_rs_cback:%d", bta_dm_cb.rs_event); + if(bta_dm_cb.rs_event == BTA_DM_API_SEARCH_EVT) + { + bta_dm_cb.search_msg.rs_res = BTA_DM_RS_OK; /* do not care about the result for now */ + bta_dm_cb.rs_event = 0; + bta_dm_search_start((tBTA_DM_MSG *)&bta_dm_cb.search_msg); + } +} + +/******************************************************************************* +** +** Function bta_dm_check_av +** +** Description This function checks if AV is active +** if yes, make sure the AV link is master +** +** Returns BOOLEAN - TRUE, if switch is in progress +** +*******************************************************************************/ +static BOOLEAN bta_dm_check_av(UINT16 event) +{ + BOOLEAN avoid_roleswitch = FALSE; + BOOLEAN switching = FALSE; + UINT8 i; + tBTA_DM_PEER_DEVICE *p_dev; + +#if defined(BTA_DM_AVOID_A2DP_ROLESWITCH_ON_INQUIRY) && (BTA_DM_AVOID_A2DP_ROLESWITCH_ON_INQUIRY == TRUE) + + /* avoid role switch upon inquiry if a2dp is actively streaming as it + introduces an audioglitch due to FW scheduling delays (unavoidable) */ + if (event == BTA_DM_API_SEARCH_EVT) + { + avoid_roleswitch = TRUE; + } +#endif + + APPL_TRACE_WARNING("bta_dm_check_av:%d", bta_dm_cb.cur_av_count); + if(bta_dm_cb.cur_av_count) + { + for(i=0; iconn_state, p_dev->info, avoid_roleswitch); + if((p_dev->conn_state == BTA_DM_CONNECTED) && (p_dev->info & BTA_DM_DI_AV_ACTIVE) && + (avoid_roleswitch == FALSE)) + { + /* make master and take away the role switch policy */ + if(BTM_CMD_STARTED == BTM_SwitchRole (p_dev->peer_bdaddr, HCI_ROLE_MASTER, (tBTM_CMPL_CB *)bta_dm_rs_cback)) + { + /* the role switch command is actually sent */ + bta_dm_cb.rs_event = event; + switching = TRUE; + } + /* else either already master or can not switch for some reasons */ + bta_dm_policy_cback(BTA_SYS_PLCY_CLR, 0, HCI_ENABLE_MASTER_SLAVE_SWITCH, p_dev->peer_bdaddr); + break; + } + } + } + return switching; +} + +/******************************************************************************* +** +** Function bta_dm_acl_change +** +** Description Process BTA_DM_ACL_CHANGE_EVT +** +** +** Returns void +** +*******************************************************************************/ +void bta_dm_acl_change(tBTA_DM_MSG *p_data) +{ + + UINT8 i; + UINT8 *p; + tBTA_DM_SEC conn; + BOOLEAN is_new = p_data->acl_change.is_new; + BD_ADDR_PTR p_bda = p_data->acl_change.bd_addr; + BOOLEAN need_policy_change = FALSE; + BOOLEAN issue_unpair_cb = FALSE; + + tBTA_DM_PEER_DEVICE *p_dev; + memset(&conn, 0, sizeof(tBTA_DM_SEC)); + + switch(p_data->acl_change.event) + { + case BTM_BL_UPDATE_EVT: /* busy level update */ + if( bta_dm_cb.p_sec_cback ) + { + conn.busy_level.level = p_data->acl_change.busy_level; + conn.busy_level.level_flags = p_data->acl_change.busy_level_flags; + bta_dm_cb.p_sec_cback(BTA_DM_BUSY_LEVEL_EVT, &conn); + } + return; + + case BTM_BL_ROLE_CHG_EVT: /* role change event */ + p_dev = bta_dm_find_peer_device(p_bda); + if(p_dev) + { + APPL_TRACE_DEBUG("bta_dm_acl_change role chg info:x%x new_role:%d dev count:%d", + p_dev->info, p_data->acl_change.new_role, bta_dm_cb.device_list.count); + if(p_dev->info & BTA_DM_DI_AV_ACTIVE) + { + /* there's AV activity on this link */ + if(p_data->acl_change.new_role == HCI_ROLE_SLAVE && bta_dm_cb.device_list.count > 1 + && p_data->acl_change.hci_status == HCI_SUCCESS) + { + /* more than one connections and the AV connection is role switched to slave + * switch it back to master and remove the switch policy */ + BTM_SwitchRole(p_bda, BTM_ROLE_MASTER, NULL); + need_policy_change = TRUE; + } + else if (p_bta_dm_cfg->avoid_scatter && (p_data->acl_change.new_role == HCI_ROLE_MASTER)) + { + /* if the link updated to be master include AV activities, remove the switch policy */ + need_policy_change = TRUE; + } + + if(need_policy_change) + { + bta_dm_policy_cback(BTA_SYS_PLCY_CLR, 0, HCI_ENABLE_MASTER_SLAVE_SWITCH, p_dev->peer_bdaddr); + } + } + else + { + /* there's AV no activity on this link and role switch happened + * check if AV is active + * if so, make sure the AV link is master */ + bta_dm_check_av(0); + } + bta_sys_notify_role_chg(p_data->acl_change.bd_addr, p_data->acl_change.new_role, p_data->acl_change.hci_status); + bdcpy(conn.role_chg.bd_addr, p_bda); + conn.role_chg.new_role = (UINT8) p_data->acl_change.new_role; + if( bta_dm_cb.p_sec_cback ) + bta_dm_cb.p_sec_cback(BTA_DM_ROLE_CHG_EVT, (tBTA_DM_SEC *)&conn); + } + return; + } + + /* Collision report from Stack: Notify profiles */ + if (p_data->acl_change.event == BTM_BL_COLLISION_EVT) + { + bta_sys_notify_collision (p_bda); + return; + } + + if(is_new) + { + for(i=0; iacl_change.handle +#endif + ) + break; + + } + + if(i == bta_dm_cb.device_list.count) + { + if (bta_dm_cb.device_list.count < BTA_DM_NUM_PEER_DEVICE) + { + bdcpy(bta_dm_cb.device_list.peer_device[bta_dm_cb.device_list.count].peer_bdaddr, p_bda); + bta_dm_cb.device_list.peer_device[bta_dm_cb.device_list.count].link_policy = bta_dm_cb.cur_policy; + bta_dm_cb.device_list.count++; +#if BLE_INCLUDED == TRUE + bta_dm_cb.device_list.peer_device[i].conn_handle = p_data->acl_change.handle; + if (p_data->acl_change.transport == BT_TRANSPORT_LE) + bta_dm_cb.device_list.le_count++; +#endif + } else { + APPL_TRACE_ERROR("%s max active connection reached, no resources", __func__); + return; + } + } + + bta_dm_cb.device_list.peer_device[i].conn_state = BTA_DM_CONNECTED; + bta_dm_cb.device_list.peer_device[i].pref_role = BTA_ANY_ROLE; + bdcpy(conn.link_up.bd_addr, p_bda); + bta_dm_cb.device_list.peer_device[i].info = BTA_DM_DI_NONE; +#if BLE_INCLUDED == TRUE + conn.link_up.link_type = p_data->acl_change.transport; + bta_dm_cb.device_list.peer_device[i].transport = p_data->acl_change.transport; +#endif + + if (((NULL != (p = BTM_ReadLocalFeatures ())) && HCI_SNIFF_SUB_RATE_SUPPORTED(p)) && + ((NULL != (p = BTM_ReadRemoteFeatures (p_bda))) && HCI_SNIFF_SUB_RATE_SUPPORTED(p))) + { + /* both local and remote devices support SSR */ + bta_dm_cb.device_list.peer_device[i].info = BTA_DM_DI_USE_SSR; + } + APPL_TRACE_WARNING("%s info: 0x%x", __func__, bta_dm_cb.device_list.peer_device[i].info); + + if (bta_dm_cb.p_sec_cback) + bta_dm_cb.p_sec_cback(BTA_DM_LINK_UP_EVT, (tBTA_DM_SEC *)&conn); + } else { + for(i=0; iacl_change.transport +#endif + ) + continue; + + if( bta_dm_cb.device_list.peer_device[i].conn_state == BTA_DM_UNPAIRING ) + { + if (BTM_SecDeleteDevice(bta_dm_cb.device_list.peer_device[i].peer_bdaddr)) + issue_unpair_cb = TRUE; + + APPL_TRACE_DEBUG("%s: Unpairing: issue unpair CB = %d ",__FUNCTION__, issue_unpair_cb); + } + + conn.link_down.is_removed = bta_dm_cb.device_list.peer_device[i].remove_dev_pending; + + for(; iacl_change.transport == BT_TRANSPORT_LE) && + (bta_dm_cb.device_list.le_count)) + bta_dm_cb.device_list.le_count--; + conn.link_down.link_type = p_data->acl_change.transport; +#endif + + if(bta_dm_search_cb.wait_disc && !bdcmp(bta_dm_search_cb.peer_bdaddr, p_bda)) + { + bta_dm_search_cb.wait_disc = FALSE; + + if(bta_dm_search_cb.sdp_results) + { + APPL_TRACE_EVENT(" timer stopped "); + bta_sys_stop_timer(&bta_dm_search_cb.search_timer); + bta_dm_discover_next_device(); + } + + } + + if(bta_dm_cb.disabling) + { + if(!BTM_GetNumAclLinks()) + { + bta_sys_stop_timer(&bta_dm_cb.disable_timer); + bta_dm_cb.disable_timer.p_cback = (TIMER_CBACK*)&bta_dm_disable_conn_down_timer_cback; + /* + * Start a timer to make sure that the profiles + * get the disconnect event. + */ + bta_sys_start_timer(&bta_dm_cb.disable_timer, 0, 1000); + } + } + if (conn.link_down.is_removed) + { + BTM_SecDeleteDevice(p_bda); +#if (BLE_INCLUDED == TRUE && BTA_GATT_INCLUDED == TRUE) + /* need to remove all pending background connection */ + BTA_GATTC_CancelOpen(0, p_bda, FALSE); + /* remove all cached GATT information */ + BTA_GATTC_Refresh(p_bda); +#endif + } + + bdcpy(conn.link_down.bd_addr, p_bda); + conn.link_down.status = (UINT8) btm_get_acl_disc_reason_code(); + if( bta_dm_cb.p_sec_cback ) + { + bta_dm_cb.p_sec_cback(BTA_DM_LINK_DOWN_EVT, &conn); + if( issue_unpair_cb ) + bta_dm_cb.p_sec_cback(BTA_DM_DEV_UNPAIRED_EVT, &conn); + } + } + + bta_dm_adjust_roles(TRUE); +} + +/******************************************************************************* +** +** Function bta_dm_disable_conn_down_timer_cback +** +** Description Sends disable event to application +** +** +** Returns void +** +*******************************************************************************/ +static void bta_dm_disable_conn_down_timer_cback (TIMER_LIST_ENT *p_tle) +{ + UNUSED(p_tle); + tBTA_SYS_HW_MSG *sys_enable_event; + + /* disable the power managment module */ + bta_dm_disable_pm(); + + /* register our callback to SYS HW manager */ + bta_sys_hw_register( BTA_SYS_HW_BLUETOOTH, bta_dm_sys_hw_cback ); + + /* send a message to BTA SYS */ + if ((sys_enable_event = (tBTA_SYS_HW_MSG *) GKI_getbuf(sizeof(tBTA_SYS_HW_MSG))) != NULL) + { + sys_enable_event->hdr.event = BTA_SYS_API_DISABLE_EVT; + sys_enable_event->hw_module = BTA_SYS_HW_BLUETOOTH; + bta_sys_sendmsg(sys_enable_event); + } + + bta_dm_cb.disabling = FALSE; + +} + +/******************************************************************************* +** +** Function bta_dm_rm_cback +** +** Description Role management callback from sys +** +** +** Returns void +** +*******************************************************************************/ +static void bta_dm_rm_cback(tBTA_SYS_CONN_STATUS status, UINT8 id, UINT8 app_id, BD_ADDR peer_addr) +{ + UINT8 j; + tBTA_PREF_ROLES role; + tBTA_DM_PEER_DEVICE *p_dev; + + p_dev = bta_dm_find_peer_device(peer_addr); + if( status == BTA_SYS_CONN_OPEN) + { + if(p_dev) + { + /* Do not set to connected if we are in the middle of unpairing. When AV stream is + * started it fakes out a SYS_CONN_OPEN to potentially trigger a role switch command. + * But this should not be done if we are in the middle of unpairing. + */ + if (p_dev->conn_state != BTA_DM_UNPAIRING) + p_dev->conn_state = BTA_DM_CONNECTED; + + for(j=1; j<= p_bta_dm_rm_cfg[0].app_id; j++) + { + if(((p_bta_dm_rm_cfg[j].app_id == app_id) || (p_bta_dm_rm_cfg[j].app_id == BTA_ALL_APP_ID)) + && (p_bta_dm_rm_cfg[j].id == id)) + { + role = p_bta_dm_rm_cfg[j].cfg; + + if(role > p_dev->pref_role ) + p_dev->pref_role = role; + break; + } + } + } + } + + if((BTA_ID_AV == id)||(BTA_ID_AVK ==id)) + { + if( status == BTA_SYS_CONN_BUSY) + { + if(p_dev) + p_dev->info |= BTA_DM_DI_AV_ACTIVE; + /* AV calls bta_sys_conn_open with the A2DP stream count as app_id */ + if(BTA_ID_AV == id) + bta_dm_cb.cur_av_count = bta_dm_get_av_count(); + } + else if( status == BTA_SYS_CONN_IDLE) + { + if(p_dev) + p_dev->info &= ~BTA_DM_DI_AV_ACTIVE; + + /* get cur_av_count from connected services */ + if(BTA_ID_AV == id) + bta_dm_cb.cur_av_count = bta_dm_get_av_count(); + } + APPL_TRACE_WARNING("bta_dm_rm_cback:%d, status:%d", bta_dm_cb.cur_av_count, status); + } + + /* Don't adjust roles for each busy/idle state transition to avoid + excessive switch requests when individual profile busy/idle status + changes */ + if ((status != BTA_SYS_CONN_BUSY) && (status != BTA_SYS_CONN_IDLE)) + bta_dm_adjust_roles(FALSE); +} + +/******************************************************************************* +** +** Function bta_dm_delay_role_switch_cback +** +** Description Callback from btm to delay a role switch +** +** Returns void +** +*******************************************************************************/ +static void bta_dm_delay_role_switch_cback(TIMER_LIST_ENT *p_tle) +{ + UNUSED(p_tle); + APPL_TRACE_EVENT("bta_dm_delay_role_switch_cback: initiating Delayed RS"); + bta_dm_adjust_roles (FALSE); +} + +/******************************************************************************* +** +** Function bta_dm_remove_sec_dev_entry +** +** Description Removes device entry from Security device DB if ACL connection with +** remtoe device does not exist, else schedule for dev entry removal upon + ACL close +** +** Returns void +** +*******************************************************************************/ +static void bta_dm_remove_sec_dev_entry(BD_ADDR remote_bd_addr) +{ + UINT16 index = 0; + if ( BTM_IsAclConnectionUp(remote_bd_addr, BT_TRANSPORT_LE) || + BTM_IsAclConnectionUp(remote_bd_addr, BT_TRANSPORT_BR_EDR)) + { + APPL_TRACE_DEBUG("%s ACL is not down. Schedule for Dev Removal when ACL closes", + __FUNCTION__); + for (index = 0; index < bta_dm_cb.device_list.count; index ++) + { + if (!bdcmp( bta_dm_cb.device_list.peer_device[index].peer_bdaddr, remote_bd_addr)) + break; + } + if (index != bta_dm_cb.device_list.count) + { + bta_dm_cb.device_list.peer_device[index].remove_dev_pending = TRUE; + } + else + { + APPL_TRACE_ERROR(" %s Device does not exist in DB", __FUNCTION__); + } + } + else + { + BTM_SecDeleteDevice (remote_bd_addr); +#if (BLE_INCLUDED == TRUE && BTA_GATT_INCLUDED == TRUE) + /* need to remove all pending background connection */ + BTA_GATTC_CancelOpen(0, remote_bd_addr, FALSE); + /* remove all cached GATT information */ + BTA_GATTC_Refresh(remote_bd_addr); +#endif + } +} + + +/******************************************************************************* +** +** Function bta_dm_adjust_roles +** +** Description Adjust roles +** +** +** Returns void +** +*******************************************************************************/ +static void bta_dm_adjust_roles(BOOLEAN delay_role_switch) +{ + + UINT8 i; + BOOLEAN set_master_role = FALSE; +#if BLE_INCLUDED == TRUE + UINT8 br_count = bta_dm_cb.device_list.count - bta_dm_cb.device_list.le_count; +#else + UINT8 br_count = bta_dm_cb.device_list.count; +#endif + if (br_count) + { + + /* the configuration is no scatternet + * or AV connection exists and there are more than one ACL link */ + if ( (p_bta_dm_rm_cfg[0].cfg == BTA_DM_NO_SCATTERNET) || + (bta_dm_cb.cur_av_count && br_count > 1) ) + { + + L2CA_SetDesireRole (HCI_ROLE_MASTER); + set_master_role = TRUE; + + } + + for(i=0; i 1)) + { + + /* Initiating immediate role switch with certain remote devices + has caused issues due to role switch colliding with link encryption setup and + causing encryption (and in turn the link) to fail . These device . Firmware + versions are stored in a blacklist and role switch with these devices are + delayed to avoid the collision with link encryption setup */ + + if (bta_dm_cb.device_list.peer_device[i].pref_role != BTA_SLAVE_ROLE_ONLY && + delay_role_switch == FALSE) + { + BTM_SwitchRole (bta_dm_cb.device_list.peer_device[i].peer_bdaddr, + HCI_ROLE_MASTER, NULL); + } + else + { + bta_dm_cb.switch_delay_timer.p_cback = + (TIMER_CBACK*)&bta_dm_delay_role_switch_cback; + bta_sys_start_timer(&bta_dm_cb.switch_delay_timer, 0, 500); + } + } + + } + } + + + if(!set_master_role) + { + + L2CA_SetDesireRole (L2CAP_DESIRED_LINK_ROLE); + + } + + } + else + { + L2CA_SetDesireRole (L2CAP_DESIRED_LINK_ROLE); + } + + +} + +/******************************************************************************* +** +** Function bta_dm_get_remname +** +** Description Returns a pointer to the remote name stored in the DM control +** block if it exists, or from the BTM memory. +** +** Returns char * - Pointer to the remote device name +*******************************************************************************/ +static char *bta_dm_get_remname(void) +{ + char *p_name = (char *)bta_dm_search_cb.peer_name; + char *p_temp; + + /* If the name isn't already stored, try retrieving from BTM */ + if (*p_name == '\0') + if ((p_temp = BTM_SecReadDevName(bta_dm_search_cb.peer_bdaddr)) != NULL) + p_name = p_temp; + + return p_name; +} + +/******************************************************************************* +** +** Function bta_dm_bond_cancel_complete_cback +** +** Description Authentication complete callback from BTM +** +** Returns void +** +*******************************************************************************/ +static void bta_dm_bond_cancel_complete_cback(tBTM_STATUS result) +{ + + tBTA_DM_SEC sec_event; + + if (result == BTM_SUCCESS) + sec_event.bond_cancel_cmpl.result = BTA_SUCCESS; + else + sec_event.bond_cancel_cmpl.result = BTA_FAILURE; + + if(bta_dm_cb.p_sec_cback) + { + bta_dm_cb.p_sec_cback(BTA_DM_BOND_CANCEL_CMPL_EVT, &sec_event); + } +} + +/******************************************************************************* +** +** Function bta_dm_set_eir +** +** Description This function creates EIR tagged data and writes it to controller. +** +** Returns None +** +*******************************************************************************/ +static void bta_dm_set_eir (char *local_name) +{ + BT_HDR *p_buf; + UINT8 *p; + UINT8 *p_length; +#if (BTA_EIR_CANNED_UUID_LIST != TRUE) + UINT8 *p_type; + UINT8 max_num_uuid; +#if (BTA_EIR_SERVER_NUM_CUSTOM_UUID > 0) + UINT8 custom_uuid_idx; +#endif // BTA_EIR_SERVER_NUM_CUSTOM_UUID +#endif // BTA_EIR_CANNED_UUID_LIST +#if (BTM_EIR_DEFAULT_FEC_REQUIRED == FALSE) + UINT8 free_eir_length = HCI_EXT_INQ_RESPONSE_LEN; +#else // BTM_EIR_DEFAULT_FEC_REQUIRED + UINT8 free_eir_length = HCI_DM5_PACKET_SIZE; +#endif // BTM_EIR_DEFAULT_FEC_REQUIRED + UINT8 num_uuid; + UINT8 data_type; + UINT8 local_name_len; + + /* wait until complete to disable */ + if (bta_dm_cb.disable_timer.in_use) + return; + +#if ( BTA_EIR_CANNED_UUID_LIST != TRUE ) + /* wait until App is ready */ + if (bta_dm_cb.app_ready_timer.in_use) + return; + + /* if local name is not provided, get it from controller */ + if( local_name == NULL ) + { + if( BTM_ReadLocalDeviceName( &local_name ) != BTM_SUCCESS ) + { + APPL_TRACE_ERROR("Fail to read local device name for EIR"); + } + } +#endif // BTA_EIR_CANNED_UUID_LIST + + /* Allocate a buffer to hold HCI command */ + if ((p_buf = (BT_HDR *)GKI_getpoolbuf(BTM_CMD_POOL_ID)) == NULL) + { + APPL_TRACE_ERROR("bta_dm_set_eir couldn't allocate buffer"); + return; + } + p = (UINT8 *)p_buf + BTM_HCI_EIR_OFFSET; + + memset(p, 0x00, HCI_EXT_INQ_RESPONSE_LEN ); + + APPL_TRACE_DEBUG("BTA is generating EIR"); + + if( local_name ) + local_name_len = strlen( local_name ); + else + local_name_len = 0; + + data_type = BTM_EIR_COMPLETE_LOCAL_NAME_TYPE; + /* if local name is longer than minimum length of shortened name */ + /* check whether it needs to be shortened or not */ + if( local_name_len > p_bta_dm_eir_cfg->bta_dm_eir_min_name_len ) + { + /* get number of UUID 16-bit list */ +#if (BTA_EIR_CANNED_UUID_LIST == TRUE) + num_uuid = p_bta_dm_eir_cfg->bta_dm_eir_uuid16_len/LEN_UUID_16; +#else // BTA_EIR_CANNED_UUID_LIST + max_num_uuid = (free_eir_length - 2)/LEN_UUID_16; + data_type = BTM_GetEirSupportedServices( bta_dm_cb.eir_uuid, &p, + max_num_uuid, &num_uuid ); + p = (UINT8 *)p_buf + BTM_HCI_EIR_OFFSET; /* reset p */ +#endif // BTA_EIR_CANNED_UUID_LIST + + /* if UUID doesn't fit remaing space, shorten local name */ + if ( local_name_len > (free_eir_length - 4 - num_uuid*LEN_UUID_16)) + { + APPL_TRACE_WARNING("BTA EIR: local name is shortened"); + local_name_len = p_bta_dm_eir_cfg->bta_dm_eir_min_name_len; + data_type = BTM_EIR_SHORTENED_LOCAL_NAME_TYPE; + } + else + data_type = BTM_EIR_COMPLETE_LOCAL_NAME_TYPE; + } + + UINT8_TO_STREAM(p, local_name_len + 1); + UINT8_TO_STREAM(p, data_type); + + if (local_name != NULL) + { + memcpy(p, local_name, local_name_len); + p += local_name_len; + } + free_eir_length -= local_name_len + 2; + +#if (BTA_EIR_CANNED_UUID_LIST == TRUE) + /* if UUID list is provided as static data in configuration */ + if(( p_bta_dm_eir_cfg->bta_dm_eir_uuid16_len > 0 ) + &&(p_bta_dm_eir_cfg->bta_dm_eir_uuid16)) + { + if( free_eir_length > LEN_UUID_16 + 2) + { + free_eir_length -= 2; + + if( free_eir_length >= p_bta_dm_eir_cfg->bta_dm_eir_uuid16_len) + { + num_uuid = p_bta_dm_eir_cfg->bta_dm_eir_uuid16_len / LEN_UUID_16; + data_type = BTM_EIR_COMPLETE_16BITS_UUID_TYPE; + } + else /* not enough room for all UUIDs */ + { + APPL_TRACE_WARNING("BTA EIR: UUID 16-bit list is truncated"); + num_uuid = free_eir_length / LEN_UUID_16; + data_type = BTM_EIR_MORE_16BITS_UUID_TYPE; + } + UINT8_TO_STREAM(p, num_uuid * LEN_UUID_16 + 1); + UINT8_TO_STREAM(p, data_type); + memcpy(p, p_bta_dm_eir_cfg->bta_dm_eir_uuid16, num_uuid * LEN_UUID_16 ); + p += num_uuid * LEN_UUID_16; + free_eir_length -= num_uuid * LEN_UUID_16; + } + } +#else /* (BTA_EIR_CANNED_UUID_LIST == TRUE) */ + /* if UUID list is dynamic */ + if ( free_eir_length >= 2) + { + p_length = p++; + p_type = p++; + num_uuid = 0; + + max_num_uuid = (free_eir_length - 2)/LEN_UUID_16; + data_type = BTM_GetEirSupportedServices( bta_dm_cb.eir_uuid, &p, max_num_uuid, &num_uuid ); + + if( data_type == BTM_EIR_MORE_16BITS_UUID_TYPE ) + { + APPL_TRACE_WARNING("BTA EIR: UUID 16-bit list is truncated"); + } +#if (BTA_EIR_SERVER_NUM_CUSTOM_UUID > 0) + else + { + for (custom_uuid_idx = 0; custom_uuid_idx < BTA_EIR_SERVER_NUM_CUSTOM_UUID; custom_uuid_idx++) + { + if (bta_dm_cb.custom_uuid[custom_uuid_idx].len == LEN_UUID_16) + { + if ( num_uuid < max_num_uuid ) + { + UINT16_TO_STREAM(p, bta_dm_cb.custom_uuid[custom_uuid_idx].uu.uuid16); + num_uuid++; + } + else + { + data_type = BTM_EIR_MORE_16BITS_UUID_TYPE; + APPL_TRACE_WARNING("BTA EIR: UUID 16-bit list is truncated"); + break; + } + } + } + } +#endif /* (BTA_EIR_SERVER_NUM_CUSTOM_UUID > 0) */ + + UINT8_TO_STREAM(p_length, num_uuid * LEN_UUID_16 + 1); + UINT8_TO_STREAM(p_type, data_type); + free_eir_length -= num_uuid * LEN_UUID_16 + 2; + } +#endif /* (BTA_EIR_CANNED_UUID_LIST == TRUE) */ + +#if ( BTA_EIR_CANNED_UUID_LIST != TRUE )&&(BTA_EIR_SERVER_NUM_CUSTOM_UUID > 0) + /* Adding 32-bit UUID list */ + if ( free_eir_length >= 2) + { + p_length = p++; + p_type = p++; + num_uuid = 0; + data_type = BTM_EIR_COMPLETE_32BITS_UUID_TYPE; + + max_num_uuid = (free_eir_length - 2)/LEN_UUID_32; + + for (custom_uuid_idx = 0; custom_uuid_idx < BTA_EIR_SERVER_NUM_CUSTOM_UUID; custom_uuid_idx++) + { + if (bta_dm_cb.custom_uuid[custom_uuid_idx].len == LEN_UUID_32) + { + if ( num_uuid < max_num_uuid ) + { + UINT32_TO_STREAM(p, bta_dm_cb.custom_uuid[custom_uuid_idx].uu.uuid32); + num_uuid++; + } + else + { + data_type = BTM_EIR_MORE_32BITS_UUID_TYPE; + APPL_TRACE_WARNING("BTA EIR: UUID 32-bit list is truncated"); + break; + } + } + } + + UINT8_TO_STREAM(p_length, num_uuid * LEN_UUID_32 + 1); + UINT8_TO_STREAM(p_type, data_type); + free_eir_length -= num_uuid * LEN_UUID_32 + 2; + } + + /* Adding 128-bit UUID list */ + if ( free_eir_length >= 2) + { + p_length = p++; + p_type = p++; + num_uuid = 0; + data_type = BTM_EIR_COMPLETE_128BITS_UUID_TYPE; + + max_num_uuid = (free_eir_length - 2)/LEN_UUID_128; + + for (custom_uuid_idx = 0; custom_uuid_idx < BTA_EIR_SERVER_NUM_CUSTOM_UUID; custom_uuid_idx++) + { + if (bta_dm_cb.custom_uuid[custom_uuid_idx].len == LEN_UUID_128) + { + if ( num_uuid < max_num_uuid ) + { + ARRAY16_TO_STREAM(p, bta_dm_cb.custom_uuid[custom_uuid_idx].uu.uuid128); + num_uuid++; + } + else + { + data_type = BTM_EIR_MORE_128BITS_UUID_TYPE; + APPL_TRACE_WARNING("BTA EIR: UUID 128-bit list is truncated"); + break; + } + } + } + + UINT8_TO_STREAM(p_length, num_uuid * LEN_UUID_128 + 1); + UINT8_TO_STREAM(p_type, data_type); + free_eir_length -= num_uuid * LEN_UUID_128 + 2; + } +#endif /* ( BTA_EIR_CANNED_UUID_LIST != TRUE )&&(BTA_EIR_SERVER_NUM_CUSTOM_UUID > 0) */ + + /* if Flags are provided in configuration */ + if(( p_bta_dm_eir_cfg->bta_dm_eir_flag_len > 0 ) + &&( p_bta_dm_eir_cfg->bta_dm_eir_flags ) + &&( free_eir_length >= p_bta_dm_eir_cfg->bta_dm_eir_flag_len + 2 )) + { + UINT8_TO_STREAM(p, p_bta_dm_eir_cfg->bta_dm_eir_flag_len + 1); + UINT8_TO_STREAM(p, BTM_EIR_FLAGS_TYPE); + memcpy(p, p_bta_dm_eir_cfg->bta_dm_eir_flags, + p_bta_dm_eir_cfg->bta_dm_eir_flag_len); + p += p_bta_dm_eir_cfg->bta_dm_eir_flag_len; + free_eir_length -= p_bta_dm_eir_cfg->bta_dm_eir_flag_len + 2; + } + + /* if Manufacturer Specific are provided in configuration */ + if(( p_bta_dm_eir_cfg->bta_dm_eir_manufac_spec_len > 0 ) + &&( p_bta_dm_eir_cfg->bta_dm_eir_manufac_spec ) + &&( free_eir_length >= p_bta_dm_eir_cfg->bta_dm_eir_manufac_spec_len + 2 )) + { + p_length = p; + + UINT8_TO_STREAM(p, p_bta_dm_eir_cfg->bta_dm_eir_manufac_spec_len + 1); + UINT8_TO_STREAM(p, BTM_EIR_MANUFACTURER_SPECIFIC_TYPE); + memcpy(p, p_bta_dm_eir_cfg->bta_dm_eir_manufac_spec, + p_bta_dm_eir_cfg->bta_dm_eir_manufac_spec_len); + p += p_bta_dm_eir_cfg->bta_dm_eir_manufac_spec_len; + free_eir_length -= p_bta_dm_eir_cfg->bta_dm_eir_manufac_spec_len + 2; + + } + else + { + p_length = NULL; + } + + /* if Inquiry Tx Resp Power compiled */ + if ((p_bta_dm_eir_cfg->bta_dm_eir_inq_tx_power) && + (free_eir_length >= 3)) + { + UINT8_TO_STREAM(p, 2); /* Length field */ + UINT8_TO_STREAM(p, BTM_EIR_TX_POWER_LEVEL_TYPE); + UINT8_TO_STREAM(p, *(p_bta_dm_eir_cfg->bta_dm_eir_inq_tx_power)); + free_eir_length -= 3; + } + + if( free_eir_length ) + UINT8_TO_STREAM(p, 0); /* terminator of significant part */ + + BTM_WriteEIR( p_buf ); + +} + +/******************************************************************************* +** +** Function bta_dm_eir_search_services +** +** Description This function searches services in received EIR +** +** Returns None +** +*******************************************************************************/ +static void bta_dm_eir_search_services( tBTM_INQ_RESULTS *p_result, + tBTA_SERVICE_MASK *p_services_to_search, + tBTA_SERVICE_MASK *p_services_found) +{ + tBTA_SERVICE_MASK service_index = 0; + tBTM_EIR_SEARCH_RESULT result; + + APPL_TRACE_DEBUG("BTA searching services in EIR of BDA:0x%02X%02X%02X%02X%02X%02X", + p_result->remote_bd_addr[0],p_result->remote_bd_addr[1], + p_result->remote_bd_addr[2],p_result->remote_bd_addr[3], + p_result->remote_bd_addr[4],p_result->remote_bd_addr[5]); + + APPL_TRACE_DEBUG(" with services_to_search=0x%08X", *p_services_to_search); + +#if BLE_INCLUDED == TRUE && BTA_GATT_INCLUDED == TRUE + /* always do GATT based service discovery by SDP instead of from EIR */ + /* if GATT based service is also to be put in EIR, need to modify this */ + while (service_index < (BTA_MAX_SERVICE_ID - 1)) +#else + while(service_index < BTA_MAX_SERVICE_ID) +#endif + { + if( *p_services_to_search + & (tBTA_SERVICE_MASK)(BTA_SERVICE_ID_TO_SERVICE_MASK(service_index))) + { + result = BTM_HasInquiryEirService( p_result, + bta_service_id_to_uuid_lkup_tbl[service_index] ); + + /* Searching for HSP v1.2 only device */ + if ((result != BTM_EIR_FOUND) && + (bta_service_id_to_uuid_lkup_tbl[service_index] == UUID_SERVCLASS_HEADSET)) + { + result = BTM_HasInquiryEirService (p_result, UUID_SERVCLASS_HEADSET_HS); + } + + if( result == BTM_EIR_FOUND ) + { + /* If Plug and Play service record, need to check to see if Broadcom stack */ + /* However, EIR data doesn't have EXT_BRCM_VERSION so just skip it */ + if( bta_service_id_to_uuid_lkup_tbl[service_index] + != UUID_SERVCLASS_PNP_INFORMATION ) + { + + *p_services_found |= + (tBTA_SERVICE_MASK)(BTA_SERVICE_ID_TO_SERVICE_MASK(service_index)); + /* remove the service from services to be searched */ + *p_services_to_search &= + (tBTA_SERVICE_MASK)(~(BTA_SERVICE_ID_TO_SERVICE_MASK(service_index))); + } + } + else if( result == BTM_EIR_NOT_FOUND ) + { + /* remove the service from services to be searched */ + *p_services_to_search &= + (tBTA_SERVICE_MASK)(~(BTA_SERVICE_ID_TO_SERVICE_MASK(service_index))); + } + } + + service_index++; + } + + APPL_TRACE_ERROR("BTA EIR search result, services_to_search=0x%08X, services_found=0x%08X", + *p_services_to_search, *p_services_found); +} + +#if (BTA_EIR_CANNED_UUID_LIST != TRUE) +/******************************************************************************* +** +** Function bta_dm_eir_update_uuid +** +** Description This function adds or removes service UUID in EIR database. +** +** Returns None +** +*******************************************************************************/ +void bta_dm_eir_update_uuid(UINT16 uuid16, BOOLEAN adding) +{ + /* if this UUID is not advertised in EIR */ + if( !BTM_HasEirService( p_bta_dm_eir_cfg->uuid_mask, uuid16 )) + return; + + if( adding ) + { + APPL_TRACE_EVENT("Adding UUID=0x%04X into EIR", uuid16); + + BTM_AddEirService( bta_dm_cb.eir_uuid, uuid16 ); + } + else + { + APPL_TRACE_EVENT("Removing UUID=0x%04X from EIR", uuid16); + + BTM_RemoveEirService( bta_dm_cb.eir_uuid, uuid16 ); + } + + bta_dm_set_eir (NULL); + + APPL_TRACE_EVENT("bta_dm_eir_update_uuid UUID bit mask=0x%08X %08X", + bta_dm_cb.eir_uuid[1], bta_dm_cb.eir_uuid[0] ); +} +#endif + +/******************************************************************************* +** +** Function bta_dm_enable_test_mode +** +** Description enable test mode +** +** +** Returns void +** +*******************************************************************************/ +void bta_dm_enable_test_mode(tBTA_DM_MSG *p_data) +{ + UNUSED(p_data); + BTM_EnableTestMode(); +} + +/******************************************************************************* +** +** Function bta_dm_disable_test_mode +** +** Description disable test mode +** +** +** Returns void +** +*******************************************************************************/ +void bta_dm_disable_test_mode(tBTA_DM_MSG *p_data) +{ + UNUSED(p_data); + BTM_DeviceReset(NULL); +} + +/******************************************************************************* +** +** Function bta_dm_execute_callback +** +** Description Just execute a generic call back in the context of the BTU/BTA tack +** +** +** Returns void +** +*******************************************************************************/ +void bta_dm_execute_callback(tBTA_DM_MSG *p_data) +{ + /* sanity check */ + if(p_data->exec_cback.p_exec_cback == NULL) + { + return; + } + + p_data->exec_cback.p_exec_cback(p_data->exec_cback.p_param); +} + +/******************************************************************************* +** +** Function bta_dm_encrypt_cback +** +** Description link encryption complete callback. +** +** Returns None +** +*******************************************************************************/ +void bta_dm_encrypt_cback(BD_ADDR bd_addr, tBT_TRANSPORT transport, void *p_ref_data, tBTM_STATUS result) +{ + tBTA_STATUS bta_status = BTA_SUCCESS; + tBTA_DM_ENCRYPT_CBACK *p_callback = NULL; + UINT8 i ; + UNUSED(p_ref_data); + + for (i=0; iset_encryption.p_callback) + { + APPL_TRACE_ERROR("bta_dm_set_encryption callback is not provided"); + return; + } + for (i=0; iset_encryption.bd_addr) == 0 && + bta_dm_cb.device_list.peer_device[i].conn_state == BTA_DM_CONNECTED) + break; + } + if (i < bta_dm_cb.device_list.count) + { + if (bta_dm_cb.device_list.peer_device[i].p_encrypt_cback) + { + APPL_TRACE_ERROR("earlier enc was not done for same device"); + (*p_data->set_encryption.p_callback)(p_data->set_encryption.bd_addr, + p_data->set_encryption.transport, + BTA_BUSY); + return; + } + + if (BTM_SetEncryption(p_data->set_encryption.bd_addr, p_data->set_encryption.transport, + bta_dm_encrypt_cback, &p_data->set_encryption.sec_act) + == BTM_CMD_STARTED) + { + bta_dm_cb.device_list.peer_device[i].p_encrypt_cback = p_data->set_encryption.p_callback; + } + } +} + +#if (BLE_INCLUDED == TRUE) +/******************************************************************************* +** +** Function bta_dm_observe_results_cb +** +** Description Callback for BLE Observe result +** +** +** Returns void +** +*******************************************************************************/ +static void bta_dm_observe_results_cb (tBTM_INQ_RESULTS *p_inq, UINT8 *p_eir) +{ +; + tBTA_DM_SEARCH result; + tBTM_INQ_INFO *p_inq_info; + APPL_TRACE_DEBUG("bta_dm_observe_results_cb") + + bdcpy(result.inq_res.bd_addr, p_inq->remote_bd_addr); + result.inq_res.rssi = p_inq->rssi; + result.inq_res.ble_addr_type = p_inq->ble_addr_type; + result.inq_res.inq_result_type = p_inq->inq_result_type; + result.inq_res.device_type = p_inq->device_type; + result.inq_res.flag = p_inq->flag; + + /* application will parse EIR to find out remote device name */ + result.inq_res.p_eir = p_eir; + + if((p_inq_info = BTM_InqDbRead(p_inq->remote_bd_addr)) != NULL) + { + /* initialize remt_name_not_required to FALSE so that we get the name by default */ + result.inq_res.remt_name_not_required = FALSE; + } + + if(bta_dm_search_cb.p_scan_cback) + bta_dm_search_cb.p_scan_cback(BTA_DM_INQ_RES_EVT, &result); + + if(p_inq_info) + { + /* application indicates if it knows the remote name, inside the callback + copy that to the inquiry data base*/ + if(result.inq_res.remt_name_not_required) + p_inq_info->appl_knows_rem_name = TRUE; + } +} + +/******************************************************************************* +** +** Function bta_dm_observe_cmpl_cb +** +** Description Callback for BLE Observe complete +** +** +** Returns void +** +*******************************************************************************/ +static void bta_dm_observe_cmpl_cb (void * p_result) +{ + tBTA_DM_SEARCH data; + + APPL_TRACE_DEBUG("bta_dm_observe_cmpl_cb"); + + data.inq_cmpl.num_resps = ((tBTM_INQUIRY_CMPL *)p_result)->num_resp; + if (bta_dm_search_cb.p_scan_cback) + { + bta_dm_search_cb.p_scan_cback(BTA_DM_INQ_CMPL_EVT, &data); + } +} + +#if (SMP_INCLUDED == TRUE) +/******************************************************************************* +** +** Function bta_dm_ble_smp_cback +** +** Description Callback for BLE SMP +** +** +** Returns void +** +*******************************************************************************/ +static UINT8 bta_dm_ble_smp_cback (tBTM_LE_EVT event, BD_ADDR bda, tBTM_LE_EVT_DATA *p_data) +{ + tBTM_STATUS status = BTM_SUCCESS; + tBTA_DM_SEC sec_event; + char *p_name = NULL; + UINT8 i; + tBT_DEVICE_TYPE dev_type; + + if (!bta_dm_cb.p_sec_cback) + return BTM_NOT_AUTHORIZED; + + memset(&sec_event, 0, sizeof(tBTA_DM_SEC)); + switch (event) + { + case BTM_LE_IO_REQ_EVT: +#if (BTM_LOCAL_IO_CAPS != BTM_IO_CAP_NONE) + + bta_dm_co_ble_io_req(bda, + &p_data->io_req.io_cap, + &p_data->io_req.oob_data, + &p_data->io_req.auth_req, + &p_data->io_req.max_key_size, + &p_data->io_req.init_keys, + &p_data->io_req.resp_keys); +#endif +#if BTM_OOB_INCLUDED == FALSE + status = BTM_SUCCESS; +#endif + APPL_TRACE_EVENT("io mitm: %d oob_data:%d\n", p_data->io_req.auth_req, p_data->io_req.oob_data); + + break; + + case BTM_LE_SEC_REQUEST_EVT: + bdcpy(sec_event.ble_req.bd_addr, bda); + p_name = BTM_SecReadDevName(bda); + if (p_name != NULL) + { + BCM_STRNCPY_S((char*)sec_event.ble_req.bd_name, + sizeof(BD_NAME), p_name, (BD_NAME_LEN)); + } + else + { + sec_event.ble_req.bd_name[0] = 0; + } + sec_event.ble_req.bd_name[BD_NAME_LEN] = 0; + bta_dm_cb.p_sec_cback(BTA_DM_BLE_SEC_REQ_EVT, &sec_event); + break; + + case BTM_LE_KEY_NOTIF_EVT: + bdcpy(sec_event.key_notif.bd_addr, bda); + p_name = BTM_SecReadDevName(bda); + if (p_name != NULL) + { + BCM_STRNCPY_S((char*)sec_event.key_notif.bd_name, + sizeof(BD_NAME), p_name, (BD_NAME_LEN)); + } + else + { + sec_event.key_notif.bd_name[0] = 0; + } + sec_event.ble_req.bd_name[BD_NAME_LEN] = 0; + sec_event.key_notif.passkey = p_data->key_notif; + bta_dm_cb.p_sec_cback(BTA_DM_BLE_PASSKEY_NOTIF_EVT, &sec_event); + break; + + case BTM_LE_KEY_REQ_EVT: + bdcpy(sec_event.ble_req.bd_addr, bda); + bta_dm_cb.p_sec_cback(BTA_DM_BLE_PASSKEY_REQ_EVT, &sec_event); + break; + + case BTM_LE_OOB_REQ_EVT: + bdcpy(sec_event.ble_req.bd_addr, bda); + bta_dm_cb.p_sec_cback(BTA_DM_BLE_OOB_REQ_EVT, &sec_event); + break; + + case BTM_LE_NC_REQ_EVT: + bdcpy(sec_event.key_notif.bd_addr, bda); + BCM_STRNCPY_S((char*)sec_event.key_notif.bd_name, sizeof(BD_NAME), bta_dm_get_remname(), (BD_NAME_LEN)); + sec_event.ble_req.bd_name[BD_NAME_LEN] = 0; + sec_event.key_notif.passkey = p_data->key_notif; + bta_dm_cb.p_sec_cback(BTA_DM_BLE_NC_REQ_EVT, &sec_event); + break; + + case BTM_LE_KEY_EVT: + bdcpy(sec_event.ble_key.bd_addr, bda); + sec_event.ble_key.key_type = p_data->key.key_type; + sec_event.ble_key.p_key_value = p_data->key.p_key_value; + bta_dm_cb.p_sec_cback(BTA_DM_BLE_KEY_EVT, &sec_event); + break; + + case BTM_LE_COMPLT_EVT: + bdcpy(sec_event.auth_cmpl.bd_addr, bda); +#if BLE_INCLUDED == TRUE + BTM_ReadDevInfo(bda, &sec_event.auth_cmpl.dev_type, &sec_event.auth_cmpl.addr_type); +#endif + p_name = BTM_SecReadDevName(bda); + if (p_name != NULL) + { + BCM_STRNCPY_S((char*)sec_event.auth_cmpl.bd_name, + sizeof(BD_NAME), p_name, (BD_NAME_LEN)); + } + else + { + sec_event.auth_cmpl.bd_name[0] = 0; + } + if (p_data->complt.reason != 0) + { + sec_event.auth_cmpl.fail_reason = BTA_DM_AUTH_CONVERT_SMP_CODE(((UINT8)p_data->complt.reason)); + /* delete this device entry from Sec Dev DB */ + bta_dm_remove_sec_dev_entry (bda); + } + else + { + sec_event.auth_cmpl.success = TRUE; + if (!p_data->complt.smp_over_br) + GATT_ConfigServiceChangeCCC(bda, TRUE, BT_TRANSPORT_LE); + } + + if (bta_dm_cb.p_sec_cback) + { + //bta_dm_cb.p_sec_cback(BTA_DM_AUTH_CMPL_EVT, &sec_event); + bta_dm_cb.p_sec_cback(BTA_DM_BLE_AUTH_CMPL_EVT, &sec_event); + } + + break; + + default: + status = BTM_NOT_AUTHORIZED; + break; + } + return status; +} +#endif /* SMP_INCLUDED == TRUE */ + +/******************************************************************************* +** +** Function bta_dm_ble_id_key_cback +** +** Description Callback for BLE local ID keys +** +** +** Returns void +** +*******************************************************************************/ +static void bta_dm_ble_id_key_cback (UINT8 key_type, tBTM_BLE_LOCAL_KEYS *p_key) +{ + UINT8 evt; + tBTA_DM_SEC dm_key; + + switch (key_type) + { + case BTM_BLE_KEY_TYPE_ID: + case BTM_BLE_KEY_TYPE_ER: + if (bta_dm_cb.p_sec_cback) + { + memcpy(&dm_key.ble_id_keys, p_key, sizeof(tBTM_BLE_LOCAL_KEYS)); + + evt = (key_type == BTM_BLE_KEY_TYPE_ID) ? BTA_DM_BLE_LOCAL_IR_EVT :\ + BTA_DM_BLE_LOCAL_ER_EVT; + bta_dm_cb.p_sec_cback(evt, &dm_key); + } + break; + + default: + APPL_TRACE_DEBUG("Unknown key type %d", key_type); + break; + } + return; + +} + +/******************************************************************************* +** +** Function bta_dm_add_blekey +** +** Description This function adds an BLE Key to an security database entry. +** This function shall only be called AFTER BTA_DmAddBleDevice has been called. +** It is normally called during host startup to restore all required information +** stored in the NVRAM. +** +** Parameters: +** +*******************************************************************************/ +void bta_dm_add_blekey (tBTA_DM_MSG *p_data) +{ + if (!BTM_SecAddBleKey (p_data->add_ble_key.bd_addr, + (tBTM_LE_KEY_VALUE *)&p_data->add_ble_key.blekey, + p_data->add_ble_key.key_type)) + { + APPL_TRACE_ERROR ("BTA_DM: Error adding BLE Key for device %08x%04x", + (p_data->add_ble_key.bd_addr[0]<<24)+(p_data->add_ble_key.bd_addr[1]<<16)+\ + (p_data->add_ble_key.bd_addr[2]<<8)+p_data->add_ble_key.bd_addr[3], + (p_data->add_ble_key.bd_addr[4]<<8)+p_data->add_ble_key.bd_addr[5]); + } +} + +/******************************************************************************* +** +** Function bta_dm_add_ble_device +** +** Description This function adds an BLE device to an security database entry. +** It is normally called during host startup to restore all required information +** stored in the NVRAM. +** +** Parameters: +** +*******************************************************************************/ +void bta_dm_add_ble_device (tBTA_DM_MSG *p_data) +{ + if (!BTM_SecAddBleDevice (p_data->add_ble_device.bd_addr, NULL, + p_data->add_ble_device.dev_type , + p_data->add_ble_device.addr_type)) + { + APPL_TRACE_ERROR ("BTA_DM: Error adding BLE Device for device %08x%04x", + (p_data->add_ble_device.bd_addr[0]<<24)+(p_data->add_ble_device.bd_addr[1]<<16)+ \ + (p_data->add_ble_device.bd_addr[2]<<8)+p_data->add_ble_device.bd_addr[3], + (p_data->add_ble_device.bd_addr[4]<<8)+p_data->add_ble_device.bd_addr[5]); + } +} + +/******************************************************************************* +** +** Function bta_dm_add_ble_device +** +** Description This function adds an BLE device to an security database entry. +** It is normally called during host startup to restore all required information +** stored in the NVRAM. +** +** Parameters: +** +*******************************************************************************/ +void bta_dm_ble_passkey_reply (tBTA_DM_MSG *p_data) +{ + if (p_data->pin_reply.accept) + { + BTM_BlePasskeyReply(p_data->ble_passkey_reply.bd_addr, BTM_SUCCESS, p_data->ble_passkey_reply.passkey); + } + else + { + BTM_BlePasskeyReply(p_data->ble_passkey_reply.bd_addr, BTM_NOT_AUTHORIZED, p_data->ble_passkey_reply.passkey); + } + +} + +/******************************************************************************* +** +** Function bta_dm_ble_confirm_reply +** +** Description This is response to SM numeric comparison request submitted +** to application. +** +** Parameters: +** +*******************************************************************************/ +void bta_dm_ble_confirm_reply (tBTA_DM_MSG *p_data) +{ + if (p_data->confirm.accept) + { + BTM_BleConfirmReply(p_data->confirm.bd_addr, BTM_SUCCESS); + } + else + { + BTM_BleConfirmReply(p_data->ble_passkey_reply.bd_addr, BTM_NOT_AUTHORIZED); + } +} + +/******************************************************************************* +** +** Function bta_dm_security_grant +** +** Description This function grant SMP security request access. +** +** Parameters: +** +*******************************************************************************/ +void bta_dm_security_grant (tBTA_DM_MSG *p_data) +{ + BTM_SecurityGrant(p_data->ble_sec_grant.bd_addr, p_data->ble_sec_grant.res); +} + +/******************************************************************************* +** +** Function bta_dm_ble_set_bg_conn_type +** +** Description This function set the BLE background connection type +** +** Parameters: +** +*******************************************************************************/ +void bta_dm_ble_set_bg_conn_type (tBTA_DM_MSG *p_data) +{ + BTM_BleSetBgConnType(p_data->ble_set_bd_conn_type.bg_conn_type, + p_data->ble_set_bd_conn_type.p_select_cback); +} + +/******************************************************************************* +** +** Function bta_dm_ble_set_conn_params +** +** Description This function set the preferred connection parameters. +** +** Parameters: +** +*******************************************************************************/ +void bta_dm_ble_set_conn_params (tBTA_DM_MSG *p_data) +{ + BTM_BleSetPrefConnParams(p_data->ble_set_conn_params.peer_bda, + p_data->ble_set_conn_params.conn_int_min, + p_data->ble_set_conn_params.conn_int_max, + p_data->ble_set_conn_params.slave_latency, + p_data->ble_set_conn_params.supervision_tout); +} + +/******************************************************************************* +** +** Function bta_dm_ble_set_conn_scan_params +** +** Description This function sets BLE scan parameters. +** +** Parameters: +** +*******************************************************************************/ +void bta_dm_ble_set_scan_params(tBTA_DM_MSG *p_data) +{ + BTM_BleSetScanParams(p_data->ble_set_scan_params.client_if, + p_data->ble_set_scan_params.scan_int, + p_data->ble_set_scan_params.scan_window, + p_data->ble_set_scan_params.scan_mode, + p_data->ble_set_scan_params.scan_param_setup_cback); +} + +/******************************************************************************* +** +** Function bta_dm_ble_set_conn_scan_params +** +** Description This function set the preferred connection scan parameters. +** +** Parameters: +** +*******************************************************************************/ +void bta_dm_ble_set_conn_scan_params (tBTA_DM_MSG *p_data) +{ + BTM_BleSetConnScanParams(p_data->ble_set_conn_scan_params.scan_int, + p_data->ble_set_conn_scan_params.scan_window); +} +/******************************************************************************* +** +** Function bta_dm_ble_update_conn_params +** +** Description This function update LE connection parameters. +** +** Parameters: +** +*******************************************************************************/ +void bta_dm_ble_update_conn_params (tBTA_DM_MSG *p_data) +{ + if (!L2CA_UpdateBleConnParams(p_data->ble_update_conn_params.bd_addr, + p_data->ble_update_conn_params.min_int, + p_data->ble_update_conn_params.max_int, + p_data->ble_update_conn_params.latency, + p_data->ble_update_conn_params.timeout)) + { + APPL_TRACE_ERROR("Update connection parameters failed!"); + } +} + +/******************************************************************************* +** +** Function bta_dm_ble_set_rand_address +** +** Description This function set the LE random address for the device. +** +** Parameters: rand_addr:the random address whitch should be setting +** Explanation: This function added by Yulong at 2016/9/9 +*******************************************************************************/ +void bta_dm_ble_set_rand_address(tBTA_DM_MSG *p_data) +{ + UINT8 len = sizeof(p_data->set_addr); + if(len != BD_ADDR_LEN) + { + APPL_TRACE_ERROR("Invalid random adress"); + return; + } + if(p_data->set_addr.addr_type != BLE_ADDR_RANDOM) + { + APPL_TRACE_ERROR("Invalid random adress type = %d\n",p_data->set_addr.addr_type); + return; + } + //send the setting random address to BTM layer + BTM_BleSetRandAddress(p_data->set_addr.address); + +} + +#if BLE_PRIVACY_SPT == TRUE +/******************************************************************************* +** +** Function bta_dm_ble_config_local_privacy +** +** Description This function set the local device LE privacy settings. +** +** Parameters: +** +*******************************************************************************/ +void bta_dm_ble_config_local_privacy (tBTA_DM_MSG *p_data) +{ + BTM_BleConfigPrivacy (p_data->ble_local_privacy.privacy_enable); +} +#endif + +/******************************************************************************* +** +** Function bta_dm_ble_observe +** +** Description This function set the preferred connection scan parameters. +** +** Parameters: +** +*******************************************************************************/ +void bta_dm_ble_observe (tBTA_DM_MSG *p_data) +{ + tBTM_STATUS status; + if (p_data->ble_observe.start) + { + /*Save the callback to be called when a scan results are available */ + bta_dm_search_cb.p_scan_cback = p_data->ble_observe.p_cback; + if ((status = BTM_BleObserve(TRUE, p_data->ble_observe.duration, + bta_dm_observe_results_cb, bta_dm_observe_cmpl_cb))!= BTM_CMD_STARTED) + { + tBTA_DM_SEARCH data; + APPL_TRACE_WARNING(" %s BTM_BleObserve failed. status %d",__FUNCTION__,status); + data.inq_cmpl.num_resps = 0; + if (bta_dm_search_cb.p_scan_cback) + { + bta_dm_search_cb.p_scan_cback(BTA_DM_INQ_CMPL_EVT, &data); + } + } + } + else + { + bta_dm_search_cb.p_scan_cback = NULL; + BTM_BleObserve(FALSE, 0, NULL,NULL ); + } +} +/******************************************************************************* +** +** Function bta_dm_ble_set_adv_params +** +** Description This function set the adv parameters. +** +** Parameters: +** +*******************************************************************************/ +void bta_dm_ble_set_adv_params (tBTA_DM_MSG *p_data) +{ + BTM_BleSetAdvParams(p_data->ble_set_adv_params.adv_int_min, + p_data->ble_set_adv_params.adv_int_max, + p_data->ble_set_adv_params.p_dir_bda, + BTA_DM_BLE_ADV_CHNL_MAP); +} + +/******************************************************************************* +** +** Function bta_dm_ble_set_adv_config +** +** Description This function set the customized ADV data configuration +** +** Parameters: +** +*******************************************************************************/ +void bta_dm_ble_set_adv_config (tBTA_DM_MSG *p_data) +{ + tBTA_STATUS status = BTA_FAILURE; + + if (BTM_BleWriteAdvData(p_data->ble_set_adv_data.data_mask, + (tBTM_BLE_ADV_DATA *)p_data->ble_set_adv_data.p_adv_cfg) == BTM_SUCCESS) + { + status = BTA_SUCCESS; + } + + if (p_data->ble_set_adv_data.p_adv_data_cback) + (*p_data->ble_set_adv_data.p_adv_data_cback)(status); +} + +/******************************************************************************* +** +** Function bta_dm_ble_set_scan_rsp +** +** Description This function set the customized ADV scan resp. configuration +** +** Parameters: +** +*******************************************************************************/ +void bta_dm_ble_set_scan_rsp (tBTA_DM_MSG *p_data) +{ + tBTA_STATUS status = BTA_FAILURE; + + if(BTM_BleWriteScanRsp(p_data->ble_set_adv_data.data_mask, + (tBTM_BLE_ADV_DATA *)p_data->ble_set_adv_data.p_adv_cfg) == BTM_SUCCESS) + { + status = BTA_SUCCESS; + } + + if (p_data->ble_set_adv_data.p_adv_data_cback) + (*p_data->ble_set_adv_data.p_adv_data_cback)(status); +} + +/******************************************************************************* +** +** Function bta_dm_ble_set_data_length +** +** Description This function set the maximum transmission packet size +** +** Parameters +** +*******************************************************************************/ +void bta_dm_ble_set_data_length(tBTA_DM_MSG *p_data) +{ + if (BTM_SetBleDataLength(p_data->ble_set_data_length.remote_bda, + p_data->ble_set_data_length.tx_data_length) != BTM_SUCCESS) + { + APPL_TRACE_ERROR("%s failed", __FUNCTION__); + } +} + +/******************************************************************************* +** +** Function bta_dm_ble_broadcast +** +** Description Starts or stops LE broadcasts +** +** Parameters: +** +*******************************************************************************/ +void bta_dm_ble_broadcast (tBTA_DM_MSG *p_data) +{ + BTM_BleBroadcast(p_data->ble_observe.start); +} + +/******************************************************************************* +** +** Function bta_dm_ble_multi_adv_enb +** +** Description This function enables a single advertising instance +** +** Parameters: +** +*******************************************************************************/ +void bta_dm_ble_multi_adv_enb(tBTA_DM_MSG *p_data) +{ + tBTM_STATUS btm_status = 0; + + bta_dm_cb.p_multi_adv_cback = p_data->ble_multi_adv_enb.p_cback; + if(BTM_BleMaxMultiAdvInstanceCount() > 0 && NULL != p_data->ble_multi_adv_enb.p_ref) + { + btm_status = BTM_BleEnableAdvInstance((tBTM_BLE_ADV_PARAMS*) + p_data->ble_multi_adv_enb.p_params, + p_data->ble_multi_adv_enb.p_cback, + p_data->ble_multi_adv_enb.p_ref); + } + + if(BTM_CMD_STARTED != btm_status) + { + bta_dm_cb.p_multi_adv_cback(BTA_BLE_MULTI_ADV_ENB_EVT, 0xFF, + p_data->ble_multi_adv_enb.p_ref, BTA_FAILURE); + } +} +/******************************************************************************* +** +** Function bta_dm_ble_multi_adv_param_upd +** +** Description This function updates multiple advertising instance parameters +** +** Parameters: +** +*******************************************************************************/ +void bta_dm_ble_multi_adv_upd_param(tBTA_DM_MSG *p_data) +{ + tBTM_STATUS btm_status = 0; + void *p_ref = NULL; + + if(BTM_BleMaxMultiAdvInstanceCount() > 0 && p_data->ble_multi_adv_param.inst_id > 0 + && p_data->ble_multi_adv_param.inst_id < BTM_BleMaxMultiAdvInstanceCount()) + { + btm_status = BTM_BleUpdateAdvInstParam(p_data->ble_multi_adv_param.inst_id, + (tBTM_BLE_ADV_PARAMS*)p_data->ble_multi_adv_param.p_params); + } + + if(BTM_CMD_STARTED != btm_status) + { + p_ref = btm_ble_multi_adv_get_ref(p_data->ble_multi_adv_param.inst_id); + bta_dm_cb.p_multi_adv_cback(BTA_BLE_MULTI_ADV_PARAM_EVT, + p_data->ble_multi_adv_param.inst_id, p_ref, BTA_FAILURE); + } +} +/******************************************************************************* +** +** Function bta_dm_ble_multi_adv_data +** +** Description This function write multiple advertising instance adv data +** or scan response data +** +** Parameters: +** +*******************************************************************************/ +void bta_dm_ble_multi_adv_data(tBTA_DM_MSG *p_data) +{ + tBTM_STATUS btm_status = 0; + void *p_ref = NULL; + + if(BTM_BleMaxMultiAdvInstanceCount() > 0 && p_data->ble_multi_adv_data.inst_id > 0 + && p_data->ble_multi_adv_data.inst_id < BTM_BleMaxMultiAdvInstanceCount()) + { + btm_status = BTM_BleCfgAdvInstData(p_data->ble_multi_adv_data.inst_id, + p_data->ble_multi_adv_data.is_scan_rsp, + p_data->ble_multi_adv_data.data_mask, + (tBTM_BLE_ADV_DATA*)p_data->ble_multi_adv_data.p_data); + } + + if(BTM_CMD_STARTED != btm_status) + { + p_ref = btm_ble_multi_adv_get_ref(p_data->ble_multi_adv_data.inst_id); + bta_dm_cb.p_multi_adv_cback(BTA_BLE_MULTI_ADV_DATA_EVT, + p_data->ble_multi_adv_data.inst_id, p_ref, BTA_FAILURE); + } + +} +/******************************************************************************* +** +** Function btm_dm_ble_multi_adv_disable +** +** Description This function disable a single adv instance +** +** Parameters: +** +*******************************************************************************/ +void btm_dm_ble_multi_adv_disable(tBTA_DM_MSG *p_data) +{ + tBTM_STATUS btm_status = 0; + void *p_ref = NULL; + + if(BTM_BleMaxMultiAdvInstanceCount() > 0 && p_data->ble_multi_adv_disable.inst_id > 0 + && p_data->ble_multi_adv_disable.inst_id < BTM_BleMaxMultiAdvInstanceCount()) + { + btm_status = BTM_BleDisableAdvInstance(p_data->ble_multi_adv_disable.inst_id); + } + + if(BTM_CMD_STARTED != btm_status) + { + p_ref = btm_ble_multi_adv_get_ref(p_data->ble_multi_adv_disable.inst_id); + bta_dm_cb.p_multi_adv_cback(BTA_BLE_MULTI_ADV_DISABLE_EVT, + p_data->ble_multi_adv_disable.inst_id, p_ref, BTA_FAILURE); + } +} + +/******************************************************************************* +** +** Function bta_dm_ble_setup_storage +** +** Description This function configures up the storage parameters for ADV batch scanning +** +** Parameters: +** +*******************************************************************************/ +void bta_dm_ble_setup_storage (tBTA_DM_MSG *p_data) +{ + tBTM_STATUS btm_status = 0; + tBTM_BLE_VSC_CB cmn_ble_vsc_cb; + + BTM_BleGetVendorCapabilities(&cmn_ble_vsc_cb); + + if (0 != cmn_ble_vsc_cb.tot_scan_results_strg) + { + btm_status = BTM_BleSetStorageConfig(p_data->ble_set_storage.batch_scan_full_max, + p_data->ble_set_storage.batch_scan_trunc_max, + p_data->ble_set_storage.batch_scan_notify_threshold, + p_data->ble_set_storage.p_setup_cback, + p_data->ble_set_storage.p_thres_cback, + p_data->ble_set_storage.p_read_rep_cback, + p_data->ble_set_storage.ref_value); + } + + if(BTM_CMD_STARTED != btm_status) + bta_ble_scan_setup_cb(BTM_BLE_BATCH_SCAN_CFG_STRG_EVT, p_data->ble_set_storage.ref_value, + btm_status); +} + +/******************************************************************************* +** +** Function bta_dm_ble_enable_batch_scan +** +** Description This function sets up the parameters and enables batch scan +** +** Parameters: +** +*******************************************************************************/ +void bta_dm_ble_enable_batch_scan (tBTA_DM_MSG *p_data) +{ + tBTM_STATUS btm_status = 0; + tBTM_BLE_VSC_CB cmn_ble_vsc_cb; + + BTM_BleGetVendorCapabilities(&cmn_ble_vsc_cb); + + if (0 != cmn_ble_vsc_cb.tot_scan_results_strg) + { + btm_status = BTM_BleEnableBatchScan(p_data->ble_enable_scan.scan_mode, + p_data->ble_enable_scan.scan_int, + p_data->ble_enable_scan.scan_window, + p_data->ble_enable_scan.discard_rule, + p_data->ble_enable_scan.addr_type, + p_data->ble_enable_scan.ref_value); + } + + if(BTM_CMD_STARTED != btm_status) + bta_ble_scan_setup_cb(BTM_BLE_BATCH_SCAN_ENABLE_EVT, p_data->ble_enable_scan.ref_value, + btm_status); +} + +/******************************************************************************* +** +** Function bta_dm_ble_disable_batch_scan +** +** Description This function disables the batch scan +** +** Parameters: +** +*******************************************************************************/ +void bta_dm_ble_disable_batch_scan (tBTA_DM_MSG *p_data) +{ + UNUSED(p_data); + tBTM_STATUS btm_status = 0; + tBTM_BLE_VSC_CB cmn_ble_vsc_cb; + + BTM_BleGetVendorCapabilities(&cmn_ble_vsc_cb); + + if (0 != cmn_ble_vsc_cb.tot_scan_results_strg) + { + btm_status = BTM_BleDisableBatchScan(p_data->ble_disable_scan.ref_value); + } + + if(BTM_CMD_STARTED != btm_status) + bta_ble_scan_setup_cb(BTM_BLE_BATCH_SCAN_DISABLE_EVT, p_data->ble_enable_scan.ref_value, + btm_status); +} + +/******************************************************************************* +** +** Function bta_dm_ble_read_scan_reports +** +** Description This function reads the batch scan reports +** +** Parameters: +** +*******************************************************************************/ +void bta_dm_ble_read_scan_reports(tBTA_DM_MSG *p_data) +{ + tBTM_STATUS btm_status = 0; + tBTM_BLE_VSC_CB cmn_ble_vsc_cb; + + BTM_BleGetVendorCapabilities(&cmn_ble_vsc_cb); + + if (0 != cmn_ble_vsc_cb.tot_scan_results_strg) + { + btm_status = BTM_BleReadScanReports(p_data->ble_read_reports.scan_type, + p_data->ble_read_reports.ref_value); + } + + if(BTM_CMD_STARTED != btm_status) + bta_ble_scan_setup_cb(BTM_BLE_BATCH_SCAN_READ_REPTS_EVT, p_data->ble_enable_scan.ref_value, + btm_status); +} + +/******************************************************************************* +** +** Function bta_dm_ble_track_advertiser +** +** Description This function tracks the specific advertiser +** +** Parameters: +** +*******************************************************************************/ +void bta_dm_ble_track_advertiser(tBTA_DM_MSG *p_data) +{ + tBTM_STATUS btm_status = 0; + BD_ADDR bda; + memset(&bda, 0 , sizeof(BD_ADDR)); + tBTM_BLE_VSC_CB cmn_ble_vsc_cb; + tBTA_DM_BLE_TRACK_ADV_DATA track_adv_data; + + BTM_BleGetVendorCapabilities(&cmn_ble_vsc_cb); + + if (0 != cmn_ble_vsc_cb.tot_scan_results_strg) + { + btm_status = BTM_BleTrackAdvertiser((tBTM_BLE_TRACK_ADV_CBACK *) + p_data->ble_track_advert.p_track_adv_cback, + p_data->ble_track_advert.ref_value); + } + + if(BTM_CMD_STARTED != btm_status) + { + memset(&track_adv_data, 0, sizeof(tBTA_DM_BLE_TRACK_ADV_DATA)); + track_adv_data.advertiser_info_present = NO_ADV_INFO_PRESENT; /* Indicates failure */ + track_adv_data.client_if = (UINT8)p_data->ble_track_advert.ref_value; + p_data->ble_track_advert.p_track_adv_cback(&track_adv_data); + } +} + +/******************************************************************************* +** +** Function bta_ble_scan_setup_cb +** +** Description Handle the setup callback from BTM layer and forward it to app layer +** +** Parameters: +** +*******************************************************************************/ +void bta_ble_scan_setup_cb(tBTM_BLE_BATCH_SCAN_EVT evt, tBTM_BLE_REF_VALUE ref_value, + tBTM_STATUS status) +{ + tBTA_BLE_BATCH_SCAN_EVT bta_evt = 0; + + APPL_TRACE_DEBUG("bta_ble_scan_setup_cb : evt: %d, ref_value: %d, status:%d", evt, + ref_value, status); + + switch(evt) + { + case BTM_BLE_BATCH_SCAN_ENABLE_EVT: + bta_evt = BTA_BLE_BATCH_SCAN_ENB_EVT; + break; + case BTM_BLE_BATCH_SCAN_CFG_STRG_EVT: + bta_evt = BTA_BLE_BATCH_SCAN_CFG_STRG_EVT; + break; + case BTM_BLE_BATCH_SCAN_DISABLE_EVT: + bta_evt = BTA_BLE_BATCH_SCAN_DIS_EVT; + break; + case BTM_BLE_BATCH_SCAN_PARAM_EVT: + bta_evt = BTA_BLE_BATCH_SCAN_PARAM_EVT; + break; + default: + break; + } + + if(NULL != bta_dm_cb.p_setup_cback) + bta_dm_cb.p_setup_cback(bta_evt, ref_value, status); +} + + +#if BLE_ANDROID_CONTROLLER_SCAN_FILTER == TRUE +/******************************************************************************* +** +** Function bta_ble_scan_pf_cmpl +** +** Description ADV payload filtering operation complete callback +** +** +** Returns TRUE if handled, otherwise FALSE. +** +*******************************************************************************/ +static void bta_ble_scan_cfg_cmpl(tBTM_BLE_PF_ACTION action, tBTM_BLE_SCAN_COND_OP cfg_op, + tBTM_BLE_PF_AVBL_SPACE avbl_space, tBTM_STATUS status, + tBTM_BLE_REF_VALUE ref_value) +{ + tBTA_STATUS st = (status == BTM_SUCCESS) ? BTA_SUCCESS: BTA_FAILURE; + + APPL_TRACE_DEBUG("bta_ble_scan_cfg_cmpl: %d, %d, %d, %d", action, cfg_op, avbl_space, status); + + if(bta_dm_cb.p_scan_filt_cfg_cback) + bta_dm_cb.p_scan_filt_cfg_cback(action, cfg_op, avbl_space, st, ref_value); +} + +/******************************************************************************* +** +** Function bta_dm_cfg_filter_cond +** +** Description This function configure adv payload filtering condition +** +** Parameters: +** +*******************************************************************************/ +void bta_dm_cfg_filter_cond (tBTA_DM_MSG *p_data) +{ + tBTM_STATUS st = BTM_MODE_UNSUPPORTED; + tBTA_STATUS status = BTA_FAILURE; + + tBTM_BLE_VSC_CB cmn_vsc_cb; + + APPL_TRACE_DEBUG("bta_dm_cfg_filter_cond"); + BTM_BleGetVendorCapabilities(&cmn_vsc_cb); + if(0 != cmn_vsc_cb.filter_support) + { + if ((st = BTM_BleCfgFilterCondition(p_data->ble_cfg_filter_cond.action, + p_data->ble_cfg_filter_cond.cond_type, + (tBTM_BLE_PF_FILT_INDEX)p_data->ble_cfg_filter_cond.filt_index, + (tBTM_BLE_PF_COND_PARAM *)p_data->ble_cfg_filter_cond.p_cond_param, + bta_ble_scan_cfg_cmpl, p_data->ble_cfg_filter_cond.ref_value)) + == BTM_CMD_STARTED) + { + bta_dm_cb.p_scan_filt_cfg_cback = p_data->ble_cfg_filter_cond.p_filt_cfg_cback; + return; + } + } + + if (p_data->ble_cfg_filter_cond.p_filt_cfg_cback) + p_data->ble_cfg_filter_cond.p_filt_cfg_cback(BTA_DM_BLE_PF_CONFIG_EVT, + p_data->ble_cfg_filter_cond.cond_type, 0, status, + p_data->ble_cfg_filter_cond.ref_value); + return; +} + +/******************************************************************************* +** +** Function bta_dm_enable_scan_filter +** +** Description This function enable/disable adv payload filtering condition +** +** Parameters: +** +*******************************************************************************/ +void bta_dm_enable_scan_filter(tBTA_DM_MSG *p_data) +{ + tBTM_STATUS st = BTM_MODE_UNSUPPORTED; + tBTA_STATUS status = BTA_FAILURE; + + tBTM_BLE_VSC_CB cmn_vsc_cb; + APPL_TRACE_DEBUG("bta_dm_enable_scan_filter"); + BTM_BleGetVendorCapabilities(&cmn_vsc_cb); + + if(0 != cmn_vsc_cb.filter_support) + { + if((st = BTM_BleEnableDisableFilterFeature(p_data->ble_enable_scan_filt.action, + p_data->ble_enable_scan_filt.p_filt_status_cback, + (tBTM_BLE_REF_VALUE)p_data->ble_enable_scan_filt.ref_value)) == BTM_CMD_STARTED) + bta_dm_cb.p_scan_filt_status_cback = p_data->ble_enable_scan_filt.p_filt_status_cback; + return; + } + + if (p_data->ble_enable_scan_filt.p_filt_status_cback) + p_data->ble_enable_scan_filt.p_filt_status_cback (BTA_DM_BLE_PF_ENABLE_EVT, + p_data->ble_enable_scan_filt.ref_value, status); + +} + +/******************************************************************************* +** +** Function bta_dm_scan_filter_param_setup +** +** Description This function sets up scan filter params +** +** Parameters: +** +*******************************************************************************/ +void bta_dm_scan_filter_param_setup (tBTA_DM_MSG *p_data) +{ + tBTM_STATUS st = BTM_MODE_UNSUPPORTED; + tBTA_STATUS status = BTA_FAILURE; + + tBTM_BLE_VSC_CB cmn_vsc_cb; + + APPL_TRACE_DEBUG("bta_dm_scan_filter_param_setup"); + BTM_BleGetVendorCapabilities(&cmn_vsc_cb); + if(0 != cmn_vsc_cb.filter_support) + { + if ((st = BTM_BleAdvFilterParamSetup(p_data->ble_scan_filt_param_setup.action, + p_data->ble_scan_filt_param_setup.filt_index, + (tBTM_BLE_PF_FILT_PARAMS *)&p_data->ble_scan_filt_param_setup.filt_params, + p_data->ble_scan_filt_param_setup.p_target, + p_data->ble_scan_filt_param_setup.p_filt_param_cback, + p_data->ble_scan_filt_param_setup.ref_value)) == BTM_CMD_STARTED) + { + bta_dm_cb.p_scan_filt_param_cback = p_data->ble_scan_filt_param_setup.p_filt_param_cback; + return; + } + } + + if (p_data->ble_scan_filt_param_setup.p_filt_param_cback) + p_data->ble_scan_filt_param_setup.p_filt_param_cback (BTA_DM_BLE_PF_ENABLE_EVT, 0, + p_data->ble_scan_filt_param_setup.ref_value, status); + + return; +} +#endif + +/******************************************************************************* +** +** Function bta_ble_enable_scan_cmpl +** +** Description ADV payload filtering enable / disable complete callback +** +** +** Returns None +** +*******************************************************************************/ +static void bta_ble_energy_info_cmpl(tBTM_BLE_TX_TIME_MS tx_time, + tBTM_BLE_RX_TIME_MS rx_time, + tBTM_BLE_IDLE_TIME_MS idle_time, + tBTM_BLE_ENERGY_USED energy_used, + tBTM_STATUS status) +{ + tBTA_STATUS st = (status == BTM_SUCCESS) ? BTA_SUCCESS: BTA_FAILURE; + tBTA_DM_CONTRL_STATE ctrl_state = 0; + + if (BTA_SUCCESS == st) + ctrl_state = bta_dm_pm_obtain_controller_state(); + + if (bta_dm_cb.p_energy_info_cback) + bta_dm_cb.p_energy_info_cback(tx_time, rx_time, idle_time, energy_used, ctrl_state, st); +} + +/******************************************************************************* +** +** Function bta_dm_ble_get_energy_info +** +** Description This function obtains the energy info +** +** Parameters: +** +*******************************************************************************/ +void bta_dm_ble_get_energy_info(tBTA_DM_MSG *p_data) +{ + tBTM_STATUS btm_status = 0; + + bta_dm_cb.p_energy_info_cback = p_data->ble_energy_info.p_energy_info_cback; + btm_status = BTM_BleGetEnergyInfo(bta_ble_energy_info_cmpl); + if (BTM_CMD_STARTED != btm_status) + bta_ble_energy_info_cmpl(0, 0, 0, 0, btm_status); +} + +#if ((defined BTA_GATT_INCLUDED) && (BTA_GATT_INCLUDED == TRUE)) +#ifndef BTA_DM_GATT_CLOSE_DELAY_TOUT +#define BTA_DM_GATT_CLOSE_DELAY_TOUT 1000 +#endif + +/******************************************************************************* +** +** Function bta_dm_gattc_register +** +** Description Register with GATTC in DM if BLE is needed. +** +** +** Returns void +** +*******************************************************************************/ +static void bta_dm_gattc_register(void) +{ + tBT_UUID app_uuid = {LEN_UUID_128,{0}}; + + if (bta_dm_search_cb.client_if == BTA_GATTS_INVALID_IF) + { + memset (&app_uuid.uu.uuid128, 0x87, LEN_UUID_128); + BTA_GATTC_AppRegister(&app_uuid, bta_dm_gattc_callback); + } +} + +/******************************************************************************* +** +** Function btm_dm_start_disc_gatt_services +** +** Description This function starts a GATT service search request. +** +** Parameters: +** +*******************************************************************************/ +static void btm_dm_start_disc_gatt_services (UINT16 conn_id) +{ + tBT_UUID *p_uuid = bta_dm_search_cb.p_srvc_uuid + + bta_dm_search_cb.num_uuid - bta_dm_search_cb.uuid_to_search; + + p_uuid = bta_dm_search_cb.p_srvc_uuid + + bta_dm_search_cb.num_uuid - bta_dm_search_cb.uuid_to_search; + + /* always search for all services */ + BTA_GATTC_ServiceSearchRequest(conn_id, p_uuid); +} + +/******************************************************************************* +** +** Function bta_dm_gatt_disc_result +** +** Description This function process the GATT service search result. +** +** Parameters: +** +*******************************************************************************/ +static void bta_dm_gatt_disc_result(tBTA_GATT_ID service_id) +{ + tBTA_DM_SEARCH result; + + /* + * This logic will not work for gatt case. We are checking against the bluetooth profiles here + * just copy the GATTID in raw data field and send it across. + */ + + + if ( bta_dm_search_cb.ble_raw_used + sizeof(tBTA_GATT_ID) < bta_dm_search_cb.ble_raw_size ) + { + APPL_TRACE_DEBUG("ADDING BLE SERVICE uuid=0x%x, ble_ptr = 0x%x, ble_raw_used = 0x%x", + service_id.uuid.uu.uuid16,bta_dm_search_cb.p_ble_rawdata,bta_dm_search_cb.ble_raw_used); + + if(bta_dm_search_cb.p_ble_rawdata) + { + memcpy((bta_dm_search_cb.p_ble_rawdata + bta_dm_search_cb.ble_raw_used), &service_id, + sizeof(service_id) ); + + bta_dm_search_cb.ble_raw_used += sizeof(service_id); + } + else + { + APPL_TRACE_ERROR("p_ble_rawdata is NULL"); + } + + } + else + { + APPL_TRACE_ERROR("%s out of room to accomodate more service ids ble_raw_size = %d ble_raw_used = %d", __FUNCTION__,bta_dm_search_cb.ble_raw_size, bta_dm_search_cb.ble_raw_used ); + } + + LOG_INFO("%s service_id_uuid_len=%d ", __func__, service_id.uuid.len); + if ( bta_dm_search_cb.state != BTA_DM_SEARCH_IDLE) + { + + /* send result back to app now, one by one */ + bdcpy (result.disc_ble_res.bd_addr, bta_dm_search_cb.peer_bdaddr); + BCM_STRNCPY_S((char*)result.disc_ble_res.bd_name, sizeof(BD_NAME), bta_dm_get_remname(), (BD_NAME_LEN-1)); + result.disc_ble_res.bd_name[BD_NAME_LEN] = 0; + memcpy(&result.disc_ble_res.service, &service_id.uuid, sizeof(tBT_UUID)); + + bta_dm_search_cb.p_search_cback(BTA_DM_DISC_BLE_RES_EVT, &result); + } +} + +/******************************************************************************* +** +** Function bta_dm_gatt_disc_complete +** +** Description This function process the GATT service search complete. +** +** Parameters: +** +*******************************************************************************/ +static void bta_dm_gatt_disc_complete(UINT16 conn_id, tBTA_GATT_STATUS status) +{ + tBTA_DM_MSG *p_msg; + + APPL_TRACE_DEBUG("bta_dm_gatt_disc_complete conn_id = %d",conn_id); + + if (bta_dm_search_cb.uuid_to_search > 0) bta_dm_search_cb.uuid_to_search --; + + if (status == BTA_GATT_OK && bta_dm_search_cb.uuid_to_search > 0) + { + btm_dm_start_disc_gatt_services(conn_id); + } + else + { + bta_dm_search_cb.uuid_to_search = 0; + + /* no more services to be discovered */ + if ((p_msg = (tBTA_DM_MSG *) GKI_getbuf(sizeof(tBTA_DM_MSG))) != NULL) + { + p_msg->hdr.event = BTA_DM_DISCOVERY_RESULT_EVT; + p_msg->disc_result.result.disc_res.result = (status == BTA_GATT_OK) ? BTA_SUCCESS :BTA_FAILURE; + APPL_TRACE_DEBUG("%s service found: 0x%08x", __FUNCTION__, + bta_dm_search_cb.services_found); + p_msg->disc_result.result.disc_res.services = bta_dm_search_cb.services_found; + p_msg->disc_result.result.disc_res.num_uuids = 0; + p_msg->disc_result.result.disc_res.p_uuid_list = NULL; + bdcpy (p_msg->disc_result.result.disc_res.bd_addr, bta_dm_search_cb.peer_bdaddr); + BCM_STRNCPY_S((char*)p_msg->disc_result.result.disc_res.bd_name, sizeof(BD_NAME), + bta_dm_get_remname(), (BD_NAME_LEN-1)); + + /* make sure the string is terminated */ + p_msg->disc_result.result.disc_res.bd_name[BD_NAME_LEN-1] = 0; + + p_msg->disc_result.result.disc_res.device_type |= BT_DEVICE_TYPE_BLE; + if ( bta_dm_search_cb.ble_raw_used > 0 ) + { + p_msg->disc_result.result.disc_res.p_raw_data = GKI_getbuf(bta_dm_search_cb.ble_raw_used); + + memcpy( p_msg->disc_result.result.disc_res.p_raw_data, + bta_dm_search_cb.p_ble_rawdata, + bta_dm_search_cb.ble_raw_used ); + + p_msg->disc_result.result.disc_res.raw_data_size = bta_dm_search_cb.ble_raw_used; + } + else + { + p_msg->disc_result.result.disc_res.p_raw_data = NULL; + bta_dm_search_cb.p_ble_rawdata = 0; + } + + bta_sys_sendmsg(p_msg); + } + + if (conn_id != BTA_GATT_INVALID_CONN_ID) + { + /* start a GATT channel close delay timer */ + bta_sys_start_timer(&bta_dm_search_cb.gatt_close_timer, BTA_DM_DISC_CLOSE_TOUT_EVT, + BTA_DM_GATT_CLOSE_DELAY_TOUT); + bdcpy(bta_dm_search_cb.pending_close_bda, bta_dm_search_cb.peer_bdaddr); + } + bta_dm_search_cb.gatt_disc_active = FALSE; + } +} + +/******************************************************************************* +** +** Function bta_dm_close_gatt_conn +** +** Description This function close the GATT connection after delay timeout. +** +** Parameters: +** +*******************************************************************************/ +void bta_dm_close_gatt_conn(tBTA_DM_MSG *p_data) +{ + UNUSED(p_data); + + if (bta_dm_search_cb.conn_id != BTA_GATT_INVALID_CONN_ID) + BTA_GATTC_Close(bta_dm_search_cb.conn_id); + + memset(bta_dm_search_cb.pending_close_bda, 0, BD_ADDR_LEN); + bta_dm_search_cb.conn_id = BTA_GATT_INVALID_CONN_ID; +} +/******************************************************************************* +** +** Function btm_dm_start_gatt_discovery +** +** Description This is GATT initiate the service search by open a GATT connection +** first. +** +** Parameters: +** +*******************************************************************************/ +void btm_dm_start_gatt_discovery (BD_ADDR bd_addr) +{ + bta_dm_search_cb.gatt_disc_active = TRUE; + + /* connection is already open */ + if (bdcmp(bta_dm_search_cb.pending_close_bda, bd_addr) == 0 && + bta_dm_search_cb.conn_id != BTA_GATT_INVALID_CONN_ID) + { + memset(bta_dm_search_cb.pending_close_bda, 0, BD_ADDR_LEN); + bta_sys_stop_timer(&bta_dm_search_cb.gatt_close_timer); + btm_dm_start_disc_gatt_services(bta_dm_search_cb.conn_id); + } + else + BTA_GATTC_Open(bta_dm_search_cb.client_if, bd_addr, TRUE, BTA_GATT_TRANSPORT_LE); +} + +/******************************************************************************* +** +** Function bta_dm_cancel_gatt_discovery +** +** Description This is GATT cancel the GATT service search. +** +** Parameters: +** +*******************************************************************************/ +static void bta_dm_cancel_gatt_discovery(BD_ADDR bd_addr) +{ + if (bta_dm_search_cb.conn_id == BTA_GATT_INVALID_CONN_ID) + { + BTA_GATTC_CancelOpen(bta_dm_search_cb.client_if, bd_addr, TRUE); + } + + bta_dm_gatt_disc_complete(bta_dm_search_cb.conn_id, (tBTA_GATT_STATUS) BTA_GATT_ERROR); +} + +/******************************************************************************* +** +** Function bta_dm_proc_open_evt +** +** Description process BTA_GATTC_OPEN_EVT in DM. +** +** Parameters: +** +*******************************************************************************/ +void bta_dm_proc_open_evt(tBTA_GATTC_OPEN *p_data) +{ + UINT8 *p1; + UINT8 *p2; + + p1 = bta_dm_search_cb.peer_bdaddr; + p2 = p_data->remote_bda; + + APPL_TRACE_DEBUG("DM Search state= %d search_cb.peer_dbaddr: [%08x%04x] connected_bda= [%08x%04x] ", + bta_dm_search_cb.state, + ((p1[0])<<24)+((p1[1])<<16)+((p1[2])<<8)+(p1[3]), + ((p1[4])<<8)+ p1[5], + ((p2[0])<<24)+((p2[1])<<16)+((p2[2])<<8)+(p2[3]), + ((p2[4])<<8)+ p2[5]); + + APPL_TRACE_DEBUG("BTA_GATTC_OPEN_EVT conn_id = %d client_if=%d status = %d" , + p_data->conn_id, + p_data->client_if, + p_data->status); + + bta_dm_search_cb.conn_id = p_data->conn_id; + + if (p_data->status == BTA_GATT_OK) + { + btm_dm_start_disc_gatt_services(p_data->conn_id); + } + else + { + bta_dm_gatt_disc_complete(BTA_GATT_INVALID_CONN_ID, p_data->status); + } +} + +/******************************************************************************* +** +** Function bta_dm_gattc_callback +** +** Description This is GATT client callback function used in DM. +** +** Parameters: +** +*******************************************************************************/ +static void bta_dm_gattc_callback(tBTA_GATTC_EVT event, tBTA_GATTC *p_data) +{ + APPL_TRACE_DEBUG("bta_dm_gattc_callback event = %d", event); + + switch (event) + { + case BTA_GATTC_REG_EVT: + APPL_TRACE_DEBUG("BTA_GATTC_REG_EVT client_if = %d", p_data->reg_oper.client_if); + if (p_data->reg_oper.status == BTA_GATT_OK) + bta_dm_search_cb.client_if = p_data->reg_oper.client_if; + else + bta_dm_search_cb.client_if = BTA_GATTS_INVALID_IF; + break; + + case BTA_GATTC_OPEN_EVT: + bta_dm_proc_open_evt(&p_data->open); + break; + + case BTA_GATTC_SEARCH_RES_EVT: + bta_dm_gatt_disc_result(p_data->srvc_res.service_uuid.id); + break; + + case BTA_GATTC_SEARCH_CMPL_EVT: + if ( bta_dm_search_cb.state != BTA_DM_SEARCH_IDLE) + bta_dm_gatt_disc_complete(p_data->search_cmpl.conn_id, p_data->search_cmpl.status); + break; + + case BTA_GATTC_CLOSE_EVT: + APPL_TRACE_DEBUG("BTA_GATTC_CLOSE_EVT reason = %d", p_data->close.reason); + /* in case of disconnect before search is completed */ + if ( (bta_dm_search_cb.state != BTA_DM_SEARCH_IDLE) && + (bta_dm_search_cb.state != BTA_DM_SEARCH_ACTIVE) && + !memcmp(p_data->close.remote_bda, bta_dm_search_cb.peer_bdaddr, BD_ADDR_LEN)) + { + bta_dm_gatt_disc_complete((UINT16)BTA_GATT_INVALID_CONN_ID, (tBTA_GATT_STATUS) BTA_GATT_ERROR); + } + break; + + default: + break; + } +} + +#endif /* BTA_GATT_INCLUDED */ + +#if BLE_VND_INCLUDED == TRUE +/******************************************************************************* +** +** Function bta_dm_ctrl_features_rd_cmpl_cback +** +** Description callback to handle controller feature read complete +** +** Parameters: +** +*******************************************************************************/ +static void bta_dm_ctrl_features_rd_cmpl_cback(tBTM_STATUS result) +{ + APPL_TRACE_DEBUG("%s status = %d ", __FUNCTION__, result); + if (result == BTM_SUCCESS) + { + if(bta_dm_cb.p_sec_cback) + bta_dm_cb.p_sec_cback(BTA_DM_LE_FEATURES_READ, NULL); + } + else + { + APPL_TRACE_ERROR("%s Ctrl BLE feature read failed: status :%d",__FUNCTION__, result); + } + +} +#endif /* BLE_VND_INCLUDED */ + +#endif /* BLE_INCLUDED */ diff --git a/components/bt/bluedroid/bta/dm/bta_dm_api.c b/components/bt/bluedroid/bta/dm/bta_dm_api.c new file mode 100755 index 0000000000..959c975855 --- /dev/null +++ b/components/bt/bluedroid/bta/dm/bta_dm_api.c @@ -0,0 +1,2165 @@ +/****************************************************************************** + * + * Copyright (C) 2003-2014 Broadcom Corporation + * + * 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 is the API implementation file for the BTA device manager. + * + ******************************************************************************/ + +#include "gki.h" +#include "bta_sys.h" +#include "bta_api.h" +#include "bta_dm_int.h" +#include "bta_sys_int.h" +#include "btm_api.h" +#include "btm_int.h" +#include +#include "utl.h" + +/***************************************************************************** +** Constants +*****************************************************************************/ + +static const tBTA_SYS_REG bta_dm_reg = +{ + bta_dm_sm_execute, + bta_dm_sm_disable +}; + +static const tBTA_SYS_REG bta_dm_search_reg = +{ + bta_dm_search_sm_execute, + bta_dm_search_sm_disable +}; + +/******************************************************************************* +** +** Function BTA_EnableBluetooth +** +** Description Enables bluetooth service. This function must be +** called before any other functions in the BTA API are called. +** +** +** Returns tBTA_STATUS +** +*******************************************************************************/ +tBTA_STATUS BTA_EnableBluetooth(tBTA_DM_SEC_CBACK *p_cback) +{ + + tBTA_DM_API_ENABLE *p_msg; + + /* Bluetooth disabling is in progress */ + if (bta_dm_cb.disabling) + return BTA_FAILURE; + + memset(&bta_dm_cb, 0, sizeof(bta_dm_cb)); + + bta_sys_register (BTA_ID_DM, &bta_dm_reg ); + bta_sys_register (BTA_ID_DM_SEARCH, &bta_dm_search_reg ); + + /* if UUID list is not provided as static data */ + bta_sys_eir_register(bta_dm_eir_update_uuid); + + if ((p_msg = (tBTA_DM_API_ENABLE *) GKI_getbuf(sizeof(tBTA_DM_API_ENABLE))) != NULL) + { + p_msg->hdr.event = BTA_DM_API_ENABLE_EVT; + p_msg->p_sec_cback = p_cback; + bta_sys_sendmsg(p_msg); + return BTA_SUCCESS; + } + return BTA_FAILURE; + +} + +/******************************************************************************* +** +** Function BTA_DisableBluetooth +** +** Description Disables bluetooth service. This function is called when +** the application no longer needs bluetooth service +** +** Returns void +** +*******************************************************************************/ +tBTA_STATUS BTA_DisableBluetooth(void) +{ + + BT_HDR *p_msg; + + if ((p_msg = (BT_HDR *) GKI_getbuf(sizeof(BT_HDR))) != NULL) + { + p_msg->event = BTA_DM_API_DISABLE_EVT; + bta_sys_sendmsg(p_msg); + } + else + { + return BTA_FAILURE; + } + + return BTA_SUCCESS; +} + +/******************************************************************************* +** +** Function BTA_EnableTestMode +** +** Description Enables bluetooth device under test mode +** +** +** Returns tBTA_STATUS +** +*******************************************************************************/ +tBTA_STATUS BTA_EnableTestMode(void) +{ + BT_HDR *p_msg; + + APPL_TRACE_API("BTA_EnableTestMode"); + + if ((p_msg = (BT_HDR *) GKI_getbuf(sizeof(BT_HDR))) != NULL) + { + p_msg->event = BTA_DM_API_ENABLE_TEST_MODE_EVT; + bta_sys_sendmsg(p_msg); + return BTA_SUCCESS; + } + return BTA_FAILURE; +} + +/******************************************************************************* +** +** Function BTA_DisableTestMode +** +** Description Disable bluetooth device under test mode +** +** +** Returns None +** +*******************************************************************************/ +void BTA_DisableTestMode(void) +{ + BT_HDR *p_msg; + + APPL_TRACE_API("BTA_DisableTestMode"); + + if ((p_msg = (BT_HDR *) GKI_getbuf(sizeof(BT_HDR))) != NULL) + { + p_msg->event = BTA_DM_API_DISABLE_TEST_MODE_EVT; + bta_sys_sendmsg(p_msg); + } +} + +/******************************************************************************* +** +** Function BTA_DmSetDeviceName +** +** Description This function sets the Bluetooth name of local device +** +** +** Returns void +** +*******************************************************************************/ +void BTA_DmSetDeviceName(char *p_name) +{ + + tBTA_DM_API_SET_NAME *p_msg; + + if ((p_msg = (tBTA_DM_API_SET_NAME *) GKI_getbuf(sizeof(tBTA_DM_API_SET_NAME))) != NULL) + { + p_msg->hdr.event = BTA_DM_API_SET_NAME_EVT; + /* truncate the name if needed */ + BCM_STRNCPY_S((char*)p_msg->name, sizeof(p_msg->name), p_name, BD_NAME_LEN-1); + p_msg->name[BD_NAME_LEN-1]=0; + + bta_sys_sendmsg(p_msg); + } + + +} + +/******************************************************************************* +** +** Function BTA_DmSetVisibility +** +** Description This function sets the Bluetooth connectable, +** discoverable, pairable and conn paired only modes of local device +** +** +** Returns void +** +*******************************************************************************/ +void BTA_DmSetVisibility(tBTA_DM_DISC disc_mode, tBTA_DM_CONN conn_mode, UINT8 pairable_mode, UINT8 conn_filter ) +{ + + tBTA_DM_API_SET_VISIBILITY *p_msg; + + if ((p_msg = (tBTA_DM_API_SET_VISIBILITY *) GKI_getbuf(sizeof(tBTA_DM_MSG))) != NULL) + { + p_msg->hdr.event = BTA_DM_API_SET_VISIBILITY_EVT; + p_msg->disc_mode = disc_mode; + p_msg->conn_mode = conn_mode; + p_msg->pair_mode = pairable_mode; + p_msg->conn_paired_only = conn_filter; + + + bta_sys_sendmsg(p_msg); + } + + +} + +/******************************************************************************* +** +** Function BTA_DmSearch +** +** Description This function searches for peer Bluetooth devices. It performs +** an inquiry and gets the remote name for devices. Service +** discovery is done if services is non zero +** +** +** Returns void +** +*******************************************************************************/ +void BTA_DmSearch(tBTA_DM_INQ *p_dm_inq, tBTA_SERVICE_MASK services, tBTA_DM_SEARCH_CBACK *p_cback) +{ + + tBTA_DM_API_SEARCH *p_msg; + + if ((p_msg = (tBTA_DM_API_SEARCH *) GKI_getbuf(sizeof(tBTA_DM_API_SEARCH))) != NULL) + { + memset(p_msg, 0, sizeof(tBTA_DM_API_SEARCH)); + + p_msg->hdr.event = BTA_DM_API_SEARCH_EVT; + memcpy(&p_msg->inq_params, p_dm_inq, sizeof(tBTA_DM_INQ)); + p_msg->services = services; + p_msg->p_cback = p_cback; + p_msg->rs_res = BTA_DM_RS_NONE; + bta_sys_sendmsg(p_msg); + } + +} + + +/******************************************************************************* +** +** Function BTA_DmSearchCancel +** +** Description This function cancels a search initiated by BTA_DmSearch +** +** +** Returns void +** +*******************************************************************************/ +void BTA_DmSearchCancel(void) +{ + BT_HDR *p_msg; + + if ((p_msg = (BT_HDR *) GKI_getbuf(sizeof(BT_HDR))) != NULL) + { + p_msg->event = BTA_DM_API_SEARCH_CANCEL_EVT; + bta_sys_sendmsg(p_msg); + } + +} + +/******************************************************************************* +** +** Function BTA_DmDiscover +** +** Description This function does service discovery for services of a +** peer device +** +** +** Returns void +** +*******************************************************************************/ +void BTA_DmDiscover(BD_ADDR bd_addr, tBTA_SERVICE_MASK services, + tBTA_DM_SEARCH_CBACK *p_cback, BOOLEAN sdp_search) +{ + tBTA_DM_API_DISCOVER *p_msg; + + if ((p_msg = (tBTA_DM_API_DISCOVER *) GKI_getbuf(sizeof(tBTA_DM_API_DISCOVER))) != NULL) + { + memset(p_msg, 0, sizeof(tBTA_DM_API_DISCOVER)); + + p_msg->hdr.event = BTA_DM_API_DISCOVER_EVT; + bdcpy(p_msg->bd_addr, bd_addr); + p_msg->services = services; + p_msg->p_cback = p_cback; + p_msg->sdp_search = sdp_search; + bta_sys_sendmsg(p_msg); + } + +} + +/******************************************************************************* +** +** Function BTA_DmDiscoverUUID +** +** Description This function does service discovery for services of a +** peer device +** +** +** Returns void +** +*******************************************************************************/ +void BTA_DmDiscoverUUID(BD_ADDR bd_addr, tSDP_UUID *uuid, + tBTA_DM_SEARCH_CBACK *p_cback, BOOLEAN sdp_search) +{ + tBTA_DM_API_DISCOVER *p_msg; + + if ((p_msg = (tBTA_DM_API_DISCOVER *) GKI_getbuf(sizeof(tBTA_DM_API_DISCOVER))) != NULL) + { + p_msg->hdr.event = BTA_DM_API_DISCOVER_EVT; + bdcpy(p_msg->bd_addr, bd_addr); + p_msg->services = BTA_USER_SERVICE_MASK; //Not exposed at API level + p_msg->p_cback = p_cback; + p_msg->sdp_search = sdp_search; + +#if BLE_INCLUDED == TRUE && BTA_GATT_INCLUDED == TRUE + p_msg->num_uuid = 0; + p_msg->p_uuid = NULL; +#endif + memcpy( &p_msg->uuid, uuid, sizeof(tSDP_UUID) ); + bta_sys_sendmsg(p_msg); + } + +} + +/******************************************************************************* +** +** Function BTA_DmBond +** +** Description This function initiates a bonding procedure with a peer +** device +** +** +** Returns void +** +*******************************************************************************/ +void BTA_DmBond(BD_ADDR bd_addr) +{ + tBTA_DM_API_BOND *p_msg; + + p_msg = (tBTA_DM_API_BOND *) GKI_getbuf(sizeof(tBTA_DM_API_BOND)); + if (p_msg != NULL) + { + p_msg->hdr.event = BTA_DM_API_BOND_EVT; + bdcpy(p_msg->bd_addr, bd_addr); + p_msg->transport = BTA_TRANSPORT_UNKNOWN; + bta_sys_sendmsg(p_msg); + } +} + +/******************************************************************************* +** +** Function BTA_DmBondByTransports +** +** Description This function initiates a bonding procedure with a peer +** device +** +** +** Returns void +** +*******************************************************************************/ +void BTA_DmBondByTransport(BD_ADDR bd_addr, tBTA_TRANSPORT transport) +{ + tBTA_DM_API_BOND *p_msg; + + if ((p_msg = (tBTA_DM_API_BOND *) GKI_getbuf(sizeof(tBTA_DM_API_BOND))) != NULL) + { + p_msg->hdr.event = BTA_DM_API_BOND_EVT; + bdcpy(p_msg->bd_addr, bd_addr); + p_msg->transport = transport; + bta_sys_sendmsg(p_msg); + } + + +} + +/******************************************************************************* +** +** Function BTA_DmBondCancel +** +** Description This function cancels the bonding procedure with a peer +** device +** +** +** Returns void +** +*******************************************************************************/ +void BTA_DmBondCancel(BD_ADDR bd_addr) +{ + tBTA_DM_API_BOND_CANCEL *p_msg; + + if ((p_msg = (tBTA_DM_API_BOND_CANCEL *) GKI_getbuf(sizeof(tBTA_DM_API_BOND_CANCEL))) != NULL) + { + p_msg->hdr.event = BTA_DM_API_BOND_CANCEL_EVT; + bdcpy(p_msg->bd_addr, bd_addr); + bta_sys_sendmsg(p_msg); + } + + +} + +/******************************************************************************* +** +** Function BTA_DmPinReply +** +** Description This function provides a pincode for a remote device when +** one is requested by DM through BTA_DM_PIN_REQ_EVT +** +** +** Returns void +** +*******************************************************************************/ +void BTA_DmPinReply(BD_ADDR bd_addr, BOOLEAN accept, UINT8 pin_len, UINT8 *p_pin) + +{ + tBTA_DM_API_PIN_REPLY *p_msg; + + if ((p_msg = (tBTA_DM_API_PIN_REPLY *) GKI_getbuf(sizeof(tBTA_DM_API_PIN_REPLY))) != NULL) + { + p_msg->hdr.event = BTA_DM_API_PIN_REPLY_EVT; + bdcpy(p_msg->bd_addr, bd_addr); + p_msg->accept = accept; + if(accept) + { + p_msg->pin_len = pin_len; + memcpy(p_msg->p_pin, p_pin, pin_len); + } + bta_sys_sendmsg(p_msg); + } + +} + +#if (BTM_OOB_INCLUDED == TRUE) +/******************************************************************************* +** +** Function BTA_DmLocalOob +** +** Description This function retrieves the OOB data from local controller. +** The result is reported by: +** - bta_dm_co_loc_oob_ext() if device supports secure +** connections (SC) +** - bta_dm_co_loc_oob() if device doesn't support SC +** +** Returns void +** +*******************************************************************************/ +void BTA_DmLocalOob(void) +{ + tBTA_DM_API_LOC_OOB *p_msg; + + if ((p_msg = (tBTA_DM_API_LOC_OOB *) GKI_getbuf(sizeof(tBTA_DM_API_LOC_OOB))) != NULL) + { + p_msg->hdr.event = BTA_DM_API_LOC_OOB_EVT; + bta_sys_sendmsg(p_msg); + } +} +#endif /* BTM_OOB_INCLUDED */ +/******************************************************************************* +** +** Function BTA_DmConfirm +** +** Description This function accepts or rejects the numerical value of the +** Simple Pairing process on BTA_DM_SP_CFM_REQ_EVT +** +** Returns void +** +*******************************************************************************/ +void BTA_DmConfirm(BD_ADDR bd_addr, BOOLEAN accept) +{ + tBTA_DM_API_CONFIRM *p_msg; + + if ((p_msg = (tBTA_DM_API_CONFIRM *) GKI_getbuf(sizeof(tBTA_DM_API_CONFIRM))) != NULL) + { + p_msg->hdr.event = BTA_DM_API_CONFIRM_EVT; + bdcpy(p_msg->bd_addr, bd_addr); + p_msg->accept = accept; + bta_sys_sendmsg(p_msg); + } +} + +/******************************************************************************* +** +** Function BTA_DmAddDevice +** +** Description This function adds a device to the security database list of +** peer device +** +** +** Returns void +** +*******************************************************************************/ +void BTA_DmAddDevice(BD_ADDR bd_addr, DEV_CLASS dev_class, LINK_KEY link_key, + tBTA_SERVICE_MASK trusted_mask, BOOLEAN is_trusted, + UINT8 key_type, tBTA_IO_CAP io_cap, UINT8 pin_length) +{ + + tBTA_DM_API_ADD_DEVICE *p_msg; + + if ((p_msg = (tBTA_DM_API_ADD_DEVICE *) GKI_getbuf(sizeof(tBTA_DM_API_ADD_DEVICE))) != NULL) + { + memset (p_msg, 0, sizeof(tBTA_DM_API_ADD_DEVICE)); + + p_msg->hdr.event = BTA_DM_API_ADD_DEVICE_EVT; + bdcpy(p_msg->bd_addr, bd_addr); + p_msg->tm = trusted_mask; + p_msg->is_trusted = is_trusted; + p_msg->io_cap = io_cap; + + if (link_key) + { + p_msg->link_key_known = TRUE; + p_msg->key_type = key_type; + memcpy(p_msg->link_key, link_key, LINK_KEY_LEN); + } + + /* Load device class if specified */ + if (dev_class) + { + p_msg->dc_known = TRUE; + memcpy (p_msg->dc, dev_class, DEV_CLASS_LEN); + } + + memset (p_msg->bd_name, 0, BD_NAME_LEN + 1); + memset (p_msg->features, 0, sizeof (p_msg->features)); + p_msg->pin_length = pin_length; + + bta_sys_sendmsg(p_msg); + } +} + + +/******************************************************************************* +** +** Function BTA_DmRemoveDevice +** +** Description This function removes a device fromthe security database list of +** peer device. It manages unpairing even while connected. +** +** +** Returns void +** +*******************************************************************************/ +tBTA_STATUS BTA_DmRemoveDevice(BD_ADDR bd_addr) +{ + tBTA_DM_API_REMOVE_DEVICE *p_msg; + + if ((p_msg = (tBTA_DM_API_REMOVE_DEVICE *) GKI_getbuf(sizeof(tBTA_DM_API_REMOVE_DEVICE))) != NULL) + { + memset (p_msg, 0, sizeof(tBTA_DM_API_REMOVE_DEVICE)); + + p_msg->hdr.event = BTA_DM_API_REMOVE_DEVICE_EVT; + bdcpy(p_msg->bd_addr, bd_addr); + bta_sys_sendmsg(p_msg); + } + else + { + return BTA_FAILURE; + } + + return BTA_SUCCESS; +} + +/******************************************************************************* +** +** Function BTA_GetEirService +** +** Description This function is called to get BTA service mask from EIR. +** +** Parameters p_eir - pointer of EIR significant part +** p_services - return the BTA service mask +** +** Returns None +** +*******************************************************************************/ +extern const UINT16 bta_service_id_to_uuid_lkup_tbl []; +void BTA_GetEirService( UINT8 *p_eir, tBTA_SERVICE_MASK *p_services ) +{ + UINT8 xx, yy; + UINT8 num_uuid, max_num_uuid = 32; + UINT8 uuid_list[32*LEN_UUID_16]; + UINT16 *p_uuid16 = (UINT16 *)uuid_list; + tBTA_SERVICE_MASK mask; + + BTM_GetEirUuidList( p_eir, LEN_UUID_16, &num_uuid, uuid_list, max_num_uuid); + for( xx = 0; xx < num_uuid; xx++ ) + { + mask = 1; + for( yy = 0; yy < BTA_MAX_SERVICE_ID; yy++ ) + { + if( *(p_uuid16 + xx) == bta_service_id_to_uuid_lkup_tbl[yy] ) + { + *p_services |= mask; + break; + } + mask <<= 1; + } + + /* for HSP v1.2 only device */ + if (*(p_uuid16 + xx) == UUID_SERVCLASS_HEADSET_HS) + *p_services |= BTA_HSP_SERVICE_MASK; + + if (*(p_uuid16 + xx) == UUID_SERVCLASS_HDP_SOURCE) + *p_services |= BTA_HL_SERVICE_MASK; + + if (*(p_uuid16 + xx) == UUID_SERVCLASS_HDP_SINK) + *p_services |= BTA_HL_SERVICE_MASK; + } +} + +/******************************************************************************* +** +** Function BTA_DmGetConnectionState +** +** Description Returns whether the remote device is currently connected. +** +** Returns 0 if the device is NOT connected. +** +*******************************************************************************/ +UINT16 BTA_DmGetConnectionState( BD_ADDR bd_addr ) +{ + tBTA_DM_PEER_DEVICE * p_dev = bta_dm_find_peer_device(bd_addr); + return (p_dev && p_dev->conn_state == BTA_DM_CONNECTED); +} + + +/******************************************************************************* +** Device Identification (DI) Server Functions +*******************************************************************************/ +/******************************************************************************* +** +** Function BTA_DmSetLocalDiRecord +** +** Description This function adds a DI record to the local SDP database. +** +** Returns BTA_SUCCESS if record set sucessfully, otherwise error code. +** +*******************************************************************************/ +tBTA_STATUS BTA_DmSetLocalDiRecord( tBTA_DI_RECORD *p_device_info, + UINT32 *p_handle ) +{ + tBTA_STATUS status = BTA_FAILURE; + + if(bta_dm_di_cb.di_num < BTA_DI_NUM_MAX) + { + if(SDP_SetLocalDiRecord((tSDP_DI_RECORD *)p_device_info, p_handle) == SDP_SUCCESS) + { + if(!p_device_info->primary_record) + { + bta_dm_di_cb.di_handle[bta_dm_di_cb.di_num] = *p_handle; + bta_dm_di_cb.di_num ++; + } + + bta_sys_add_uuid(UUID_SERVCLASS_PNP_INFORMATION); + status = BTA_SUCCESS; + } + } + + return status; +} + +/******************************************************************************* +** +** Function bta_dmexecutecallback +** +** Description This function will request BTA to execute a call back in the context of BTU task +** This API was named in lower case because it is only intended +** for the internal customers(like BTIF). +** +** Returns void +** +*******************************************************************************/ +void bta_dmexecutecallback (tBTA_DM_EXEC_CBACK* p_callback, void * p_param) +{ + tBTA_DM_API_EXECUTE_CBACK *p_msg; + + if ((p_msg = (tBTA_DM_API_EXECUTE_CBACK *) GKI_getbuf(sizeof(tBTA_DM_MSG))) != NULL) + { + p_msg->hdr.event = BTA_DM_API_EXECUTE_CBACK_EVT; + p_msg->p_param= p_param; + p_msg->p_exec_cback= p_callback; + bta_sys_sendmsg(p_msg); + } +} + +/******************************************************************************* +** +** Function BTA_DmAddBleKey +** +** Description Add/modify LE device information. This function will be +** normally called during host startup to restore all required +** information stored in the NVRAM. +** +** Parameters: bd_addr - BD address of the peer +** p_le_key - LE key values. +** key_type - LE SMP key type. +** +** Returns BTA_SUCCESS if successful +** BTA_FAIL if operation failed. +** +*******************************************************************************/ +void BTA_DmAddBleKey (BD_ADDR bd_addr, tBTA_LE_KEY_VALUE *p_le_key, tBTA_LE_KEY_TYPE key_type) +{ +#if BLE_INCLUDED == TRUE + + tBTA_DM_API_ADD_BLEKEY *p_msg; + + if ((p_msg = (tBTA_DM_API_ADD_BLEKEY *) GKI_getbuf(sizeof(tBTA_DM_API_ADD_BLEKEY))) != NULL) + { + memset (p_msg, 0, sizeof(tBTA_DM_API_ADD_BLEKEY)); + + p_msg->hdr.event = BTA_DM_API_ADD_BLEKEY_EVT; + p_msg->key_type = key_type; + bdcpy(p_msg->bd_addr, bd_addr); + memcpy(&p_msg->blekey, p_le_key, sizeof(tBTA_LE_KEY_VALUE)); + + bta_sys_sendmsg(p_msg); + } + +#endif +} + +/******************************************************************************* +** +** Function BTA_DmAddBleDevice +** +** Description Add a BLE device. This function will be normally called +** during host startup to restore all required information +** for a LE device stored in the NVRAM. +** +** Parameters: bd_addr - BD address of the peer +** dev_type - Remote device's device type. +** addr_type - LE device address type. +** +** Returns void +** +*******************************************************************************/ +void BTA_DmAddBleDevice(BD_ADDR bd_addr, tBLE_ADDR_TYPE addr_type, tBT_DEVICE_TYPE dev_type) +{ +#if BLE_INCLUDED == TRUE + tBTA_DM_API_ADD_BLE_DEVICE *p_msg; + + if ((p_msg = (tBTA_DM_API_ADD_BLE_DEVICE *) GKI_getbuf(sizeof(tBTA_DM_API_ADD_BLE_DEVICE))) != NULL) + { + memset (p_msg, 0, sizeof(tBTA_DM_API_ADD_BLE_DEVICE)); + + p_msg->hdr.event = BTA_DM_API_ADD_BLEDEVICE_EVT; + bdcpy(p_msg->bd_addr, bd_addr); + p_msg->addr_type = addr_type; + p_msg->dev_type = dev_type; + + bta_sys_sendmsg(p_msg); + } +#endif +} +/******************************************************************************* +** +** Function BTA_DmBlePasskeyReply +** +** Description Send BLE SMP passkey reply. +** +** Parameters: bd_addr - BD address of the peer +** accept - passkey entry sucessful or declined. +** passkey - passkey value, must be a 6 digit number, +** can be lead by 0. +** +** Returns void +** +*******************************************************************************/ +void BTA_DmBlePasskeyReply(BD_ADDR bd_addr, BOOLEAN accept, UINT32 passkey) +{ +#if BLE_INCLUDED == TRUE + tBTA_DM_API_PASSKEY_REPLY *p_msg; + + if ((p_msg = (tBTA_DM_API_PASSKEY_REPLY *) GKI_getbuf(sizeof(tBTA_DM_API_PASSKEY_REPLY))) != NULL) + { + memset(p_msg, 0, sizeof(tBTA_DM_API_PASSKEY_REPLY)); + + p_msg->hdr.event = BTA_DM_API_BLE_PASSKEY_REPLY_EVT; + bdcpy(p_msg->bd_addr, bd_addr); + p_msg->accept = accept; + + if(accept) + { + p_msg->passkey = passkey; + } + bta_sys_sendmsg(p_msg); + } +#endif +} +/******************************************************************************* +** +** Function BTA_DmBleConfirmReply +** +** Description Send BLE SMP SC user confirmation reply. +** +** Parameters: bd_addr - BD address of the peer +** accept - numbers to compare are the same or different. +** +** Returns void +** +*******************************************************************************/ +void BTA_DmBleConfirmReply(BD_ADDR bd_addr, BOOLEAN accept) +{ +#if BLE_INCLUDED == TRUE + tBTA_DM_API_CONFIRM *p_msg = (tBTA_DM_API_CONFIRM *)GKI_getbuf(sizeof(tBTA_DM_API_CONFIRM)); + if (p_msg != NULL) + { + memset(p_msg, 0, sizeof(tBTA_DM_API_CONFIRM)); + p_msg->hdr.event = BTA_DM_API_BLE_CONFIRM_REPLY_EVT; + bdcpy(p_msg->bd_addr, bd_addr); + p_msg->accept = accept; + bta_sys_sendmsg(p_msg); + } +#endif +} + +/******************************************************************************* +** +** Function BTA_DmBleSecurityGrant +** +** Description Grant security request access. +** +** Parameters: bd_addr - BD address of the peer +** res - security grant status. +** +** Returns void +** +*******************************************************************************/ +void BTA_DmBleSecurityGrant(BD_ADDR bd_addr, tBTA_DM_BLE_SEC_GRANT res) +{ +#if BLE_INCLUDED == TRUE + tBTA_DM_API_BLE_SEC_GRANT *p_msg; + + if ((p_msg = (tBTA_DM_API_BLE_SEC_GRANT *) GKI_getbuf(sizeof(tBTA_DM_API_BLE_SEC_GRANT))) != NULL) + { + memset(p_msg, 0, sizeof(tBTA_DM_API_BLE_SEC_GRANT)); + + p_msg->hdr.event = BTA_DM_API_BLE_SEC_GRANT_EVT; + bdcpy(p_msg->bd_addr, bd_addr); + p_msg->res = res; + + bta_sys_sendmsg(p_msg); + } +#endif +} +/******************************************************************************* +** +** Function BTA_DmSetBlePrefConnParams +** +** Description This function is called to set the preferred connection +** parameters when default connection parameter is not desired. +** +** Parameters: bd_addr - BD address of the peripheral +** scan_interval - scan interval +** scan_window - scan window +** min_conn_int - minimum preferred connection interval +** max_conn_int - maximum preferred connection interval +** slave_latency - preferred slave latency +** supervision_tout - preferred supervision timeout +** +** +** Returns void +** +*******************************************************************************/ +void BTA_DmSetBlePrefConnParams(BD_ADDR bd_addr, + UINT16 min_conn_int, UINT16 max_conn_int, + UINT16 slave_latency, UINT16 supervision_tout ) +{ +#if BLE_INCLUDED == TRUE + tBTA_DM_API_BLE_CONN_PARAMS *p_msg; + + if ((p_msg = (tBTA_DM_API_BLE_CONN_PARAMS *) GKI_getbuf(sizeof(tBTA_DM_API_BLE_CONN_PARAMS))) != NULL) + { + memset(p_msg, 0, sizeof(tBTA_DM_API_BLE_CONN_PARAMS)); + + p_msg->hdr.event = BTA_DM_API_BLE_CONN_PARAM_EVT; + + memcpy(p_msg->peer_bda, bd_addr, BD_ADDR_LEN); + + p_msg->conn_int_max = max_conn_int; + p_msg->conn_int_min = min_conn_int; + p_msg->slave_latency = slave_latency; + p_msg->supervision_tout = supervision_tout; + + bta_sys_sendmsg(p_msg); + } +#endif +} + +/******************************************************************************* +** +** Function BTA_DmSetBleConnScanParams +** +** Description This function is called to set scan parameters used in +** BLE connection request +** +** Parameters: scan_interval - scan interval +** scan_window - scan window +** +** Returns void +** +*******************************************************************************/ +void BTA_DmSetBleConnScanParams(UINT32 scan_interval, UINT32 scan_window) +{ + tBTA_DM_API_BLE_SCAN_PARAMS *p_msg; + if ((p_msg = (tBTA_DM_API_BLE_SCAN_PARAMS *)GKI_getbuf(sizeof(tBTA_DM_API_BLE_SCAN_PARAMS))) != NULL) + { + memset(p_msg, 0, sizeof(tBTA_DM_API_BLE_SCAN_PARAMS)); + p_msg->hdr.event = BTA_DM_API_BLE_CONN_SCAN_PARAM_EVT; + p_msg->scan_int = scan_interval; + p_msg->scan_window = scan_window; + bta_sys_sendmsg(p_msg); + } +} + +/******************************************************************************* +** +** Function BTA_DmSetBleScanParams +** +** Description This function is called to set scan parameters +** +** Parameters: client_if - Client IF +** scan_interval - scan interval +** scan_window - scan window +** scan_mode - scan mode +** scan_param_setup_status_cback - Set scan param status callback +** +** Returns void +** +*******************************************************************************/ +void BTA_DmSetBleScanParams(tGATT_IF client_if, UINT32 scan_interval, + UINT32 scan_window, tBLE_SCAN_MODE scan_mode, + tBLE_SCAN_PARAM_SETUP_CBACK scan_param_setup_cback) +{ + tBTA_DM_API_BLE_SCAN_PARAMS *p_msg; + + if ((p_msg = (tBTA_DM_API_BLE_SCAN_PARAMS *)GKI_getbuf(sizeof(tBTA_DM_API_BLE_SCAN_PARAMS))) != NULL) + { + memset(p_msg, 0, sizeof(tBTA_DM_API_BLE_SCAN_PARAMS)); + p_msg->hdr.event = BTA_DM_API_BLE_SCAN_PARAM_EVT; + p_msg->client_if = client_if; + p_msg->scan_int = scan_interval; + p_msg->scan_window = scan_window; + p_msg->scan_mode = scan_mode; + p_msg->scan_param_setup_cback = scan_param_setup_cback; + + bta_sys_sendmsg(p_msg); + } +} + +/******************************************************************************* +** +** Function BTA_DmSetBleAdvParams +** +** Description This function sets the advertising parameters BLE functionality. +** It is to be called when device act in peripheral or broadcaster +** role. +** +** +** Returns void +** +*******************************************************************************/ +void BTA_DmSetBleAdvParams (UINT16 adv_int_min, UINT16 adv_int_max, + tBLE_BD_ADDR *p_dir_bda) +{ +#if BLE_INCLUDED == TRUE + tBTA_DM_API_BLE_ADV_PARAMS *p_msg; + + APPL_TRACE_API ("BTA_DmSetBleAdvParam: %d, %d", adv_int_min, adv_int_max); + + if ((p_msg = (tBTA_DM_API_BLE_ADV_PARAMS *) GKI_getbuf(sizeof(tBTA_DM_API_BLE_ADV_PARAMS))) != NULL) + { + memset(p_msg, 0, sizeof(tBTA_DM_API_BLE_ADV_PARAMS)); + + p_msg->hdr.event = BTA_DM_API_BLE_ADV_PARAM_EVT; + + p_msg->adv_int_min = adv_int_min; + p_msg->adv_int_max = adv_int_max; + + if (p_dir_bda != NULL) + { + p_msg->p_dir_bda = (tBLE_BD_ADDR *)(p_msg + 1); + memcpy(p_msg->p_dir_bda, p_dir_bda, sizeof(tBLE_BD_ADDR)); + } + + bta_sys_sendmsg(p_msg); + } +#endif +} +/******************************************************************************* +** BLE ADV data management API +********************************************************************************/ + +#if BLE_INCLUDED == TRUE +/******************************************************************************* +** +** Function BTA_DmBleSetAdvConfig +** +** Description This function is called to override the BTA default ADV parameters. +** +** Parameters data_mask: adv data mask. +** p_adv_cfg: Pointer to User defined ADV data structure. This +** memory space can not be freed until p_adv_data_cback +** is received. +** p_adv_data_cback: set adv data complete callback. +** +** Returns None +** +*******************************************************************************/ +void BTA_DmBleSetAdvConfig (tBTA_BLE_AD_MASK data_mask, tBTA_BLE_ADV_DATA *p_adv_cfg, + tBTA_SET_ADV_DATA_CMPL_CBACK *p_adv_data_cback) +{ + tBTA_DM_API_SET_ADV_CONFIG *p_msg; + + if ((p_msg = (tBTA_DM_API_SET_ADV_CONFIG *) + GKI_getbuf(sizeof(tBTA_DM_API_SET_ADV_CONFIG))) != NULL) + { + p_msg->hdr.event = BTA_DM_API_BLE_SET_ADV_CONFIG_EVT; + p_msg->data_mask = data_mask; + p_msg->p_adv_data_cback = p_adv_data_cback; + p_msg->p_adv_cfg = p_adv_cfg; + + bta_sys_sendmsg(p_msg); + } +} + +/******************************************************************************* +** +** Function BTA_DmBleSetScanRsp +** +** Description This function is called to override the BTA scan response. +** +** Parameters Pointer to User defined ADV data structure +** +** Returns None +** +*******************************************************************************/ +extern void BTA_DmBleSetScanRsp (tBTA_BLE_AD_MASK data_mask, tBTA_BLE_ADV_DATA *p_adv_cfg, + tBTA_SET_ADV_DATA_CMPL_CBACK *p_adv_data_cback) +{ + tBTA_DM_API_SET_ADV_CONFIG *p_msg; + + if ((p_msg = (tBTA_DM_API_SET_ADV_CONFIG *) + GKI_getbuf(sizeof(tBTA_DM_API_SET_ADV_CONFIG))) != NULL) + { + p_msg->hdr.event = BTA_DM_API_BLE_SET_SCAN_RSP_EVT; + p_msg->data_mask = data_mask; + p_msg->p_adv_data_cback = p_adv_data_cback; + p_msg->p_adv_cfg = p_adv_cfg; + + bta_sys_sendmsg(p_msg); + } +} + +/******************************************************************************* +** +** Function BTA_DmBleSetStorageParams +** +** Description This function is called to override the BTA scan response. +** +** Parameters batch_scan_full_max -Max storage space (in %) allocated to full scanning +** batch_scan_trunc_max -Max storage space (in %) allocated to truncated scanning +** batch_scan_notify_threshold -Setup notification level based on total space +** p_setup_cback - Setup callback pointer +** p_thres_cback - Threshold callback pointer +** p_rep_cback - Reports callback pointer +** ref_value - Ref value +** +** Returns None +** +*******************************************************************************/ +extern void BTA_DmBleSetStorageParams(UINT8 batch_scan_full_max, + UINT8 batch_scan_trunc_max, + UINT8 batch_scan_notify_threshold, + tBTA_BLE_SCAN_SETUP_CBACK *p_setup_cback, + tBTA_BLE_SCAN_THRESHOLD_CBACK *p_thres_cback, + tBTA_BLE_SCAN_REP_CBACK* p_rep_cback, + tBTA_DM_BLE_REF_VALUE ref_value) +{ + tBTA_DM_API_SET_STORAGE_CONFIG *p_msg; + bta_dm_cb.p_setup_cback = p_setup_cback; + if ((p_msg = (tBTA_DM_API_SET_STORAGE_CONFIG *) + GKI_getbuf(sizeof(tBTA_DM_API_SET_STORAGE_CONFIG))) != NULL) + { + p_msg->hdr.event = BTA_DM_API_BLE_SETUP_STORAGE_EVT; + p_msg->p_setup_cback=bta_ble_scan_setup_cb; + p_msg->p_thres_cback=p_thres_cback; + p_msg->p_read_rep_cback=p_rep_cback; + p_msg->ref_value = ref_value; + p_msg->batch_scan_full_max = batch_scan_full_max; + p_msg->batch_scan_trunc_max = batch_scan_trunc_max; + p_msg->batch_scan_notify_threshold = batch_scan_notify_threshold; + bta_sys_sendmsg(p_msg); + } +} + +/******************************************************************************* +** +** Function BTA_DmBleEnableBatchScan +** +** Description This function is called to enable the batch scan +** +** Parameters scan_mode -Batch scan mode +** scan_interval - Scan interval +** scan_window - Scan window +** discard_rule -Discard rules +** addr_type - Address type +** ref_value - Reference value +** +** Returns None +** +*******************************************************************************/ +extern void BTA_DmBleEnableBatchScan(tBTA_BLE_BATCH_SCAN_MODE scan_mode, + UINT32 scan_interval, UINT32 scan_window, + tBTA_BLE_DISCARD_RULE discard_rule, + tBLE_ADDR_TYPE addr_type, + tBTA_DM_BLE_REF_VALUE ref_value) +{ + tBTA_DM_API_ENABLE_SCAN *p_msg; + + if ((p_msg = (tBTA_DM_API_ENABLE_SCAN *) GKI_getbuf(sizeof(tBTA_DM_API_ENABLE_SCAN))) != NULL) + { + p_msg->hdr.event = BTA_DM_API_BLE_ENABLE_BATCH_SCAN_EVT; + p_msg->scan_mode = scan_mode; + p_msg->scan_int = scan_interval; + p_msg->scan_window = scan_window; + p_msg->discard_rule = discard_rule; + p_msg->addr_type = addr_type; + p_msg->ref_value = ref_value; + bta_sys_sendmsg(p_msg); + } +} + +/******************************************************************************* +** +** Function BTA_DmBleDisableBatchScan +** +** Description This function is called to disable the batch scan +** +** Parameters ref_value - Reference value +** +** Returns None +** +*******************************************************************************/ +extern void BTA_DmBleDisableBatchScan(tBTA_DM_BLE_REF_VALUE ref_value) +{ + tBTA_DM_API_DISABLE_SCAN *p_msg; + + if ((p_msg = (tBTA_DM_API_DISABLE_SCAN *) + GKI_getbuf(sizeof(tBTA_DM_API_DISABLE_SCAN))) != NULL) + { + p_msg->hdr.event = BTA_DM_API_BLE_DISABLE_BATCH_SCAN_EVT; + p_msg->ref_value = ref_value; + bta_sys_sendmsg(p_msg); + } +} + +/******************************************************************************* +** +** Function BTA_DmBleReadScanReports +** +** Description This function is called to read scan reports +** +** Parameters scan_type -Batch scan mode +** ref_value - Reference value +** +** Returns None +** +*******************************************************************************/ +extern void BTA_DmBleReadScanReports(tBTA_BLE_BATCH_SCAN_MODE scan_type, + tBTA_DM_BLE_REF_VALUE ref_value) +{ + tBTA_DM_API_READ_SCAN_REPORTS *p_msg; + + if ((p_msg = (tBTA_DM_API_READ_SCAN_REPORTS *) + GKI_getbuf(sizeof(tBTA_DM_API_READ_SCAN_REPORTS))) != NULL) + { + p_msg->hdr.event = BTA_DM_API_BLE_READ_SCAN_REPORTS_EVT; + p_msg->scan_type = scan_type; + p_msg->ref_value = ref_value; + bta_sys_sendmsg(p_msg); + } +} + +/******************************************************************************* +** +** Function BTA_DmBleTrackAdvertiser +** +** Description This function is called to track advertiser +** +** Parameters ref_value - Reference value +** p_track_adv_cback - Track ADV callback +** +** Returns None +** +*******************************************************************************/ +extern void BTA_DmBleTrackAdvertiser(tBTA_DM_BLE_REF_VALUE ref_value, + tBTA_BLE_TRACK_ADV_CBACK *p_track_adv_cback) +{ + tBTA_DM_API_TRACK_ADVERTISER *p_msg; + + if ((p_msg = (tBTA_DM_API_TRACK_ADVERTISER *) + GKI_getbuf(sizeof(tBTA_DM_API_TRACK_ADVERTISER))) != NULL) + { + p_msg->hdr.event = BTA_DM_API_BLE_TRACK_ADVERTISER_EVT; + p_msg->p_track_adv_cback = p_track_adv_cback; + p_msg->ref_value = ref_value; + bta_sys_sendmsg(p_msg); + } +} + +#endif + +/******************************************************************************* +** BLE ADV data management API +********************************************************************************/ +#if BLE_INCLUDED == TRUE + +/******************************************************************************* +** +** Function BTA_DmBleBroadcast +** +** Description This function starts or stops LE broadcasting. +** +** Parameters start: start or stop broadcast. +** +** Returns None +** +*******************************************************************************/ +extern void BTA_DmBleBroadcast (BOOLEAN start) +{ + tBTA_DM_API_BLE_OBSERVE *p_msg; + + APPL_TRACE_API("BTA_DmBleBroadcast: start = %d ", start); + + if ((p_msg = (tBTA_DM_API_BLE_OBSERVE *) GKI_getbuf(sizeof(tBTA_DM_API_BLE_OBSERVE))) != NULL) + { + memset(p_msg, 0, sizeof(tBTA_DM_API_BLE_OBSERVE)); + + p_msg->hdr.event = BTA_DM_API_BLE_BROADCAST_EVT; + p_msg->start = start; + + bta_sys_sendmsg(p_msg); + } +} + +#endif +/******************************************************************************* +** +** Function BTA_DmBleSetBgConnType +** +** Description This function is called to set BLE connectable mode for a +** peripheral device. +** +** Parameters bg_conn_type: it can be auto connection, or selective connection. +** p_select_cback: callback function when selective connection procedure +** is being used. +** +** Returns void +** +*******************************************************************************/ +void BTA_DmBleSetBgConnType(tBTA_DM_BLE_CONN_TYPE bg_conn_type, tBTA_DM_BLE_SEL_CBACK *p_select_cback) +{ +#if BLE_INCLUDED == TRUE + tBTA_DM_API_BLE_SET_BG_CONN_TYPE *p_msg; + + if ((p_msg = (tBTA_DM_API_BLE_SET_BG_CONN_TYPE *) GKI_getbuf(sizeof(tBTA_DM_API_BLE_SET_BG_CONN_TYPE))) != NULL) + { + memset(p_msg, 0, sizeof(tBTA_DM_API_BLE_SET_BG_CONN_TYPE)); + + p_msg->hdr.event = BTA_DM_API_BLE_SET_BG_CONN_TYPE; + p_msg->bg_conn_type = bg_conn_type; + p_msg->p_select_cback = p_select_cback; + + bta_sys_sendmsg(p_msg); + } +#endif +} + +/******************************************************************************* +** +** Function bta_dm_discover_send_msg +** +** Description This function send discover message to BTA task. +** +** Returns void +** +*******************************************************************************/ +#if BLE_INCLUDED == TRUE && BTA_GATT_INCLUDED == TRUE +static void bta_dm_discover_send_msg(BD_ADDR bd_addr, tBTA_SERVICE_MASK_EXT *p_services, + tBTA_DM_SEARCH_CBACK *p_cback, BOOLEAN sdp_search, + tBTA_TRANSPORT transport) +{ + tBTA_DM_API_DISCOVER *p_msg; + UINT16 len = p_services ? (sizeof(tBTA_DM_API_DISCOVER) + + sizeof(tBT_UUID) * p_services->num_uuid) : + sizeof(tBTA_DM_API_DISCOVER); + + if ((p_msg = (tBTA_DM_API_DISCOVER *) GKI_getbuf(len)) != NULL) + { + memset(p_msg, 0, len); + + p_msg->hdr.event = BTA_DM_API_DISCOVER_EVT; + bdcpy(p_msg->bd_addr, bd_addr); + p_msg->p_cback = p_cback; + p_msg->sdp_search = sdp_search; + p_msg->transport = transport; + + if (p_services != NULL) + { +#if BLE_INCLUDED == TRUE && BTA_GATT_INCLUDED == TRUE + p_msg->services = p_services->srvc_mask; + p_msg->num_uuid = p_services->num_uuid; + if (p_services->num_uuid != 0) + { + p_msg->p_uuid = (tBT_UUID *)(p_msg + 1); + memcpy(p_msg->p_uuid, p_services->p_uuid, sizeof(tBT_UUID) * p_services->num_uuid); + } +#endif + } + + bta_sys_sendmsg(p_msg); + } +} +#endif +/******************************************************************************* +** +** Function BTA_DmDiscoverByTransport +** +** Description This function does service discovery on particular transport +** for services of a +** peer device. When services.num_uuid is 0, it indicates all +** GATT based services are to be searched; otherwise a list of +** UUID of interested services should be provided through +** p_services->p_uuid. +** +** +** +** Returns void +** +*******************************************************************************/ +void BTA_DmDiscoverByTransport(BD_ADDR bd_addr, tBTA_SERVICE_MASK_EXT *p_services, + tBTA_DM_SEARCH_CBACK *p_cback, BOOLEAN sdp_search, + tBTA_TRANSPORT transport) +{ +#if BLE_INCLUDED == TRUE && BTA_GATT_INCLUDED == TRUE + bta_dm_discover_send_msg(bd_addr, p_services, p_cback, sdp_search, transport); +#endif +} + + +/******************************************************************************* +** +** Function BTA_DmDiscoverExt +** +** Description This function does service discovery for services of a +** peer device. When services.num_uuid is 0, it indicates all +** GATT based services are to be searched; other wise a list of +** UUID of interested services should be provided through +** p_services->p_uuid. +** +** +** +** Returns void +** +*******************************************************************************/ +void BTA_DmDiscoverExt(BD_ADDR bd_addr, tBTA_SERVICE_MASK_EXT *p_services, + tBTA_DM_SEARCH_CBACK *p_cback, BOOLEAN sdp_search) +{ +#if BLE_INCLUDED == TRUE && BTA_GATT_INCLUDED == TRUE + bta_dm_discover_send_msg(bd_addr, p_services, p_cback, sdp_search, BTA_TRANSPORT_UNKNOWN); +#endif + +} + +/******************************************************************************* +** +** Function BTA_DmSearchExt +** +** Description This function searches for peer Bluetooth devices. It performs +** an inquiry and gets the remote name for devices. Service +** discovery is done if services is non zero +** +** Parameters p_dm_inq: inquiry conditions +** p_services: if service is not empty, service discovery will be done. +** for all GATT based service condition, put num_uuid, and +** p_uuid is the pointer to the list of UUID values. +** p_cback: callback functino when search is completed. +** +** +** +** Returns void +** +*******************************************************************************/ +void BTA_DmSearchExt(tBTA_DM_INQ *p_dm_inq, tBTA_SERVICE_MASK_EXT *p_services, tBTA_DM_SEARCH_CBACK *p_cback) +{ +#if BLE_INCLUDED == TRUE && BTA_GATT_INCLUDED == TRUE + tBTA_DM_API_SEARCH *p_msg; + UINT16 len = p_services ? (sizeof(tBTA_DM_API_SEARCH) + sizeof(tBT_UUID) * p_services->num_uuid) : + sizeof(tBTA_DM_API_SEARCH); + + if ((p_msg = (tBTA_DM_API_SEARCH *) GKI_getbuf(len)) != NULL) + { + memset(p_msg, 0, len); + + p_msg->hdr.event = BTA_DM_API_SEARCH_EVT; + memcpy(&p_msg->inq_params, p_dm_inq, sizeof(tBTA_DM_INQ)); + p_msg->p_cback = p_cback; + p_msg->rs_res = BTA_DM_RS_NONE; + + + if (p_services != NULL) + { + p_msg->services = p_services->srvc_mask; + p_msg->num_uuid = p_services->num_uuid; + + if (p_services->num_uuid != 0) + { + p_msg->p_uuid = (tBT_UUID *)(p_msg + 1); + memcpy(p_msg->p_uuid, p_services->p_uuid, sizeof(tBT_UUID) * p_services->num_uuid); + } + else + p_msg->p_uuid = NULL; + } + + bta_sys_sendmsg(p_msg); + } +#else + UNUSED(p_dm_inq); + UNUSED(p_services); + UNUSED(p_cback); +#endif +} +/******************************************************************************* +** +** Function BTA_DmBleUpdateConnectionParam +** +** Description Update connection parameters, can only be used when connection is up. +** +** Parameters: bd_addr - BD address of the peer +** min_int - minimum connection interval, [0x0004~ 0x4000] +** max_int - maximum connection interval, [0x0004~ 0x4000] +** latency - slave latency [0 ~ 500] +** timeout - supervision timeout [0x000a ~ 0xc80] +** +** Returns void +** +*******************************************************************************/ +void BTA_DmBleUpdateConnectionParam(BD_ADDR bd_addr, UINT16 min_int, + UINT16 max_int, UINT16 latency, + UINT16 timeout) +{ +#if BLE_INCLUDED == TRUE + tBTA_DM_API_UPDATE_CONN_PARAM *p_msg; + + p_msg = (tBTA_DM_API_UPDATE_CONN_PARAM *) GKI_getbuf(sizeof(tBTA_DM_API_UPDATE_CONN_PARAM)); + if (p_msg != NULL) + { + memset(p_msg, 0, sizeof(tBTA_DM_API_UPDATE_CONN_PARAM)); + + p_msg->hdr.event = BTA_DM_API_UPDATE_CONN_PARAM_EVT; + bdcpy(p_msg->bd_addr, bd_addr); + p_msg->min_int = min_int; + p_msg->max_int = max_int; + p_msg->latency = latency; + p_msg->timeout = timeout; + + bta_sys_sendmsg(p_msg); + } +#endif +} +/******************************************************************************* +** +** Function BTA_DmBleConfigLocalPrivacy +** +** Description Enable/disable privacy on the local device +** +** Parameters: privacy_enable - enable/disabe privacy on remote device. +** +** Returns void +** +*******************************************************************************/ +void BTA_DmBleConfigLocalPrivacy(BOOLEAN privacy_enable) +{ +#if BLE_INCLUDED == TRUE && BLE_PRIVACY_SPT == TRUE + tBTA_DM_API_LOCAL_PRIVACY *p_msg; + + if ((p_msg = (tBTA_DM_API_LOCAL_PRIVACY *) GKI_getbuf(sizeof(tBTA_DM_API_ENABLE_PRIVACY))) != NULL) + { + memset (p_msg, 0, sizeof(tBTA_DM_API_LOCAL_PRIVACY)); + + p_msg->hdr.event = BTA_DM_API_LOCAL_PRIVACY_EVT; + p_msg->privacy_enable = privacy_enable; + + bta_sys_sendmsg(p_msg); + } +#else + UNUSED (privacy_enable); +#endif +} + +#if BLE_INCLUDED == TRUE +/******************************************************************************* +** +** Function BTA_BleEnableAdvInstance +** +** Description This function enable a Multi-ADV instance with the specififed +** adv parameters +** +** Parameters p_params: pointer to the adv parameter structure. +** p_cback: callback function associated to this adv instance. +** p_ref: reference data pointer to this adv instance. +** +** Returns BTA_SUCCESS if command started sucessfully; otherwise failure. +** +*******************************************************************************/ +void BTA_BleEnableAdvInstance (tBTA_BLE_ADV_PARAMS *p_params, + tBTA_BLE_MULTI_ADV_CBACK *p_cback, + void *p_ref) +{ + tBTA_DM_API_BLE_MULTI_ADV_ENB *p_msg; + UINT16 len = sizeof(tBTA_BLE_ADV_PARAMS) + sizeof(tBTA_DM_API_BLE_MULTI_ADV_ENB); + + APPL_TRACE_API ("BTA_BleEnableAdvInstance"); + + if ((p_msg = (tBTA_DM_API_BLE_MULTI_ADV_ENB *) GKI_getbuf(len)) != NULL) + { + memset(p_msg, 0, sizeof(tBTA_DM_API_BLE_MULTI_ADV_ENB)); + + p_msg->hdr.event = BTA_DM_API_BLE_MULTI_ADV_ENB_EVT; + p_msg->p_cback = (void *)p_cback; + if (p_params != NULL) + { + p_msg->p_params = (void *)(p_msg + 1); + memcpy(p_msg->p_params, p_params, sizeof(tBTA_BLE_ADV_PARAMS)); + } + p_msg->p_ref = p_ref; + + bta_sys_sendmsg(p_msg); + } +} + +/******************************************************************************* +** +** Function BTA_BleUpdateAdvInstParam +** +** Description This function update a Multi-ADV instance with the specififed +** adv parameters. +** +** Parameters inst_id: Adv instance to update the parameter. +** p_params: pointer to the adv parameter structure. +** +** Returns BTA_SUCCESS if command started sucessfully; otherwise failure. +** +*******************************************************************************/ +void BTA_BleUpdateAdvInstParam (UINT8 inst_id, tBTA_BLE_ADV_PARAMS *p_params) +{ + tBTA_DM_API_BLE_MULTI_ADV_PARAM *p_msg; + UINT16 len = sizeof(tBTA_BLE_ADV_PARAMS) + sizeof(tBTA_DM_API_BLE_MULTI_ADV_PARAM); + + APPL_TRACE_API ("BTA_BleUpdateAdvInstParam"); + if ((p_msg = (tBTA_DM_API_BLE_MULTI_ADV_PARAM *) GKI_getbuf(len)) != NULL) + { + memset(p_msg, 0, sizeof(tBTA_DM_API_BLE_MULTI_ADV_PARAM)); + p_msg->hdr.event = BTA_DM_API_BLE_MULTI_ADV_PARAM_UPD_EVT; + p_msg->inst_id = inst_id; + p_msg->p_params = (void *)(p_msg + 1); + memcpy(p_msg->p_params, p_params, sizeof(tBTA_BLE_ADV_PARAMS)); + + bta_sys_sendmsg(p_msg); + } +} + +/******************************************************************************* +** +** Function BTA_BleCfgAdvInstData +** +** Description This function configure a Multi-ADV instance with the specififed +** adv data or scan response data. +** +** Parameter inst_id: Adv instance to configure the adv data or scan response. +** is_scan_rsp: is the data scan response or adv data. +** data_mask: adv data type as bit mask. +** p_data: pointer to the ADV data structure tBTA_BLE_ADV_DATA. This +** memory space can not be freed until BTA_BLE_MULTI_ADV_DATA_EVT +** is sent to application. +** +** Returns BTA_SUCCESS if command started sucessfully; otherwise failure. +** +*******************************************************************************/ +void BTA_BleCfgAdvInstData (UINT8 inst_id, BOOLEAN is_scan_rsp, + tBTA_BLE_AD_MASK data_mask, + tBTA_BLE_ADV_DATA *p_data) +{ + tBTA_DM_API_BLE_MULTI_ADV_DATA *p_msg; + UINT16 len = sizeof(tBTA_DM_API_BLE_MULTI_ADV_DATA) ; + + APPL_TRACE_API ("BTA_BleCfgAdvInstData"); + + if ((p_msg = (tBTA_DM_API_BLE_MULTI_ADV_DATA *) GKI_getbuf(len)) != NULL) + { + memset(p_msg, 0, len); + p_msg->hdr.event = BTA_DM_API_BLE_MULTI_ADV_DATA_EVT; + p_msg->inst_id = inst_id; + p_msg->is_scan_rsp = is_scan_rsp; + p_msg->data_mask = data_mask; + p_msg->p_data = p_data; + + bta_sys_sendmsg(p_msg); + } +} + +/******************************************************************************* +** +** Function BTA_BleDisableAdvInstance +** +** Description This function disable a Multi-ADV instance. +** +** Parameter inst_id: instance ID to disable. +** +** Returns BTA_SUCCESS if command started sucessfully; otherwise failure. +** +*******************************************************************************/ +void BTA_BleDisableAdvInstance (UINT8 inst_id) +{ + tBTA_DM_API_BLE_MULTI_ADV_DISABLE *p_msg; + + APPL_TRACE_API ("BTA_BleDisableAdvInstance: %d", inst_id); + if ((p_msg = (tBTA_DM_API_BLE_MULTI_ADV_DISABLE *) + GKI_getbuf(sizeof(tBTA_DM_API_BLE_MULTI_ADV_DISABLE))) != NULL) + { + memset(p_msg, 0, sizeof(tBTA_DM_API_BLE_MULTI_ADV_DISABLE)); + p_msg->hdr.event = BTA_DM_API_BLE_MULTI_ADV_DISABLE_EVT; + p_msg->inst_id = inst_id; + bta_sys_sendmsg(p_msg); + } +} + +/******************************************************************************* +** +** Function BTA_DmBleCfgFilterCondition +** +** Description This function is called to configure the adv data payload filter +** condition. +** +** Parameters action: to read/write/clear +** cond_type: filter condition type +** filt_index - Filter index +** p_cond: filter condition parameter +** p_cmpl_back - Command completed callback +** ref_value - Reference value +** +** Returns void +** +*******************************************************************************/ +void BTA_DmBleCfgFilterCondition(tBTA_DM_BLE_SCAN_COND_OP action, + tBTA_DM_BLE_PF_COND_TYPE cond_type, + tBTA_DM_BLE_PF_FILT_INDEX filt_index, + tBTA_DM_BLE_PF_COND_PARAM *p_cond, + tBTA_DM_BLE_PF_CFG_CBACK *p_cmpl_cback, + tBTA_DM_BLE_REF_VALUE ref_value) +{ +#if BLE_ANDROID_CONTROLLER_SCAN_FILTER == TRUE + tBTA_DM_API_CFG_FILTER_COND *p_msg; + APPL_TRACE_API ("BTA_DmBleCfgFilterCondition: %d, %d", action, cond_type); + + UINT16 len = sizeof(tBTA_DM_API_CFG_FILTER_COND) + + sizeof(tBTA_DM_BLE_PF_COND_PARAM); + UINT8 *p; + + if (NULL != p_cond) + { + switch(cond_type) + { + case BTA_DM_BLE_PF_SRVC_DATA_PATTERN: + case BTA_DM_BLE_PF_MANU_DATA: + /* Length of pattern and pattern mask and other elements in */ + /* tBTA_DM_BLE_PF_MANU_COND */ + len += ((p_cond->manu_data.data_len) * 2) + + sizeof(UINT16) + sizeof(UINT16) + sizeof(UINT8); + break; + + case BTA_DM_BLE_PF_LOCAL_NAME: + len += ((p_cond->local_name.data_len) + sizeof(UINT8)); + break; + + case BTM_BLE_PF_SRVC_UUID: + case BTM_BLE_PF_SRVC_SOL_UUID: + len += sizeof(tBLE_BD_ADDR) + sizeof(tBTA_DM_BLE_PF_COND_MASK); + break; + + default: + break; + } + } + + if ((p_msg = (tBTA_DM_API_CFG_FILTER_COND *) GKI_getbuf(len)) != NULL) + { + memset (p_msg, 0, len); + + p_msg->hdr.event = BTA_DM_API_CFG_FILTER_COND_EVT; + p_msg->action = action; + p_msg->cond_type = cond_type; + p_msg->filt_index = filt_index; + p_msg->p_filt_cfg_cback = p_cmpl_cback; + p_msg->ref_value = ref_value; + if (p_cond) + { + p_msg->p_cond_param = (tBTA_DM_BLE_PF_COND_PARAM *)(p_msg + 1); + memcpy(p_msg->p_cond_param, p_cond, sizeof(tBTA_DM_BLE_PF_COND_PARAM)); + + p = (UINT8 *)(p_msg->p_cond_param + 1); + + if (cond_type == BTA_DM_BLE_PF_SRVC_DATA_PATTERN || + cond_type == BTA_DM_BLE_PF_MANU_DATA) + { + p_msg->p_cond_param->manu_data.p_pattern = p; + p_msg->p_cond_param->manu_data.data_len = p_cond->manu_data.data_len; + memcpy(p_msg->p_cond_param->manu_data.p_pattern, p_cond->manu_data.p_pattern, + p_cond->manu_data.data_len); + p += p_cond->manu_data.data_len; + + if (cond_type == BTA_DM_BLE_PF_MANU_DATA) + { + p_msg->p_cond_param->manu_data.company_id_mask = + p_cond->manu_data.company_id_mask; + if ( p_cond->manu_data.p_pattern_mask != NULL) + { + p_msg->p_cond_param->manu_data.p_pattern_mask = p; + memcpy(p_msg->p_cond_param->manu_data.p_pattern_mask, + p_cond->manu_data.p_pattern_mask, p_cond->manu_data.data_len); + } + } + } + else if (cond_type == BTA_DM_BLE_PF_LOCAL_NAME) + { + p_msg->p_cond_param->local_name.p_data = p; + p_msg->p_cond_param->local_name.data_len = + p_cond->local_name.data_len; + memcpy(p_msg->p_cond_param->local_name.p_data, + p_cond->local_name.p_data, p_cond->local_name.data_len); + } + else if ((cond_type == BTM_BLE_PF_SRVC_UUID + || cond_type == BTM_BLE_PF_SRVC_SOL_UUID)) + { + if (p_cond->srvc_uuid.p_target_addr != NULL) + { + p_msg->p_cond_param->srvc_uuid.p_target_addr = (tBLE_BD_ADDR *)(p); + p_msg->p_cond_param->srvc_uuid.p_target_addr->type = + p_cond->srvc_uuid.p_target_addr->type; + memcpy(p_msg->p_cond_param->srvc_uuid.p_target_addr->bda, + p_cond->srvc_uuid.p_target_addr->bda, BD_ADDR_LEN); + p = (UINT8*)( p_msg->p_cond_param->srvc_uuid.p_target_addr + 1); + } + if (p_cond->srvc_uuid.p_uuid_mask) + { + p_msg->p_cond_param->srvc_uuid.p_uuid_mask = (tBTA_DM_BLE_PF_COND_MASK *)p; + memcpy(p_msg->p_cond_param->srvc_uuid.p_uuid_mask, + p_cond->srvc_uuid.p_uuid_mask, sizeof(tBTA_DM_BLE_PF_COND_MASK)); + } + } + } + + bta_sys_sendmsg(p_msg); + } +#else + UNUSED(action); + UNUSED(cond_type); + UNUSED(filt_index); + UNUSED(p_cond); + UNUSED(p_cmpl_cback); + UNUSED(ref_value); +#endif +} + +/******************************************************************************* +** +** Function BTA_DmBleScanFilterSetup +** +** Description This function is called to setup the adv data payload filter param +** +** Parameters p_target: enable the filter condition on a target device; if NULL +** filt_index - Filter index +** p_filt_params -Filter parameters +** ref_value - Reference value +** action - Add, delete or clear +** p_cmpl_back - Command completed callback +** +** Returns void +** +*******************************************************************************/ +void BTA_DmBleScanFilterSetup(UINT8 action, tBTA_DM_BLE_PF_FILT_INDEX filt_index, + tBTA_DM_BLE_PF_FILT_PARAMS *p_filt_params, + tBLE_BD_ADDR *p_target, + tBTA_DM_BLE_PF_PARAM_CBACK *p_cmpl_cback, + tBTA_DM_BLE_REF_VALUE ref_value) +{ +#if BLE_ANDROID_CONTROLLER_SCAN_FILTER == TRUE + tBTA_DM_API_SCAN_FILTER_PARAM_SETUP *p_msg; + APPL_TRACE_API ("BTA_DmBleScanFilterSetup: %d", action); + + UINT16 len = sizeof(tBTA_DM_API_SCAN_FILTER_PARAM_SETUP) + sizeof(tBLE_BD_ADDR); + + if ((p_msg = (tBTA_DM_API_SCAN_FILTER_PARAM_SETUP *) GKI_getbuf(len)) != NULL) + { + memset (p_msg, 0, len); + + p_msg->hdr.event = BTA_DM_API_SCAN_FILTER_SETUP_EVT; + p_msg->action = action; + p_msg->filt_index = filt_index; + if (p_filt_params) + memcpy(&p_msg->filt_params, p_filt_params, sizeof(tBTA_DM_BLE_PF_FILT_PARAMS)); + p_msg->p_filt_param_cback = p_cmpl_cback; + p_msg->ref_value = ref_value; + + if (p_target) + { + p_msg->p_target = (tBLE_BD_ADDR *)(p_msg + 1); + memcpy(p_msg->p_target, p_target, sizeof(tBLE_BD_ADDR)); + } + + bta_sys_sendmsg(p_msg); + } +#else + UNUSED(action); + UNUSED(filt_index); + UNUSED(p_filt_params); + UNUSED(p_target); + UNUSED(p_cmpl_cback); + UNUSED(ref_value); +#endif +} + +/******************************************************************************* +** +** Function BTA_DmBleGetEnergyInfo +** +** Description This function is called to obtain the energy info +** +** Parameters p_cmpl_cback - Command complete callback +** +** Returns void +** +*******************************************************************************/ +void BTA_DmBleGetEnergyInfo(tBTA_BLE_ENERGY_INFO_CBACK *p_cmpl_cback) +{ + tBTA_DM_API_ENERGY_INFO *p_msg; + APPL_TRACE_API ("BTA_DmBleGetEnergyInfo"); + + UINT16 len = sizeof(tBTA_DM_API_ENERGY_INFO) + sizeof(tBLE_BD_ADDR); + + if ((p_msg = (tBTA_DM_API_ENERGY_INFO *) GKI_getbuf(len)) != NULL) + { + memset (p_msg, 0, len); + p_msg->hdr.event = BTA_DM_API_BLE_ENERGY_INFO_EVT; + p_msg->p_energy_info_cback = p_cmpl_cback; + bta_sys_sendmsg(p_msg); + } +} + +/******************************************************************************* +** +** Function BTA_DmEnableScanFilter +** +** Description This function is called to enable the adv data payload filter +** +** Parameters action - enable or disable the APCF feature +** p_cmpl_cback - Command completed callback +** ref_value - Reference value +** +** Returns void +** +*******************************************************************************/ +void BTA_DmEnableScanFilter(UINT8 action, tBTA_DM_BLE_PF_STATUS_CBACK *p_cmpl_cback, + tBTA_DM_BLE_REF_VALUE ref_value) +{ +#if BLE_ANDROID_CONTROLLER_SCAN_FILTER == TRUE + tBTA_DM_API_ENABLE_SCAN_FILTER *p_msg; + APPL_TRACE_API ("BTA_DmEnableScanFilter: %d", action); + + UINT16 len = sizeof(tBTA_DM_API_ENABLE_SCAN_FILTER) + sizeof(tBLE_BD_ADDR); + + if ((p_msg = (tBTA_DM_API_ENABLE_SCAN_FILTER *) GKI_getbuf(len)) != NULL) + { + memset (p_msg, 0, len); + + p_msg->hdr.event = BTA_DM_API_SCAN_FILTER_ENABLE_EVT; + p_msg->action = action; + p_msg->ref_value = ref_value; + p_msg->p_filt_status_cback = p_cmpl_cback; + + bta_sys_sendmsg(p_msg); + } +#else + UNUSED(action); + UNUSED(p_cmpl_cback); + UNUSED(ref_value); +#endif +} + +/******************************************************************************* +** +** Function BTA_DmBleUpdateConnectionParams +** +** Description Update connection parameters, can only be used when connection is up. +** +** Parameters: bd_addr - BD address of the peer +** min_int - minimum connection interval, [0x0004~ 0x4000] +** max_int - maximum connection interval, [0x0004~ 0x4000] +** latency - slave latency [0 ~ 500] +** timeout - supervision timeout [0x000a ~ 0xc80] +** +** Returns void +** +*******************************************************************************/ +void BTA_DmBleUpdateConnectionParams(BD_ADDR bd_addr, UINT16 min_int, UINT16 max_int, + UINT16 latency, UINT16 timeout) +{ + tBTA_DM_API_UPDATE_CONN_PARAM *p_msg; + + if ((p_msg = (tBTA_DM_API_UPDATE_CONN_PARAM *) GKI_getbuf(sizeof(tBTA_DM_API_UPDATE_CONN_PARAM))) != NULL) + { + memset (p_msg, 0, sizeof(tBTA_DM_API_UPDATE_CONN_PARAM)); + + p_msg->hdr.event = BTA_DM_API_UPDATE_CONN_PARAM_EVT; + bdcpy(p_msg->bd_addr, bd_addr); + p_msg->min_int = min_int; + p_msg->max_int = max_int; + p_msg->latency = latency; + p_msg->timeout = timeout; + + bta_sys_sendmsg(p_msg); + } +} + +/******************************************************************************* +** +** Function BTA_DmBleSetDataLength +** +** Description This function is to set maximum LE data packet size +** +** Returns void +** +** +*******************************************************************************/ +void BTA_DmBleSetDataLength(BD_ADDR remote_device, UINT16 tx_data_length) +{ + tBTA_DM_API_BLE_SET_DATA_LENGTH *p_msg; + + if ((p_msg = (tBTA_DM_API_BLE_SET_DATA_LENGTH *)GKI_getbuf(sizeof(tBTA_DM_API_BLE_SET_DATA_LENGTH))) + != NULL) + { + bdcpy(p_msg->remote_bda, remote_device); + p_msg->hdr.event = BTA_DM_API_SET_DATA_LENGTH_EVT; + p_msg->tx_data_length = tx_data_length; + + bta_sys_sendmsg(p_msg); + } +} + +#endif + +/******************************************************************************* +** +** Function BTA_DmSetEncryption +** +** Description This function is called to ensure that connection is +** encrypted. Should be called only on an open connection. +** Typically only needed for connections that first want to +** bring up unencrypted links, then later encrypt them. +** +** Parameters: bd_addr - Address of the peer device +** transport - transport of the link to be encruypted +** p_callback - Pointer to callback function to indicat the +** link encryption status +** sec_act - This is the security action to indicate +** what knid of BLE security level is required for +** the BLE link if the BLE is supported +** Note: This parameter is ignored for the BR/EDR link +** or the BLE is not supported +** +** Returns void +** +*******************************************************************************/ +void BTA_DmSetEncryption(BD_ADDR bd_addr, tBTA_TRANSPORT transport, tBTA_DM_ENCRYPT_CBACK *p_callback, + tBTA_DM_BLE_SEC_ACT sec_act) +{ + tBTA_DM_API_SET_ENCRYPTION *p_msg; + + APPL_TRACE_API("BTA_DmSetEncryption"); //todo + if ((p_msg = (tBTA_DM_API_SET_ENCRYPTION *) GKI_getbuf(sizeof(tBTA_DM_API_SET_ENCRYPTION))) != NULL) + { + memset(p_msg, 0, sizeof(tBTA_DM_API_SET_ENCRYPTION)); + + p_msg->hdr.event = BTA_DM_API_SET_ENCRYPTION_EVT; + + memcpy(p_msg->bd_addr, bd_addr, BD_ADDR_LEN); + p_msg->transport = transport; + p_msg->p_callback = p_callback; + p_msg->sec_act = sec_act; + + bta_sys_sendmsg(p_msg); + } +} + +/******************************************************************************* +** +** Function BTA_DmCloseACL +** +** Description This function force to close an ACL connection and remove the +** device from the security database list of known devices. +** +** Parameters: bd_addr - Address of the peer device +** remove_dev - remove device or not after link down +** +** Returns void +** +*******************************************************************************/ +void BTA_DmCloseACL(BD_ADDR bd_addr, BOOLEAN remove_dev, tBTA_TRANSPORT transport) +{ + tBTA_DM_API_REMOVE_ACL *p_msg; + + APPL_TRACE_API("BTA_DmCloseACL"); + + if ((p_msg = (tBTA_DM_API_REMOVE_ACL *) GKI_getbuf(sizeof(tBTA_DM_API_REMOVE_ACL))) != NULL) + { + memset(p_msg, 0, sizeof(tBTA_DM_API_REMOVE_ACL)); + + p_msg->hdr.event = BTA_DM_API_REMOVE_ACL_EVT; + + memcpy(p_msg->bd_addr, bd_addr, BD_ADDR_LEN); + p_msg->remove_dev = remove_dev; + p_msg->transport = transport; + + bta_sys_sendmsg(p_msg); + } +} + +#if BLE_INCLUDED == TRUE +/******************************************************************************* +** +** Function BTA_DmBleObserve +** +** Description This procedure keep the device listening for advertising +** events from a broadcast device. +** +** Parameters start: start or stop observe. +** +** Returns void + +** +** Returns void. +** +*******************************************************************************/ +extern void BTA_DmBleObserve(BOOLEAN start, UINT8 duration, + tBTA_DM_SEARCH_CBACK *p_results_cb) +{ + tBTA_DM_API_BLE_OBSERVE *p_msg; + + APPL_TRACE_API("BTA_DmBleObserve:start = %d ", start); + + if ((p_msg = (tBTA_DM_API_BLE_OBSERVE *) GKI_getbuf(sizeof(tBTA_DM_API_BLE_OBSERVE))) != NULL) + { + memset(p_msg, 0, sizeof(tBTA_DM_API_BLE_OBSERVE)); + + p_msg->hdr.event = BTA_DM_API_BLE_OBSERVE_EVT; + p_msg->start = start; + p_msg->duration = duration; + p_msg->p_cback = p_results_cb; + + bta_sys_sendmsg(p_msg); + } +} + + +/******************************************************************************* +** +** Function BTA_DmSetRandAddress +** +** Description This function set the random address for the APP +** +** Parameters rand_addr: the random address whith should be setting +** +** Returns void +** +** +*******************************************************************************/ +extern void BTA_DmSetRandAddress(BD_ADDR rand_addr) +{ + tBTA_DM_APT_SET_DEV_ADDR *p_msg; + APPL_TRACE_API("set the random address "); + if ((p_msg = (tBTA_DM_APT_SET_DEV_ADDR *) GKI_getbuf(sizeof(tBTA_DM_APT_SET_DEV_ADDR))) != NULL) + { + memset(p_msg, 0, sizeof(tBTA_DM_APT_SET_DEV_ADDR)); + memcpy(p_msg->address,rand_addr,BD_ADDR_LEN); + p_msg->hdr.event = BTA_DM_API_SET_RAND_ADDR_EVT; + p_msg->addr_type = BLE_ADDR_RANDOM; + //start sent the msg to the bta system control moudle + bta_sys_sendmsg(p_msg); + } +} + +/******************************************************************************* +** +** Function BTA_VendorInit +** +** Description This function initializes vendor specific +** +** Returns void +** +*******************************************************************************/ +void BTA_VendorInit (void) +{ + APPL_TRACE_API("BTA_VendorInit"); +} + +/******************************************************************************* +** +** Function BTA_VendorCleanup +** +** Description This function frees up Broadcom specific VS specific dynamic memory +** +** Returns void +** +*******************************************************************************/ +void BTA_VendorCleanup (void) +{ + tBTM_BLE_VSC_CB cmn_ble_vsc_cb; + BTM_BleGetVendorCapabilities(&cmn_ble_vsc_cb); + +#if (BLE_INCLUDED == TRUE && BLE_ANDROID_CONTROLLER_SCAN_FILTER == TRUE) + if (cmn_ble_vsc_cb.max_filter > 0) + { + btm_ble_adv_filter_cleanup(); +#if BLE_PRIVACY_SPT == TRUE + btm_ble_resolving_list_cleanup (); +#endif + } + + if (cmn_ble_vsc_cb.tot_scan_results_strg > 0) + btm_ble_batchscan_cleanup(); +#endif + + if(cmn_ble_vsc_cb.adv_inst_max > 0) + btm_ble_multi_adv_cleanup(); +} + +#endif diff --git a/components/bt/bluedroid/bta/dm/bta_dm_cfg.c b/components/bt/bluedroid/bta/dm/bta_dm_cfg.c new file mode 100755 index 0000000000..f0895185da --- /dev/null +++ b/components/bt/bluedroid/bta/dm/bta_dm_cfg.c @@ -0,0 +1,587 @@ +/****************************************************************************** + * + * Copyright (C) 2003-2012 Broadcom Corporation + * + * 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 compile-time configurable constants for the device + * manager. + * + ******************************************************************************/ + +#include +#include "bt_target.h" +#include "bta_sys.h" +#include "bta_api.h" +#include "bta_dm_int.h" +// #include "bta_jv_api.h" + +#ifndef BTA_DM_LINK_POLICY_SETTINGS +#define BTA_DM_LINK_POLICY_SETTINGS (HCI_ENABLE_MASTER_SLAVE_SWITCH | HCI_ENABLE_HOLD_MODE | HCI_ENABLE_SNIFF_MODE | HCI_ENABLE_PARK_MODE) +#endif + +/* page timeout in 625uS */ +#ifndef BTA_DM_PAGE_TIMEOUT +#define BTA_DM_PAGE_TIMEOUT 8192 +#endif + +/* link supervision timeout in 625uS (5 secs) */ +#ifndef BTA_DM_LINK_TIMEOUT +#define BTA_DM_LINK_TIMEOUT 8000 +#endif + +/* TRUE to avoid scatternet when av is streaming (be the master) */ +#ifndef BTA_DM_AVOID_SCATTER_A2DP +#define BTA_DM_AVOID_SCATTER_A2DP TRUE +#endif + +/* For Insight, PM cfg lookup tables are runtime configurable (to allow tweaking of params for power consumption measurements) */ +#ifndef BTE_SIM_APP +#define tBTA_DM_PM_TYPE_QUALIFIER const +#else +#define tBTA_DM_PM_TYPE_QUALIFIER +#endif + + +const tBTA_DM_CFG bta_dm_cfg = +{ + /* mobile phone COD */ + BTA_DM_COD, + /* link policy settings */ + BTA_DM_LINK_POLICY_SETTINGS, + /* page timeout in 625uS */ + BTA_DM_PAGE_TIMEOUT, + /* link supervision timeout in 625uS*/ + BTA_DM_LINK_TIMEOUT, + /* TRUE to avoid scatternet when av is streaming (be the master) */ + BTA_DM_AVOID_SCATTER_A2DP +}; + +#ifndef BTA_DM_SCATTERNET +/* By default, allow partial scatternet */ +#define BTA_DM_SCATTERNET BTA_DM_PARTIAL_SCATTERNET +#endif + +#ifndef BTA_HH_ROLE +/* By default, do not specify HH role (backward compatibility) */ +#define BTA_HH_ROLE BTA_ANY_ROLE +#endif + +#ifndef BTA_AV_ROLE +/* By default, AV role (backward BTA_MASTER_ROLE_PREF) */ +#define BTA_AV_ROLE BTA_MASTER_ROLE_PREF +#endif + +#ifndef BTA_PANU_ROLE +/* By default, AV role (backward BTA_MASTER_ROLE_PREF) */ +#define BTA_PANU_ROLE BTA_SLAVE_ROLE_ONLY +#endif +#define BTA_DM_NUM_RM_ENTRY 6 + +/* appids for PAN used by insight sample application + these have to be same as defined in btui_int.h */ +#define BTUI_PAN_ID_PANU 0 +#define BTUI_PAN_ID_NAP 1 +#define BTUI_PAN_ID_GN 2 + +/* First element is always for SYS: + app_id = # of entries table, cfg is + device scatternet support */ +const tBTA_DM_RM bta_dm_rm_cfg[] = +{ + {BTA_ID_SYS, BTA_DM_NUM_RM_ENTRY, BTA_DM_SCATTERNET}, + {BTA_ID_PAN, BTUI_PAN_ID_NAP, BTA_ANY_ROLE}, + {BTA_ID_PAN, BTUI_PAN_ID_GN, BTA_ANY_ROLE}, + {BTA_ID_PAN, BTA_APP_ID_PAN_MULTI, BTA_MASTER_ROLE_ONLY}, + {BTA_ID_PAN, BTUI_PAN_ID_PANU, BTA_PANU_ROLE}, + {BTA_ID_HH, BTA_ALL_APP_ID, BTA_HH_ROLE}, + {BTA_ID_AV, BTA_ALL_APP_ID, BTA_AV_ROLE} +}; + + +tBTA_DM_CFG *p_bta_dm_cfg = (tBTA_DM_CFG *)&bta_dm_cfg; + +tBTA_DM_RM *p_bta_dm_rm_cfg = (tBTA_DM_RM *)&bta_dm_rm_cfg; + +#if BLE_INCLUDED == TRUE +# define BTA_DM_NUM_PM_ENTRY 21 /* number of entries in bta_dm_pm_cfg except the first */ +# define BTA_DM_NUM_PM_SPEC 15 /* number of entries in bta_dm_pm_spec */ +#else +# define BTA_DM_NUM_PM_ENTRY 19 /* number of entries in bta_dm_pm_cfg except the first */ +# define BTA_DM_NUM_PM_SPEC 13 /* number of entries in bta_dm_pm_spec */ +#endif + +tBTA_DM_PM_TYPE_QUALIFIER tBTA_DM_PM_CFG bta_dm_pm_cfg[BTA_DM_NUM_PM_ENTRY + 1] = +{ + {BTA_ID_SYS, BTA_DM_NUM_PM_ENTRY, 0}, /* reserved: specifies length of this table. */ + {BTA_ID_AG, BTA_ALL_APP_ID, 0}, /* ag uses first spec table for app id 0 */ + {BTA_ID_CT, 1, 1}, /* ct (BTA_ID_CT,APP ID=1) spec table */ + {BTA_ID_CG, BTA_ALL_APP_ID, 1}, /* cg resue ct spec table */ + {BTA_ID_DG, BTA_ALL_APP_ID, 2}, /* dg spec table */ + {BTA_ID_AV, BTA_ALL_APP_ID, 4}, /* av spec table */ + {BTA_ID_AVK, BTA_ALL_APP_ID, 12}, /* avk spec table */ + {BTA_ID_FTC, BTA_ALL_APP_ID, 6}, /* ftc spec table */ + {BTA_ID_FTS, BTA_ALL_APP_ID, 7}, /* fts spec table */ + {BTA_ID_HD, BTA_ALL_APP_ID, 3}, /* hd spec table */ + {BTA_ID_HH, BTA_ALL_APP_ID, 5}, /* hh spec table */ + {BTA_ID_PBC, BTA_ALL_APP_ID, 2}, /* reuse dg spec table */ + {BTA_ID_PBS, BTA_ALL_APP_ID, 7}, /* reuse fts spec table */ + {BTA_ID_OPC, BTA_ALL_APP_ID, 6}, /* reuse ftc spec table */ + {BTA_ID_OPS, BTA_ALL_APP_ID, 7}, /* reuse fts spec table */ + {BTA_ID_MSE, BTA_ALL_APP_ID, 7}, /* reuse fts spec table */ + // {BTA_ID_JV, BTA_JV_PM_ID_1, 6}, /* app BTA_JV_PM_ID_1, reuse ftc spec table */ + // {BTA_ID_JV, BTA_ALL_APP_ID, 7}, /* reuse fts spec table */ + {BTA_ID_HL, BTA_ALL_APP_ID, 8}, /* reuse fts spec table */ + {BTA_ID_PAN, BTUI_PAN_ID_PANU, 9}, /* PANU spec table */ + {BTA_ID_PAN, BTUI_PAN_ID_NAP, 10}, /* NAP spec table */ + {BTA_ID_HS, BTA_ALL_APP_ID, 11} /* HS spec table */ +#if BLE_INCLUDED == TRUE + ,{BTA_ID_GATTC, BTA_ALL_APP_ID, 13} /* gattc spec table */ + ,{BTA_ID_GATTS, BTA_ALL_APP_ID, 14} /* gatts spec table */ +#endif +}; + +tBTA_DM_PM_TYPE_QUALIFIER tBTA_DM_PM_SPEC bta_dm_pm_spec[BTA_DM_NUM_PM_SPEC] = +{ + /* AG : 0 */ + { + (BTA_DM_PM_SNIFF | BTA_DM_PM_PARK), /* allow park & sniff */ +#if (BTM_SSR_INCLUDED == TRUE) + (BTA_DM_PM_SSR2), /* the SSR entry */ +#endif + { + {{BTA_DM_PM_SNIFF_A2DP_IDX, 7000}, {BTA_DM_PM_NO_ACTION, 0}}, /* conn open sniff */ + {{BTA_DM_PM_NO_PREF, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* conn close */ + {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* app open */ + {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* app close */ + {{BTA_DM_PM_SNIFF_SCO_OPEN_IDX, 7000}, {BTA_DM_PM_NO_ACTION, 0}}, /* sco open, active */ + {{BTA_DM_PM_SNIFF_A2DP_IDX, 7000}, {BTA_DM_PM_NO_ACTION, 0}}, /* sco close sniff */ + {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* idle */ + {{BTA_DM_PM_ACTIVE, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* busy */ + {{BTA_DM_PM_RETRY, 7000}, {BTA_DM_PM_NO_ACTION, 0}} /* mode change retry */ + } + }, + + /* CT, CG : 1 */ + { + (BTA_DM_PM_SNIFF | BTA_DM_PM_PARK), /* allow park & sniff */ +#if (BTM_SSR_INCLUDED == TRUE) + (BTA_DM_PM_SSR2), /* the SSR entry */ +#endif + { + {{BTA_DM_PM_PARK, 5000}, {BTA_DM_PM_NO_ACTION, 0}}, /* conn open park */ + {{BTA_DM_PM_NO_PREF, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* conn close */ + {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* app open */ + {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* app close */ + {{BTA_DM_PM_SNIFF_A2DP_IDX, 5000}, {BTA_DM_PM_NO_ACTION, 0}}, /* sco open sniff */ + {{BTA_DM_PM_PARK, 5000}, {BTA_DM_PM_NO_ACTION, 0}}, /* sco close park */ + {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* idle */ + {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* busy */ + {{BTA_DM_PM_RETRY, 5000}, {BTA_DM_PM_NO_ACTION, 0}} /* mode change retry */ + } + }, + + /* DG, PBC : 2 */ + { + (BTA_DM_PM_ACTIVE), /* no power saving mode allowed */ +#if (BTM_SSR_INCLUDED == TRUE) + (BTA_DM_PM_SSR2), /* the SSR entry */ +#endif + { + {{BTA_DM_PM_SNIFF, 5000}, {BTA_DM_PM_NO_ACTION, 0}}, /* conn open active */ + {{BTA_DM_PM_NO_PREF, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* conn close */ + {{BTA_DM_PM_ACTIVE, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* app open */ + {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* app close */ + {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* sco open */ + {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* sco close */ + {{BTA_DM_PM_SNIFF, 1000}, {BTA_DM_PM_NO_ACTION, 0}}, /* idle */ + {{BTA_DM_PM_ACTIVE, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* busy */ + {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}} /* mode change retry */ + } + }, + + /* HD : 3 */ + { + (BTA_DM_PM_SNIFF | BTA_DM_PM_PARK), /* allow park & sniff */ +#if (BTM_SSR_INCLUDED == TRUE) + (BTA_DM_PM_SSR3), /* the SSR entry */ +#endif + { + {{BTA_DM_PM_SNIFF_HD_ACTIVE_IDX, 5000}, {BTA_DM_PM_NO_ACTION, 0}}, /* conn open sniff */ + {{BTA_DM_PM_NO_PREF, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* conn close */ + {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* app open */ + {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* app close */ + {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* sco open */ + {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* sco close */ + {{BTA_DM_PM_SNIFF_HD_IDLE_IDX, 5000}, {BTA_DM_PM_NO_ACTION, 0}}, /* idle */ + {{BTA_DM_PM_SNIFF_HD_ACTIVE_IDX, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* busy */ + {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}} /* mode change retry */ + } + }, + + /* AV : 4 */ + { + (BTA_DM_PM_SNIFF), /* allow sniff */ +#if (BTM_SSR_INCLUDED == TRUE) + (BTA_DM_PM_SSR2), /* the SSR entry */ +#endif + { + {{BTA_DM_PM_SNIFF_A2DP_IDX, 7000}, {BTA_DM_PM_NO_ACTION, 0}}, /* conn open sniff */ + {{BTA_DM_PM_NO_PREF, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* conn close */ + {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* app open */ + {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* app close */ + {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* sco open */ + {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* sco close */ + {{BTA_DM_PM_SNIFF_A2DP_IDX, 7000}, {BTA_DM_PM_NO_ACTION, 0}}, /* idle */ + {{BTA_DM_PM_ACTIVE, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* busy */ + {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}} /* mode change retry */ + } + }, + + /* HH : 5 */ + { + (BTA_DM_PM_SNIFF | BTA_DM_PM_PARK), /* allow park & sniff */ +#if (BTM_SSR_INCLUDED == TRUE) + (BTA_DM_PM_SSR1), /* the SSR entry */ +#endif + { + {{BTA_DM_PM_SNIFF_HH_OPEN_IDX, BTA_DM_PM_HH_OPEN_DELAY},{BTA_DM_PM_NO_ACTION, 0}}, /* conn open sniff */ + {{BTA_DM_PM_NO_PREF, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* conn close */ + {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* app open */ + {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* app close */ + {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* sco open */ + {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* sco close, used for HH suspend */ + {{BTA_DM_PM_SNIFF_HH_IDLE_IDX, BTA_DM_PM_HH_IDLE_DELAY}, {BTA_DM_PM_NO_ACTION, 0}}, /* idle */ + {{BTA_DM_PM_SNIFF_HH_ACTIVE_IDX, BTA_DM_PM_HH_ACTIVE_DELAY}, {BTA_DM_PM_NO_ACTION, 0}}, /* busy */ + {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}} /* mode change retry */ + } + }, + + /* FTC, OPC, JV : 6 */ + { + (BTA_DM_PM_SNIFF), /* allow sniff */ +#if (BTM_SSR_INCLUDED == TRUE) + (BTA_DM_PM_SSR2), /* the SSR entry */ +#endif + { + {{BTA_DM_PM_ACTIVE, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* conn open active */ + {{BTA_DM_PM_NO_PREF, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* conn close */ + {{BTA_DM_PM_ACTIVE, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* app open */ + {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* app close */ + {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* sco open */ + {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* sco close */ + {{BTA_DM_PM_SNIFF_A2DP_IDX, 5000}, {BTA_DM_PM_NO_ACTION, 0}}, /* idle */ + {{BTA_DM_PM_ACTIVE, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* busy */ + {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}} /* mode change retry */ + } + }, + + /* FTS, PBS, OPS, MSE, BTA_JV_PM_ID_1 : 7 */ + { + (BTA_DM_PM_SNIFF), /* allow sniff */ +#if (BTM_SSR_INCLUDED == TRUE) + (BTA_DM_PM_SSR2), /* the SSR entry */ +#endif + { + {{BTA_DM_PM_ACTIVE, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* conn open active */ + {{BTA_DM_PM_NO_PREF, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* conn close */ + {{BTA_DM_PM_ACTIVE, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* app open */ + {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* app close */ + {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* sco open */ + {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* sco close */ + {{BTA_DM_PM_SNIFF_A2DP_IDX, BTA_FTS_OPS_IDLE_TO_SNIFF_DELAY_MS}, {BTA_DM_PM_NO_ACTION, 0}}, /* idle */ + {{BTA_DM_PM_ACTIVE, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* busy */ + {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}} /* mode change retry */ + } + }, + + /* HL : 8 */ + { + (BTA_DM_PM_SNIFF), /* allow sniff */ +#if (BTM_SSR_INCLUDED == TRUE) + (BTA_DM_PM_SSR2), /* the SSR entry */ +#endif + { + {{BTA_DM_PM_SNIFF_A2DP_IDX, 5000}, {BTA_DM_PM_NO_ACTION, 0}}, /* conn open sniff */ + {{BTA_DM_PM_NO_PREF, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* conn close */ + {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* app open */ + {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* app close */ + {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* sco open, active */ + {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* sco close sniff */ + {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* idle */ + {{BTA_DM_PM_ACTIVE, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* busy */ + {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}} /* mode change retry */ + } + }, + + /* PANU : 9 */ + { + (BTA_DM_PM_SNIFF), /* allow sniff */ +#if (BTM_SSR_INCLUDED == TRUE) + (BTA_DM_PM_SSR2), /* the SSR entry */ +#endif + { + {{BTA_DM_PM_ACTIVE, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* conn open active */ + {{BTA_DM_PM_NO_PREF, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* conn close */ + {{BTA_DM_PM_ACTIVE, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* app open */ + {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* app close */ + {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* sco open */ + {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* sco close */ + {{BTA_DM_PM_SNIFF_A2DP_IDX, 5000}, {BTA_DM_PM_NO_ACTION, 0}}, /* idle */ + {{BTA_DM_PM_ACTIVE, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* busy */ + {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}} /* mode change retry */ + } + }, + + /* NAP : 10 */ + { + (BTA_DM_PM_SNIFF), /* allow sniff */ +#if (BTM_SSR_INCLUDED == TRUE) + (BTA_DM_PM_SSR2), /* the SSR entry */ +#endif + { + {{BTA_DM_PM_ACTIVE, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* conn open active */ + {{BTA_DM_PM_NO_PREF, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* conn close */ + {{BTA_DM_PM_ACTIVE, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* app open */ + {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* app close */ + {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* sco open */ + {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* sco close */ + {{BTA_DM_PM_SNIFF_A2DP_IDX, 5000}, {BTA_DM_PM_NO_ACTION, 0}}, /* idle */ + {{BTA_DM_PM_ACTIVE, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* busy */ + + {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}} /* mode change retry */ + } + }, + + /* HS : 11 */ + { + (BTA_DM_PM_SNIFF | BTA_DM_PM_PARK), /* allow park & sniff */ +#if (BTM_SSR_INCLUDED == TRUE) + (BTA_DM_PM_SSR2), /* the SSR entry */ +#endif + { + {{BTA_DM_PM_SNIFF, 7000}, {BTA_DM_PM_NO_ACTION, 0}}, /* conn open sniff */ + {{BTA_DM_PM_NO_PREF, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* conn close */ + {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* app open */ + {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* app close */ + {{BTA_DM_PM_SNIFF3, 7000}, {BTA_DM_PM_NO_ACTION, 0}}, /* sco open, active */ + {{BTA_DM_PM_SNIFF, 7000}, {BTA_DM_PM_NO_ACTION, 0}}, /* sco close sniff */ + {{BTA_DM_PM_SNIFF, 7000}, {BTA_DM_PM_NO_ACTION, 0}}, /* idle */ + {{BTA_DM_PM_ACTIVE, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* busy */ + {{BTA_DM_PM_RETRY, 7000}, {BTA_DM_PM_NO_ACTION, 0}} /* mode change retry */ + } + }, + + /* AVK : 12 */ + { + (BTA_DM_PM_SNIFF), /* allow sniff */ +#if (BTM_SSR_INCLUDED == TRUE) + (BTA_DM_PM_SSR2), /* the SSR entry */ +#endif + { + {{BTA_DM_PM_SNIFF, 3000}, {BTA_DM_PM_NO_ACTION, 0}}, /* conn open sniff */ + {{BTA_DM_PM_NO_PREF, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* conn close */ + {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* app open */ + {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* app close */ + {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* sco open */ + {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* sco close */ + {{BTA_DM_PM_SNIFF4, 3000}, {BTA_DM_PM_NO_ACTION, 0}}, /* idle */ + {{BTA_DM_PM_ACTIVE, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* busy */ + {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}} /* mode change retry */ + } + } + +#if BLE_INCLUDED == TRUE + /* GATTC : 13 */ + ,{ + (BTA_DM_PM_SNIFF | BTA_DM_PM_PARK), /* allow park & sniff */ +#if (BTM_SSR_INCLUDED == TRUE) + (BTA_DM_PM_SSR2), /* the SSR entry */ +#endif + { + {{BTA_DM_PM_SNIFF_A2DP_IDX, 10000}, {BTA_DM_PM_NO_ACTION, 0}}, /* conn open active */ + {{BTA_DM_PM_NO_PREF, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* conn close */ + {{BTA_DM_PM_ACTIVE, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* app open */ + {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* app close */ + {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* sco open */ + {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* sco close */ + {{BTA_DM_PM_SNIFF_A2DP_IDX, 10000}, {BTA_DM_PM_NO_ACTION, 0}}, /* idle */ + {{BTA_DM_PM_ACTIVE, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* busy */ +#if defined(AMP_INCLUDED) && (AMP_INCLUDED == TRUE) + {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* amp */ +#endif + {{BTA_DM_PM_RETRY, 5000}, {BTA_DM_PM_NO_ACTION, 0}} /* mode change retry */ + } + } + /* GATTS : 14 */ + ,{ + (BTA_DM_PM_SNIFF | BTA_DM_PM_PARK), /* allow park & sniff */ +#if (BTM_SSR_INCLUDED == TRUE) + (BTA_DM_PM_SSR2), /* the SSR entry */ +#endif + { + {{BTA_DM_PM_NO_PREF, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* conn open active */ + {{BTA_DM_PM_NO_PREF, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* conn close */ + {{BTA_DM_PM_NO_PREF, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* app open */ + {{BTA_DM_PM_NO_PREF, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* app close */ + {{BTA_DM_PM_NO_PREF, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* sco open */ + {{BTA_DM_PM_NO_PREF, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* sco close */ + {{BTA_DM_PM_NO_PREF, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* idle */ + {{BTA_DM_PM_NO_PREF, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* busy */ +#if defined(AMP_INCLUDED) && (AMP_INCLUDED == TRUE) + {{BTA_DM_PM_NO_PREF, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* amp */ +#endif + {{BTA_DM_PM_RETRY, 5000}, {BTA_DM_PM_NO_ACTION, 0}} /* mode change retry */ + } + } + +#endif + +#ifdef BTE_SIM_APP /* For Insight builds only */ + /* Entries at the end of the pm_spec table are user-defined (runtime configurable), + for power consumption experiments. + Insight finds the first user-defined entry by looking for the first BTA_DM_PM_NO_PREF. + The number of user_defined specs is defined by BTA_SWRAP_UD_PM_SPEC_COUNT */ + , + {BTA_DM_PM_NO_PREF}, /* pm_spec USER_DEFINED_0 */ + {BTA_DM_PM_NO_PREF} /* pm_spec USER_DEFINED_1 */ +#endif /* BTE_SIM_APP */ +}; + +/* Please refer to the SNIFF table definitions in bta_api.h. + * + * Adding to or Modifying the Table + * Additional sniff parameter entries can be added for BTA_DM_PM_SNIFF5 - BTA_DM_PM_SNIFF7. + * Overrides of additional table entries can be specified in bdroid_buildcfg.h. If additional + * sniff parameter entries are added or an override of an existing entry is specified in + * bdroid_buildcfg.h then the BTA_DM_PM_*_IDX defines in bta_api.h will need to be match the new + * ordering. + * + * Table Ordering + * Sniff Table entries must be ordered from highest latency (biggest interval) to lowest latency. + * If there is a conflict among the connected services the setting with the lowest latency will + * be selected. + */ +tBTA_DM_PM_TYPE_QUALIFIER tBTM_PM_PWR_MD bta_dm_pm_md[] = +{ +/* + * More sniff parameter entries can be added for + * BTA_DM_PM_SNIFF3 - BTA_DM_PM_SNIFF7, if needed. When entries are added or + * removed, BTA_DM_PM_PARK_IDX needs to be updated to reflect the actual index + * BTA_DM_PM_PARK_IDX is defined in bta_api.h and can be override by the + * bdroid_buildcfg.h settings. + * The SNIFF table entries must be in the order from highest latency (biggest + * interval) to lowest latency. If there's a conflict among the connected + * services, the setting with lowest latency wins. + */ +/* sniff modes: max interval, min interval, attempt, timeout */ + {BTA_DM_PM_SNIFF_MAX, BTA_DM_PM_SNIFF_MIN, BTA_DM_PM_SNIFF_ATTEMPT, BTA_DM_PM_SNIFF_TIMEOUT, BTM_PM_MD_SNIFF}, /* for BTA_DM_PM_SNIFF - A2DP */ + {BTA_DM_PM_SNIFF1_MAX, BTA_DM_PM_SNIFF1_MIN, BTA_DM_PM_SNIFF1_ATTEMPT, BTA_DM_PM_SNIFF1_TIMEOUT, BTM_PM_MD_SNIFF}, /* for BTA_DM_PM_SNIFF1 */ + {BTA_DM_PM_SNIFF2_MAX, BTA_DM_PM_SNIFF2_MIN, BTA_DM_PM_SNIFF2_ATTEMPT, BTA_DM_PM_SNIFF2_TIMEOUT, BTM_PM_MD_SNIFF}, /* for BTA_DM_PM_SNIFF2- HD idle */ + {BTA_DM_PM_SNIFF3_MAX, BTA_DM_PM_SNIFF3_MIN, BTA_DM_PM_SNIFF3_ATTEMPT, BTA_DM_PM_SNIFF3_TIMEOUT, BTM_PM_MD_SNIFF}, /* for BTA_DM_PM_SNIFF3- SCO open */ + {BTA_DM_PM_SNIFF4_MAX, BTA_DM_PM_SNIFF4_MIN, BTA_DM_PM_SNIFF4_ATTEMPT, BTA_DM_PM_SNIFF4_TIMEOUT, BTM_PM_MD_SNIFF}, /* for BTA_DM_PM_SNIFF4- HD active */ + {BTA_DM_PM_SNIFF5_MAX, BTA_DM_PM_SNIFF5_MIN, BTA_DM_PM_SNIFF5_ATTEMPT, BTA_DM_PM_SNIFF5_TIMEOUT, BTM_PM_MD_SNIFF}, /* for BTA_DM_PM_SNIFF5- HD active */ + {BTA_DM_PM_PARK_MAX, BTA_DM_PM_PARK_MIN, BTA_DM_PM_PARK_ATTEMPT, BTA_DM_PM_PARK_TIMEOUT, BTM_PM_MD_PARK} + +#ifdef BTE_SIM_APP /* For Insight builds only */ + /* Entries at the end of the bta_dm_pm_md table are user-defined (runtime configurable), + for power consumption experiments. + Insight finds the first user-defined entry by looking for the first 'max=0'. + The number of user_defined specs is defined by BTA_SWRAP_UD_PM_DM_COUNT */ + , + {0}, /* CONN_OPEN/SCO_CLOSE power mode settings for pm_spec USER_DEFINED_0 */ + {0}, /* SCO_OPEN power mode settings for pm_spec USER_DEFINED_0 */ + + {0}, /* CONN_OPEN/SCO_CLOSE power mode settings for pm_spec USER_DEFINED_1 */ + {0} /* SCO_OPEN power mode settings for pm_spec USER_DEFINED_1 */ +#endif /* BTE_SIM_APP */ +}; + +/* 0=max_lat -> no SSR */ +/* the smaller of the SSR max latency wins. + * the entries in this table must be from highest latency (biggest interval) to lowest latency */ +#if (BTM_SSR_INCLUDED == TRUE) +tBTA_DM_SSR_SPEC bta_dm_ssr_spec[] = +{ + /*max_lat, min_rmt_to, min_loc_to*/ + {0, 0, 0}, /* BTA_DM_PM_SSR0 - do not use SSR */ + {0, 0, 2}, /* BTA_DM_PM_SSR1 - HH, can NOT share entry with any other profile, + seting default max latency and min remote timeout as 0, + and always read individual device preference from HH module */ + {1200, 2, 2}, /* BTA_DM_PM_SSR2 - others (as long as sniff is allowed)*/ + {360, 160, 2} /* BTA_DM_PM_SSR3 - HD */ +}; + +tBTA_DM_SSR_SPEC *p_bta_dm_ssr_spec = (tBTA_DM_SSR_SPEC *)&bta_dm_ssr_spec; +#endif + +tBTA_DM_PM_CFG *p_bta_dm_pm_cfg = (tBTA_DM_PM_CFG *)&bta_dm_pm_cfg; +tBTA_DM_PM_SPEC *p_bta_dm_pm_spec = (tBTA_DM_PM_SPEC *)&bta_dm_pm_spec; +tBTM_PM_PWR_MD *p_bta_dm_pm_md = (tBTM_PM_PWR_MD *)&bta_dm_pm_md; + +/* The performance impact of EIR packet size +** +** When BTM_EIR_DEFAULT_FEC_REQUIRED is TRUE, +** 1 to 17 bytes, DM1 is used and most robust. +** 18 to 121 bytes, DM3 is used but impacts inquiry scan time with large number +** of devices.(almost double with 150 users) +** 122 to 224 bytes, DM5 is used but cause quite big performance loss even with +** small number of users. so it is not recommended. +** 225 to 240 bytes, DH5 is used without FEC but it not recommended. +** (same reason of DM5) +** +** When BTM_EIR_DEFAULT_FEC_REQUIRED is FALSE, +** 1 to 27 bytes, DH1 is used but only robust at short range. +** 28 to 183 bytes, DH3 is used but only robust at short range and impacts inquiry +** scan time with large number of devices. +** 184 to 240 bytes, DH5 is used but it not recommended. +*/ + +#if (BTA_EIR_CANNED_UUID_LIST == TRUE) + /* for example */ +const UINT8 bta_dm_eir_uuid16_list[] = { 0x08, 0x11, /* Headset */ + 0x1E, 0x11, /* Handsfree */ + 0x0E, 0x11, /* AV Remote Control */ + 0x0B, 0x11, /* Audio Sink */ +}; +#endif // BTA_EIR_CANNED_UUID_LIST + +/* Extended Inquiry Response */ +const tBTA_DM_EIR_CONF bta_dm_eir_cfg = +{ + 50, /* minimum length of local name when it is shortened */ + /* if length of local name is longer than this and EIR has not enough */ + /* room for all UUID list then local name is shortened to this length */ +#if (BTA_EIR_CANNED_UUID_LIST == TRUE) + 8, + (UINT8 *)bta_dm_eir_uuid16_list, +#else // BTA_EIR_CANNED_UUID_LIST + { /* mask of UUID list in EIR */ + 0xFFFFFFFF, /* LSB is the first UUID of the first 32 UUIDs in BTM_EIR_UUID_LKUP_TBL */ + 0xFFFFFFFF /* LSB is the first UUID of the next 32 UUIDs in BTM_EIR_UUID_LKUP_TBL */ + /* BTM_EIR_UUID_LKUP_TBL can be overrided */ + }, +#endif // BTA_EIR_CANNED_UUID_LIST + NULL, /* Inquiry TX power */ + 0, /* length of flags in bytes */ + NULL, /* flags for EIR */ + 0, /* length of manufacturer specific in bytes */ + NULL, /* manufacturer specific */ + 0, /* length of additional data in bytes */ + NULL /* additional data */ +}; +tBTA_DM_EIR_CONF *p_bta_dm_eir_cfg = (tBTA_DM_EIR_CONF*)&bta_dm_eir_cfg; diff --git a/components/bt/bluedroid/bta/dm/bta_dm_ci.c b/components/bt/bluedroid/bta/dm/bta_dm_ci.c new file mode 100755 index 0000000000..11ef0b2a2f --- /dev/null +++ b/components/bt/bluedroid/bta/dm/bta_dm_ci.c @@ -0,0 +1,117 @@ +/****************************************************************************** + * + * Copyright (C) 2003-2012 Broadcom Corporation + * + * 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 is the API implementation file for the BTA device manager. + * + ******************************************************************************/ + +#include "gki.h" +#include "bta_sys.h" +#include "bta_api.h" +#include "bta_dm_int.h" +#include +#include "bta_dm_ci.h" + + +#if (BTM_OOB_INCLUDED == TRUE) +/******************************************************************************* +** +** Function bta_dm_ci_io_req +** +** Description This function must be called in response to function +** bta_dm_co_io_req(), if *p_oob_data to BTA_OOB_UNKNOWN +** by bta_dm_co_io_req(). +** +** Returns void +** +*******************************************************************************/ +void bta_dm_ci_io_req(BD_ADDR bd_addr, tBTA_IO_CAP io_cap, tBTA_OOB_DATA oob_data, + tBTA_AUTH_REQ auth_req) + +{ + tBTA_DM_CI_IO_REQ *p_msg; + + if ((p_msg = (tBTA_DM_CI_IO_REQ *) GKI_getbuf(sizeof(tBTA_DM_CI_IO_REQ))) != NULL) + { + p_msg->hdr.event = BTA_DM_CI_IO_REQ_EVT; + bdcpy(p_msg->bd_addr, bd_addr); + p_msg->io_cap = io_cap; + p_msg->oob_data = oob_data; + p_msg->auth_req = auth_req; + bta_sys_sendmsg(p_msg); + } +} + +/******************************************************************************* +** +** Function bta_dm_ci_rmt_oob +** +** Description This function must be called in response to function +** bta_dm_co_rmt_oob() to provide the OOB data associated +** with the remote device. +** +** Returns void +** +*******************************************************************************/ +void bta_dm_ci_rmt_oob(BOOLEAN accept, BD_ADDR bd_addr, BT_OCTET16 c, BT_OCTET16 r) +{ + tBTA_DM_CI_RMT_OOB *p_msg; + + if ((p_msg = (tBTA_DM_CI_RMT_OOB *) GKI_getbuf(sizeof(tBTA_DM_CI_RMT_OOB))) != NULL) + { + p_msg->hdr.event = BTA_DM_CI_RMT_OOB_EVT; + bdcpy(p_msg->bd_addr, bd_addr); + p_msg->accept = accept; + memcpy(p_msg->c, c, BT_OCTET16_LEN); + memcpy(p_msg->r, r, BT_OCTET16_LEN); + bta_sys_sendmsg(p_msg); + } +} +#endif /* BTM_OOB_INCLUDED */ + +#if (BTM_SCO_HCI_INCLUDED == TRUE) +/******************************************************************************* +** +** Function bta_dm_sco_ci_data_ready +** +** Description This function sends an event to indicating that the phone +** has SCO data ready. +** +** Parameters event: is obtained from bta_dm_sco_co_open() function, which +** is the BTA event we want to send back to BTA module +** when there is encoded data ready. +** sco_handle: is the BTA sco handle which indicate a specific +** SCO connection. +** Returns void +** +*******************************************************************************/ +void bta_dm_sco_ci_data_ready(UINT16 event, UINT16 sco_handle) +{ + BT_HDR *p_buf; + + if ((p_buf = (BT_HDR *) GKI_getbuf(sizeof(BT_HDR))) != NULL) + { + p_buf->event = event; + p_buf->layer_specific = sco_handle; + + bta_sys_sendmsg(p_buf); + } +} +#endif diff --git a/components/bt/bluedroid/bta/dm/bta_dm_int.h b/components/bt/bluedroid/bta/dm/bta_dm_int.h new file mode 100755 index 0000000000..7b407440fc --- /dev/null +++ b/components/bt/bluedroid/bta/dm/bta_dm_int.h @@ -0,0 +1,1199 @@ +/****************************************************************************** + * + * Copyright (C) 2003-2012 Broadcom Corporation + * + * 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 is the private interface file for the BTA device manager. + * + ******************************************************************************/ +#ifndef BTA_DM_INT_H +#define BTA_DM_INT_H + +#include "bt_target.h" + +#if (BLE_INCLUDED == TRUE && (defined BTA_GATT_INCLUDED) && (BTA_GATT_INCLUDED == TRUE)) + #include "bta_gatt_api.h" +#endif + + + +/***************************************************************************** +** Constants and data types +*****************************************************************************/ + + +#define BTA_COPY_DEVICE_CLASS(coddst, codsrc) {((UINT8 *)(coddst))[0] = ((UINT8 *)(codsrc))[0]; \ + ((UINT8 *)(coddst))[1] = ((UINT8 *)(codsrc))[1]; \ + ((UINT8 *)(coddst))[2] = ((UINT8 *)(codsrc))[2];} + + +#define BTA_DM_MSG_LEN 50 + +#define BTA_SERVICE_ID_TO_SERVICE_MASK(id) (1 << (id)) + +/* DM events */ +enum +{ + /* device manager local device API events */ + BTA_DM_API_ENABLE_EVT = BTA_SYS_EVT_START(BTA_ID_DM), + BTA_DM_API_DISABLE_EVT, + BTA_DM_API_SET_NAME_EVT, + BTA_DM_API_SET_VISIBILITY_EVT, + + BTA_DM_ACL_CHANGE_EVT, + BTA_DM_API_ADD_DEVICE_EVT, + BTA_DM_API_REMOVE_ACL_EVT, + + /* security API events */ + BTA_DM_API_BOND_EVT, + BTA_DM_API_BOND_CANCEL_EVT, + BTA_DM_API_PIN_REPLY_EVT, + + /* power manger events */ + BTA_DM_PM_BTM_STATUS_EVT, + BTA_DM_PM_TIMER_EVT, + + /* simple pairing events */ + BTA_DM_API_CONFIRM_EVT, + + BTA_DM_API_SET_ENCRYPTION_EVT, + +#if (BTM_OOB_INCLUDED == TRUE) + BTA_DM_API_LOC_OOB_EVT, + BTA_DM_CI_IO_REQ_EVT, + BTA_DM_CI_RMT_OOB_EVT, +#endif /* BTM_OOB_INCLUDED */ + + +#if BLE_INCLUDED == TRUE + BTA_DM_API_ADD_BLEKEY_EVT, + BTA_DM_API_ADD_BLEDEVICE_EVT, + BTA_DM_API_BLE_PASSKEY_REPLY_EVT, + BTA_DM_API_BLE_CONFIRM_REPLY_EVT, + BTA_DM_API_BLE_SEC_GRANT_EVT, + BTA_DM_API_BLE_SET_BG_CONN_TYPE, + BTA_DM_API_BLE_CONN_PARAM_EVT, + BTA_DM_API_BLE_CONN_SCAN_PARAM_EVT, + BTA_DM_API_BLE_SCAN_PARAM_EVT, + BTA_DM_API_BLE_OBSERVE_EVT, + BTA_DM_API_UPDATE_CONN_PARAM_EVT, + /*******This event added by Yulong at 2016/9/9 to + support the random address setting for the APP******/ + BTA_DM_API_SET_RAND_ADDR_EVT, +#if BLE_PRIVACY_SPT == TRUE + BTA_DM_API_LOCAL_PRIVACY_EVT, +#endif + BTA_DM_API_BLE_ADV_PARAM_EVT, + BTA_DM_API_BLE_SET_ADV_CONFIG_EVT, + BTA_DM_API_BLE_SET_SCAN_RSP_EVT, + BTA_DM_API_BLE_BROADCAST_EVT, + BTA_DM_API_SET_DATA_LENGTH_EVT, + +#if BLE_ANDROID_CONTROLLER_SCAN_FILTER == TRUE + BTA_DM_API_CFG_FILTER_COND_EVT, + BTA_DM_API_SCAN_FILTER_SETUP_EVT, + BTA_DM_API_SCAN_FILTER_ENABLE_EVT, +#endif + BTA_DM_API_BLE_MULTI_ADV_ENB_EVT, + BTA_DM_API_BLE_MULTI_ADV_PARAM_UPD_EVT, + BTA_DM_API_BLE_MULTI_ADV_DATA_EVT, + BTA_DM_API_BLE_MULTI_ADV_DISABLE_EVT, + BTA_DM_API_BLE_SETUP_STORAGE_EVT, + BTA_DM_API_BLE_ENABLE_BATCH_SCAN_EVT, + BTA_DM_API_BLE_DISABLE_BATCH_SCAN_EVT, + BTA_DM_API_BLE_READ_SCAN_REPORTS_EVT, + BTA_DM_API_BLE_TRACK_ADVERTISER_EVT, + BTA_DM_API_BLE_ENERGY_INFO_EVT, + +#endif + + BTA_DM_API_ENABLE_TEST_MODE_EVT, + BTA_DM_API_DISABLE_TEST_MODE_EVT, + BTA_DM_API_EXECUTE_CBACK_EVT, + BTA_DM_API_REMOVE_ALL_ACL_EVT, + BTA_DM_API_REMOVE_DEVICE_EVT, + BTA_DM_MAX_EVT +}; + + +/* DM search events */ +enum +{ + /* DM search API events */ + BTA_DM_API_SEARCH_EVT = BTA_SYS_EVT_START(BTA_ID_DM_SEARCH), + BTA_DM_API_SEARCH_CANCEL_EVT, + BTA_DM_API_DISCOVER_EVT, + BTA_DM_INQUIRY_CMPL_EVT, + BTA_DM_REMT_NAME_EVT, + BTA_DM_SDP_RESULT_EVT, + BTA_DM_SEARCH_CMPL_EVT, + BTA_DM_DISCOVERY_RESULT_EVT, + BTA_DM_API_DI_DISCOVER_EVT, + BTA_DM_DISC_CLOSE_TOUT_EVT + +}; + +/* data type for BTA_DM_API_ENABLE_EVT */ +typedef struct +{ + BT_HDR hdr; + tBTA_DM_SEC_CBACK *p_sec_cback; +} tBTA_DM_API_ENABLE; + +/* data type for BTA_DM_API_SET_NAME_EVT */ +typedef struct +{ + BT_HDR hdr; + BD_NAME name; /* max 248 bytes name, plus must be Null terminated */ +} tBTA_DM_API_SET_NAME; + +/* data type for BTA_DM_API_SET_VISIBILITY_EVT */ +typedef struct +{ + BT_HDR hdr; + tBTA_DM_DISC disc_mode; + tBTA_DM_CONN conn_mode; + UINT8 pair_mode; + UINT8 conn_paired_only; +} tBTA_DM_API_SET_VISIBILITY; + +enum +{ + BTA_DM_RS_NONE, /* straight API call */ + BTA_DM_RS_OK, /* the role switch result - successful */ + BTA_DM_RS_FAIL /* the role switch result - failed */ +}; +typedef UINT8 tBTA_DM_RS_RES; + +/* data type for BTA_DM_API_SEARCH_EVT */ +typedef struct +{ + BT_HDR hdr; + tBTA_DM_INQ inq_params; + tBTA_SERVICE_MASK services; + tBTA_DM_SEARCH_CBACK * p_cback; + tBTA_DM_RS_RES rs_res; +#if BLE_INCLUDED == TRUE && BTA_GATT_INCLUDED == TRUE + UINT8 num_uuid; + tBT_UUID *p_uuid; +#endif +} tBTA_DM_API_SEARCH; + +/* data type for BTA_DM_API_DISCOVER_EVT */ +typedef struct +{ + BT_HDR hdr; + BD_ADDR bd_addr; + tBTA_SERVICE_MASK services; + tBTA_DM_SEARCH_CBACK * p_cback; + BOOLEAN sdp_search; + tBTA_TRANSPORT transport; +#if BLE_INCLUDED == TRUE && BTA_GATT_INCLUDED == TRUE + UINT8 num_uuid; + tBT_UUID *p_uuid; +#endif + tSDP_UUID uuid; +} tBTA_DM_API_DISCOVER; + +/* data type for BTA_DM_API_DI_DISC_EVT */ +typedef struct +{ + BT_HDR hdr; + BD_ADDR bd_addr; + tBTA_DISCOVERY_DB *p_sdp_db; + UINT32 len; + tBTA_DM_SEARCH_CBACK * p_cback; +}tBTA_DM_API_DI_DISC; + +/* data type for BTA_DM_API_BOND_EVT */ +typedef struct +{ + BT_HDR hdr; + BD_ADDR bd_addr; + tBTA_TRANSPORT transport; +} tBTA_DM_API_BOND; + +/* data type for BTA_DM_API_BOND_CANCEL_EVT */ +typedef struct +{ + BT_HDR hdr; + BD_ADDR bd_addr; + tBTA_TRANSPORT transport; +} tBTA_DM_API_BOND_CANCEL; + +/* data type for BTA_DM_API_PIN_REPLY_EVT */ +typedef struct +{ + BT_HDR hdr; + BD_ADDR bd_addr; + BOOLEAN accept; + UINT8 pin_len; + UINT8 p_pin[PIN_CODE_LEN]; +} tBTA_DM_API_PIN_REPLY; + +/* data type for BTA_DM_API_LOC_OOB_EVT */ +typedef struct +{ + BT_HDR hdr; +} tBTA_DM_API_LOC_OOB; + +/* data type for BTA_DM_API_CONFIRM_EVT */ +typedef struct +{ + BT_HDR hdr; + BD_ADDR bd_addr; + BOOLEAN accept; +} tBTA_DM_API_CONFIRM; + +/* data type for BTA_DM_CI_IO_REQ_EVT */ +typedef struct +{ + BT_HDR hdr; + BD_ADDR bd_addr; + tBTA_IO_CAP io_cap; + tBTA_OOB_DATA oob_data; + tBTA_AUTH_REQ auth_req; +} tBTA_DM_CI_IO_REQ; + +/* data type for BTA_DM_CI_RMT_OOB_EVT */ +typedef struct +{ + BT_HDR hdr; + BD_ADDR bd_addr; + BT_OCTET16 c; + BT_OCTET16 r; + BOOLEAN accept; +} tBTA_DM_CI_RMT_OOB; + +/* data type for BTA_DM_REMT_NAME_EVT */ +typedef struct +{ + BT_HDR hdr; + tBTA_DM_SEARCH result; +} tBTA_DM_REM_NAME; + +/* data type for tBTA_DM_DISC_RESULT */ +typedef struct +{ + BT_HDR hdr; + tBTA_DM_SEARCH result; +} tBTA_DM_DISC_RESULT; + + +/* data type for BTA_DM_INQUIRY_CMPL_EVT */ +typedef struct +{ + BT_HDR hdr; + UINT8 num; +} tBTA_DM_INQUIRY_CMPL; + +/* data type for BTA_DM_SDP_RESULT_EVT */ +typedef struct +{ + BT_HDR hdr; + UINT16 sdp_result; +} tBTA_DM_SDP_RESULT; + +/* data type for BTA_DM_ACL_CHANGE_EVT */ +typedef struct +{ + BT_HDR hdr; + tBTM_BL_EVENT event; + UINT8 busy_level; + UINT8 busy_level_flags; + BOOLEAN is_new; + UINT8 new_role; + BD_ADDR bd_addr; + UINT8 hci_status; +#if BLE_INCLUDED == TRUE + UINT16 handle; + tBT_TRANSPORT transport; +#endif +} tBTA_DM_ACL_CHANGE; + +/* data type for BTA_DM_PM_BTM_STATUS_EVT */ +typedef struct +{ + + BT_HDR hdr; + BD_ADDR bd_addr; + tBTM_PM_STATUS status; + UINT16 value; + UINT8 hci_status; + +} tBTA_DM_PM_BTM_STATUS; + +/* data type for BTA_DM_PM_TIMER_EVT */ +typedef struct +{ + BT_HDR hdr; + BD_ADDR bd_addr; + tBTA_DM_PM_ACTION pm_request; +} tBTA_DM_PM_TIMER; + + +/* data type for BTA_DM_API_ADD_DEVICE_EVT */ +typedef struct +{ + BT_HDR hdr; + BD_ADDR bd_addr; + DEV_CLASS dc; + LINK_KEY link_key; + tBTA_SERVICE_MASK tm; + BOOLEAN is_trusted; + UINT8 key_type; + tBTA_IO_CAP io_cap; + BOOLEAN link_key_known; + BOOLEAN dc_known; + BD_NAME bd_name; + UINT8 features[BTA_FEATURE_BYTES_PER_PAGE * (BTA_EXT_FEATURES_PAGE_MAX + 1)]; + UINT8 pin_length; +} tBTA_DM_API_ADD_DEVICE; + +/* data type for BTA_DM_API_REMOVE_ACL_EVT */ +typedef struct +{ + BT_HDR hdr; + BD_ADDR bd_addr; +} tBTA_DM_API_REMOVE_DEVICE; + +/* data type for BTA_DM_API_EXECUTE_CBACK_EVT */ +typedef struct +{ + BT_HDR hdr; + void * p_param; + tBTA_DM_EXEC_CBACK *p_exec_cback; +} tBTA_DM_API_EXECUTE_CBACK; + +/* data type for tBTA_DM_API_SET_ENCRYPTION */ +typedef struct +{ + BT_HDR hdr; + tBTA_TRANSPORT transport; + tBTA_DM_ENCRYPT_CBACK *p_callback; + tBTA_DM_BLE_SEC_ACT sec_act; + BD_ADDR bd_addr; +} tBTA_DM_API_SET_ENCRYPTION; + +#if BLE_INCLUDED == TRUE +typedef struct +{ + BT_HDR hdr; + BD_ADDR bd_addr; + tBTA_LE_KEY_VALUE blekey; + tBTA_LE_KEY_TYPE key_type; + +}tBTA_DM_API_ADD_BLEKEY; + +typedef struct +{ + BT_HDR hdr; + BD_ADDR bd_addr; + tBT_DEVICE_TYPE dev_type ; + tBLE_ADDR_TYPE addr_type; + +}tBTA_DM_API_ADD_BLE_DEVICE; + +typedef struct +{ + BT_HDR hdr; + BD_ADDR bd_addr; + BOOLEAN accept; + UINT32 passkey; +}tBTA_DM_API_PASSKEY_REPLY; + +typedef struct +{ + BT_HDR hdr; + BD_ADDR bd_addr; + tBTA_DM_BLE_SEC_GRANT res; +}tBTA_DM_API_BLE_SEC_GRANT; + + +typedef struct +{ + BT_HDR hdr; + tBTA_DM_BLE_CONN_TYPE bg_conn_type; + tBTA_DM_BLE_SEL_CBACK *p_select_cback; +}tBTA_DM_API_BLE_SET_BG_CONN_TYPE; + +/* set prefered BLE connection parameters for a device */ +typedef struct +{ + BT_HDR hdr; + BD_ADDR peer_bda; + UINT16 conn_int_min; + UINT16 conn_int_max; + UINT16 supervision_tout; + UINT16 slave_latency; + +}tBTA_DM_API_BLE_CONN_PARAMS; + +typedef struct +{ + BT_HDR hdr; + BD_ADDR peer_bda; + BOOLEAN privacy_enable; + +}tBTA_DM_API_ENABLE_PRIVACY; + +typedef struct +{ + BT_HDR hdr; + BOOLEAN privacy_enable; +}tBTA_DM_API_LOCAL_PRIVACY; + +/* set scan parameter for BLE connections */ +typedef struct +{ + BT_HDR hdr; + tBTA_GATTC_IF client_if; + UINT32 scan_int; + UINT32 scan_window; + tBLE_SCAN_MODE scan_mode; + tBLE_SCAN_PARAM_SETUP_CBACK scan_param_setup_cback; +}tBTA_DM_API_BLE_SCAN_PARAMS; + +/* set scan parameter for BLE connections */ +typedef struct +{ + BT_HDR hdr; + UINT16 scan_int; + UINT16 scan_window; +} tBTA_DM_API_BLE_CONN_SCAN_PARAMS; + +/* Data type for start/stop observe */ +typedef struct +{ + BT_HDR hdr; + BOOLEAN start; + UINT16 duration; + tBTA_DM_SEARCH_CBACK * p_cback; +}tBTA_DM_API_BLE_OBSERVE; + +typedef struct +{ + BT_HDR hdr; + BD_ADDR remote_bda; + UINT16 tx_data_length; +}tBTA_DM_API_BLE_SET_DATA_LENGTH; + +/* set the address for BLE device + this type added by Yulong at 2016/9/9*/ +typedef struct +{ + BT_HDR hdr; + tBLE_ADDR_TYPE addr_type; + BD_ADDR address; +}tBTA_DM_APT_SET_DEV_ADDR; + +/* set adv parameter for BLE advertising */ +typedef struct +{ + BT_HDR hdr; + UINT16 adv_int_min; + UINT16 adv_int_max; + tBLE_BD_ADDR *p_dir_bda; +}tBTA_DM_API_BLE_ADV_PARAMS; + +typedef struct +{ + BT_HDR hdr; + BOOLEAN enable; + +}tBTA_DM_API_BLE_FEATURE; + +/* multi adv data structure */ +typedef struct +{ + BT_HDR hdr; + tBTA_BLE_MULTI_ADV_CBACK *p_cback; + void *p_ref; + tBTA_BLE_ADV_PARAMS *p_params; +}tBTA_DM_API_BLE_MULTI_ADV_ENB; + +typedef struct +{ + BT_HDR hdr; + UINT8 inst_id; + tBTA_BLE_ADV_PARAMS *p_params; +}tBTA_DM_API_BLE_MULTI_ADV_PARAM; + +typedef struct +{ + BT_HDR hdr; + UINT8 inst_id; + BOOLEAN is_scan_rsp; + tBTA_BLE_AD_MASK data_mask; + tBTA_BLE_ADV_DATA *p_data; +}tBTA_DM_API_BLE_MULTI_ADV_DATA; + +typedef struct +{ + BT_HDR hdr; + UINT8 inst_id; +}tBTA_DM_API_BLE_MULTI_ADV_DISABLE; + +typedef struct +{ + BT_HDR hdr; + UINT32 data_mask; + tBTA_BLE_ADV_DATA *p_adv_cfg; + tBTA_SET_ADV_DATA_CMPL_CBACK *p_adv_data_cback; +}tBTA_DM_API_SET_ADV_CONFIG; + +typedef struct +{ + BT_HDR hdr; + UINT8 batch_scan_full_max; + UINT8 batch_scan_trunc_max; + UINT8 batch_scan_notify_threshold; + tBTA_BLE_SCAN_SETUP_CBACK *p_setup_cback; + tBTA_BLE_SCAN_THRESHOLD_CBACK *p_thres_cback; + tBTA_BLE_SCAN_REP_CBACK *p_read_rep_cback; + tBTA_DM_BLE_REF_VALUE ref_value; +} tBTA_DM_API_SET_STORAGE_CONFIG; + +typedef struct +{ + BT_HDR hdr; + tBTA_BLE_BATCH_SCAN_MODE scan_mode; + UINT32 scan_int; + UINT32 scan_window; + tBTA_BLE_DISCARD_RULE discard_rule; + tBLE_ADDR_TYPE addr_type; + tBTA_DM_BLE_REF_VALUE ref_value; +} tBTA_DM_API_ENABLE_SCAN; + +typedef struct +{ + BT_HDR hdr; + tBTA_DM_BLE_REF_VALUE ref_value; +} tBTA_DM_API_DISABLE_SCAN; + +typedef struct +{ + BT_HDR hdr; + tBTA_BLE_BATCH_SCAN_MODE scan_type; + tBTA_DM_BLE_REF_VALUE ref_value; +} tBTA_DM_API_READ_SCAN_REPORTS; + +typedef struct +{ + BT_HDR hdr; + tBTA_DM_BLE_REF_VALUE ref_value; + tBTA_BLE_TRACK_ADV_CBACK *p_track_adv_cback; +} tBTA_DM_API_TRACK_ADVERTISER; + +typedef struct +{ + BT_HDR hdr; + tBTA_BLE_ENERGY_INFO_CBACK *p_energy_info_cback; +} tBTA_DM_API_ENERGY_INFO; + +#endif /* BLE_INCLUDED */ + +/* data type for BTA_DM_API_REMOVE_ACL_EVT */ +typedef struct +{ + BT_HDR hdr; + BD_ADDR bd_addr; + BOOLEAN remove_dev; + tBTA_TRANSPORT transport; + +}tBTA_DM_API_REMOVE_ACL; + +/* data type for BTA_DM_API_REMOVE_ALL_ACL_EVT */ +typedef struct +{ + BT_HDR hdr; + tBTA_DM_LINK_TYPE link_type; + +} tBTA_DM_API_REMOVE_ALL_ACL; +typedef struct +{ + BT_HDR hdr; + BD_ADDR bd_addr; + UINT16 min_int; + UINT16 max_int; + UINT16 latency; + UINT16 timeout; +}tBTA_DM_API_UPDATE_CONN_PARAM; + +#if BLE_ANDROID_CONTROLLER_SCAN_FILTER == TRUE +typedef struct +{ + BT_HDR hdr; + tBTA_DM_BLE_SCAN_COND_OP action; + tBTA_DM_BLE_PF_COND_TYPE cond_type; + tBTA_DM_BLE_PF_FILT_INDEX filt_index; + tBTA_DM_BLE_PF_COND_PARAM *p_cond_param; + tBTA_DM_BLE_PF_CFG_CBACK *p_filt_cfg_cback; + tBTA_DM_BLE_REF_VALUE ref_value; +}tBTA_DM_API_CFG_FILTER_COND; + +typedef struct +{ + BT_HDR hdr; + UINT8 action; + tBTA_DM_BLE_PF_STATUS_CBACK *p_filt_status_cback; + tBTA_DM_BLE_REF_VALUE ref_value; +}tBTA_DM_API_ENABLE_SCAN_FILTER; + +typedef struct +{ + BT_HDR hdr; + UINT8 action; + tBTA_DM_BLE_PF_FILT_INDEX filt_index; + tBTA_DM_BLE_PF_FILT_PARAMS filt_params; + tBLE_BD_ADDR *p_target; + tBTA_DM_BLE_PF_PARAM_CBACK *p_filt_param_cback; + tBTA_DM_BLE_REF_VALUE ref_value; +}tBTA_DM_API_SCAN_FILTER_PARAM_SETUP; +#endif + +/* union of all data types */ +typedef union +{ + /* GKI event buffer header */ + BT_HDR hdr; + tBTA_DM_API_ENABLE enable; + + tBTA_DM_API_SET_NAME set_name; + + tBTA_DM_API_SET_VISIBILITY set_visibility; + + tBTA_DM_API_ADD_DEVICE add_dev; + + tBTA_DM_API_REMOVE_DEVICE remove_dev; + + tBTA_DM_API_SEARCH search; + + tBTA_DM_API_DISCOVER discover; + + tBTA_DM_API_BOND bond; + + tBTA_DM_API_BOND_CANCEL bond_cancel; + + tBTA_DM_API_PIN_REPLY pin_reply; + + tBTA_DM_API_LOC_OOB loc_oob; + tBTA_DM_API_CONFIRM confirm; + tBTA_DM_CI_IO_REQ ci_io_req; + tBTA_DM_CI_RMT_OOB ci_rmt_oob; + + tBTA_DM_REM_NAME rem_name; + + tBTA_DM_DISC_RESULT disc_result; + + tBTA_DM_INQUIRY_CMPL inq_cmpl; + + tBTA_DM_SDP_RESULT sdp_event; + + tBTA_DM_ACL_CHANGE acl_change; + + tBTA_DM_PM_BTM_STATUS pm_status; + + tBTA_DM_PM_TIMER pm_timer; + + tBTA_DM_API_DI_DISC di_disc; + + tBTA_DM_API_EXECUTE_CBACK exec_cback; + + tBTA_DM_API_SET_ENCRYPTION set_encryption; + +#if BLE_INCLUDED == TRUE + tBTA_DM_API_ADD_BLEKEY add_ble_key; + tBTA_DM_API_ADD_BLE_DEVICE add_ble_device; + tBTA_DM_API_PASSKEY_REPLY ble_passkey_reply; + tBTA_DM_API_BLE_SEC_GRANT ble_sec_grant; + tBTA_DM_API_BLE_SET_BG_CONN_TYPE ble_set_bd_conn_type; + tBTA_DM_API_BLE_CONN_PARAMS ble_set_conn_params; + tBTA_DM_API_BLE_CONN_SCAN_PARAMS ble_set_conn_scan_params; + tBTA_DM_API_BLE_SCAN_PARAMS ble_set_scan_params; + tBTA_DM_API_BLE_OBSERVE ble_observe; + tBTA_DM_API_ENABLE_PRIVACY ble_remote_privacy; + tBTA_DM_API_LOCAL_PRIVACY ble_local_privacy; + tBTA_DM_API_BLE_ADV_PARAMS ble_set_adv_params; + tBTA_DM_API_SET_ADV_CONFIG ble_set_adv_data; +#if BLE_ANDROID_CONTROLLER_SCAN_FILTER == TRUE + tBTA_DM_API_SCAN_FILTER_PARAM_SETUP ble_scan_filt_param_setup; + tBTA_DM_API_CFG_FILTER_COND ble_cfg_filter_cond; + tBTA_DM_API_ENABLE_SCAN_FILTER ble_enable_scan_filt; +#endif + tBTA_DM_API_UPDATE_CONN_PARAM ble_update_conn_params; + tBTA_DM_API_BLE_SET_DATA_LENGTH ble_set_data_length; + tBTA_DM_APT_SET_DEV_ADDR set_addr; + tBTA_DM_API_BLE_MULTI_ADV_ENB ble_multi_adv_enb; + tBTA_DM_API_BLE_MULTI_ADV_PARAM ble_multi_adv_param; + tBTA_DM_API_BLE_MULTI_ADV_DATA ble_multi_adv_data; + tBTA_DM_API_BLE_MULTI_ADV_DISABLE ble_multi_adv_disable; + + tBTA_DM_API_SET_STORAGE_CONFIG ble_set_storage; + tBTA_DM_API_ENABLE_SCAN ble_enable_scan; + tBTA_DM_API_READ_SCAN_REPORTS ble_read_reports; + tBTA_DM_API_DISABLE_SCAN ble_disable_scan; + tBTA_DM_API_TRACK_ADVERTISER ble_track_advert; + tBTA_DM_API_ENERGY_INFO ble_energy_info; +#endif + + tBTA_DM_API_REMOVE_ACL remove_acl; + tBTA_DM_API_REMOVE_ALL_ACL remove_all_acl; + +} tBTA_DM_MSG; + + +#define BTA_DM_NUM_PEER_DEVICE 7 + +#define BTA_DM_NOT_CONNECTED 0 +#define BTA_DM_CONNECTED 1 +#define BTA_DM_UNPAIRING 2 +typedef UINT8 tBTA_DM_CONN_STATE; + + +#define BTA_DM_DI_NONE 0x00 /* nothing special */ +#define BTA_DM_DI_USE_SSR 0x10 /* set this bit if ssr is supported for this link */ +#define BTA_DM_DI_AV_ACTIVE 0x20 /* set this bit if AV is active for this link */ +#define BTA_DM_DI_SET_SNIFF 0x01 /* set this bit if call BTM_SetPowerMode(sniff) */ +#define BTA_DM_DI_INT_SNIFF 0x02 /* set this bit if call BTM_SetPowerMode(sniff) & enter sniff mode */ +#define BTA_DM_DI_ACP_SNIFF 0x04 /* set this bit if peer init sniff */ +typedef UINT8 tBTA_DM_DEV_INFO; + +/* set power mode request type */ +#define BTA_DM_PM_RESTART 1 +#define BTA_DM_PM_NEW_REQ 2 +#define BTA_DM_PM_EXECUTE 3 +typedef UINT8 tBTA_DM_PM_REQ; + +typedef struct +{ + BD_ADDR peer_bdaddr; + UINT16 link_policy; + tBTA_DM_CONN_STATE conn_state; + tBTA_PREF_ROLES pref_role; + BOOLEAN in_use; + tBTA_DM_DEV_INFO info; + tBTA_DM_ENCRYPT_CBACK *p_encrypt_cback; +#if (BTM_SSR_INCLUDED == TRUE) + tBTM_PM_STATUS prev_low; /* previous low power mode used */ +#endif + tBTA_DM_PM_ACTION pm_mode_attempted; + tBTA_DM_PM_ACTION pm_mode_failed; + BOOLEAN remove_dev_pending; +#if BLE_INCLUDED == TRUE + UINT16 conn_handle; + tBT_TRANSPORT transport; +#endif +} tBTA_DM_PEER_DEVICE; + + + +/* structure to store list of + active connections */ +typedef struct +{ + tBTA_DM_PEER_DEVICE peer_device[BTA_DM_NUM_PEER_DEVICE]; + UINT8 count; +#if BLE_INCLUDED == TRUE + UINT8 le_count; +#endif +} tBTA_DM_ACTIVE_LINK; + + +typedef struct +{ + BD_ADDR peer_bdaddr; + tBTA_SYS_ID id; + UINT8 app_id; + tBTA_SYS_CONN_STATUS state; + BOOLEAN new_request; + +} tBTA_DM_SRVCS; + +#ifndef BTA_DM_NUM_CONN_SRVS +#define BTA_DM_NUM_CONN_SRVS 10 +#endif + +typedef struct +{ + + UINT8 count; + tBTA_DM_SRVCS conn_srvc[BTA_DM_NUM_CONN_SRVS]; + +} tBTA_DM_CONNECTED_SRVCS; + +typedef struct +{ +#define BTA_DM_PM_SNIFF_TIMER_IDX 0 +#define BTA_DM_PM_PARK_TIMER_IDX 1 +#define BTA_DM_PM_SUSPEND_TIMER_IDX 2 +#define BTA_DM_PM_MODE_TIMER_MAX 3 + /* + * Keep three different timers for PARK, SNIFF and SUSPEND if TBFC is + * supported. + */ + TIMER_LIST_ENT timer[BTA_DM_PM_MODE_TIMER_MAX]; + + UINT8 srvc_id[BTA_DM_PM_MODE_TIMER_MAX]; + UINT8 pm_action[BTA_DM_PM_MODE_TIMER_MAX]; + UINT8 active; /* number of active timer */ + + BD_ADDR peer_bdaddr; + BOOLEAN in_use; +} tBTA_PM_TIMER; + +extern tBTA_DM_CONNECTED_SRVCS bta_dm_conn_srvcs; + +#define BTA_DM_NUM_PM_TIMER 7 + +/* DM control block */ +typedef struct +{ + BOOLEAN is_bta_dm_active; + tBTA_DM_ACTIVE_LINK device_list; + tBTA_DM_SEC_CBACK *p_sec_cback; +#if ((defined BLE_INCLUDED) && (BLE_INCLUDED == TRUE)) + tBTA_BLE_SCAN_SETUP_CBACK *p_setup_cback; + tBTA_DM_BLE_PF_CFG_CBACK *p_scan_filt_cfg_cback; + tBTA_DM_BLE_PF_STATUS_CBACK *p_scan_filt_status_cback; + tBTA_DM_BLE_PF_PARAM_CBACK *p_scan_filt_param_cback; + tBTA_BLE_MULTI_ADV_CBACK *p_multi_adv_cback; + tBTA_BLE_ENERGY_INFO_CBACK *p_energy_info_cback; +#endif + UINT16 state; + BOOLEAN disabling; + TIMER_LIST_ENT disable_timer; + UINT32 wbt_sdp_handle; /* WIDCOMM Extensions SDP record handle */ + UINT8 wbt_scn; /* WIDCOMM Extensions SCN */ + UINT8 num_master_only; + UINT8 pm_id; + tBTA_PM_TIMER pm_timer[BTA_DM_NUM_PM_TIMER]; + UINT32 role_policy_mask; /* the bits set indicates the modules that wants to remove role switch from the default link policy */ + UINT16 cur_policy; /* current default link policy */ + UINT16 rs_event; /* the event waiting for role switch */ + UINT8 cur_av_count; /* current AV connecions */ + BOOLEAN disable_pair_mode; /* disable pair mode or not */ + BOOLEAN conn_paired_only; /* allow connectable to paired device only or not */ + tBTA_DM_API_SEARCH search_msg; + UINT16 page_scan_interval; + UINT16 page_scan_window; + UINT16 inquiry_scan_interval; + UINT16 inquiry_scan_window; + + /* Storage for pin code request parameters */ + BD_ADDR pin_bd_addr; + DEV_CLASS pin_dev_class; + tBTA_DM_SEC_EVT pin_evt; + UINT32 num_val; /* the numeric value for comparison. If just_works, do not show this number to UI */ + BOOLEAN just_works; /* TRUE, if "Just Works" association model */ +#if ( BTA_EIR_CANNED_UUID_LIST != TRUE ) + /* store UUID list for EIR */ + TIMER_LIST_ENT app_ready_timer; + UINT32 eir_uuid[BTM_EIR_SERVICE_ARRAY_SIZE]; +#if (BTA_EIR_SERVER_NUM_CUSTOM_UUID > 0) + tBT_UUID custom_uuid[BTA_EIR_SERVER_NUM_CUSTOM_UUID]; +#endif + +#endif + + + tBTA_DM_ENCRYPT_CBACK *p_encrypt_cback; + TIMER_LIST_ENT switch_delay_timer; + +} tBTA_DM_CB; + +#ifndef BTA_DM_SDP_DB_SIZE +#define BTA_DM_SDP_DB_SIZE 250 +#endif + +/* DM search control block */ +typedef struct +{ + + tBTA_DM_SEARCH_CBACK * p_search_cback; + tBTM_INQ_INFO * p_btm_inq_info; + tBTA_SERVICE_MASK services; + tBTA_SERVICE_MASK services_to_search; + tBTA_SERVICE_MASK services_found; + tSDP_DISCOVERY_DB * p_sdp_db; + UINT16 state; + BD_ADDR peer_bdaddr; + BOOLEAN name_discover_done; + BD_NAME peer_name; + TIMER_LIST_ENT search_timer; + UINT8 service_index; + tBTA_DM_MSG * p_search_queue; /* search or discover commands during search cancel stored here */ + BOOLEAN wait_disc; + BOOLEAN sdp_results; + tSDP_UUID uuid; + UINT8 peer_scn; + BOOLEAN sdp_search; + BOOLEAN cancel_pending; /* inquiry cancel is pending */ + tBTA_TRANSPORT transport; +#if ((defined BLE_INCLUDED) && (BLE_INCLUDED == TRUE)) + tBTA_DM_SEARCH_CBACK * p_scan_cback; +#if ((defined BTA_GATT_INCLUDED) && (BTA_GATT_INCLUDED == TRUE)) + tBTA_GATTC_IF client_if; + UINT8 num_uuid; + tBT_UUID *p_srvc_uuid; + UINT8 uuid_to_search; + BOOLEAN gatt_disc_active; + UINT16 conn_id; + UINT8 * p_ble_rawdata; + UINT32 ble_raw_size; + UINT32 ble_raw_used; + TIMER_LIST_ENT gatt_close_timer; /* GATT channel close delay timer */ + BD_ADDR pending_close_bda; /* pending GATT channel remote device address */ +#endif +#endif + + +} tBTA_DM_SEARCH_CB; + +/* DI control block */ +typedef struct +{ + tSDP_DISCOVERY_DB * p_di_db; /* pointer to the DI discovery database */ + UINT8 di_num; /* total local DI record number */ + UINT32 di_handle[BTA_DI_NUM_MAX]; /* local DI record handle, the first one is primary record */ +}tBTA_DM_DI_CB; + +/* DM search state */ +enum +{ + + BTA_DM_SEARCH_IDLE, + BTA_DM_SEARCH_ACTIVE, + BTA_DM_SEARCH_CANCELLING, + BTA_DM_DISCOVER_ACTIVE + +}; + + + +typedef struct +{ + DEV_CLASS dev_class; /* local device class */ + UINT16 policy_settings; /* link policy setting hold, sniff, park, MS switch */ + UINT16 page_timeout; /* timeout for page in slots */ + UINT16 link_timeout; /* link supervision timeout in slots */ + BOOLEAN avoid_scatter; /* TRUE to avoid scatternet when av is streaming (be the master) */ + +} tBTA_DM_CFG; + +extern const UINT32 bta_service_id_to_btm_srv_id_lkup_tbl[]; + + +typedef struct +{ + UINT8 id; + UINT8 app_id; + UINT8 cfg; + +} tBTA_DM_RM ; + +extern tBTA_DM_CFG *p_bta_dm_cfg; +extern tBTA_DM_RM *p_bta_dm_rm_cfg; + +typedef struct +{ + + UINT8 id; + UINT8 app_id; + UINT8 spec_idx; /* index of spec table to use */ + +} tBTA_DM_PM_CFG; + + +typedef struct +{ + + tBTA_DM_PM_ACTION power_mode; + UINT16 timeout; + +} tBTA_DM_PM_ACTN; + +typedef struct +{ + + UINT8 allow_mask; /* mask of sniff/hold/park modes to allow */ +#if (BTM_SSR_INCLUDED == TRUE) + UINT8 ssr; /* set SSR on conn open/unpark */ +#endif + tBTA_DM_PM_ACTN actn_tbl [BTA_DM_PM_NUM_EVTS][2]; + +} tBTA_DM_PM_SPEC; + +typedef struct +{ + UINT16 max_lat; + UINT16 min_rmt_to; + UINT16 min_loc_to; +} tBTA_DM_SSR_SPEC; + +typedef struct +{ + UINT16 manufacturer; + UINT16 lmp_sub_version; + UINT8 lmp_version; +}tBTA_DM_LMP_VER_INFO; + +extern tBTA_DM_PM_CFG *p_bta_dm_pm_cfg; +extern tBTA_DM_PM_SPEC *p_bta_dm_pm_spec; +extern tBTM_PM_PWR_MD *p_bta_dm_pm_md; +#if (BTM_SSR_INCLUDED == TRUE) +extern tBTA_DM_SSR_SPEC *p_bta_dm_ssr_spec; +#endif + +/* update dynamic BRCM Aware EIR data */ +extern const tBTA_DM_EIR_CONF bta_dm_eir_cfg; +extern tBTA_DM_EIR_CONF *p_bta_dm_eir_cfg; + +/* DM control block */ +#if BTA_DYNAMIC_MEMORY == FALSE +extern tBTA_DM_CB bta_dm_cb; +#else +extern tBTA_DM_CB *bta_dm_cb_ptr; +#define bta_dm_cb (*bta_dm_cb_ptr) +#endif + +/* DM search control block */ +#if BTA_DYNAMIC_MEMORY == FALSE +extern tBTA_DM_SEARCH_CB bta_dm_search_cb; +#else +extern tBTA_DM_SEARCH_CB *bta_dm_search_cb_ptr; +#define bta_dm_search_cb (*bta_dm_search_cb_ptr) +#endif + +/* DI control block */ +#if BTA_DYNAMIC_MEMORY == FALSE +extern tBTA_DM_DI_CB bta_dm_di_cb; +#else +extern tBTA_DM_DI_CB *bta_dm_di_cb_ptr; +#define bta_dm_di_cb (*bta_dm_di_cb_ptr) +#endif + +extern BOOLEAN bta_dm_sm_execute(BT_HDR *p_msg); +extern void bta_dm_sm_disable( void ); +extern BOOLEAN bta_dm_search_sm_execute(BT_HDR *p_msg); +extern void bta_dm_search_sm_disable( void ); + + +extern void bta_dm_enable (tBTA_DM_MSG *p_data); +extern void bta_dm_disable (tBTA_DM_MSG *p_data); +extern void bta_dm_set_dev_name (tBTA_DM_MSG *p_data); +extern void bta_dm_set_visibility (tBTA_DM_MSG *p_data); + +extern void bta_dm_set_scan_config(tBTA_DM_MSG *p_data); +extern void bta_dm_vendor_spec_command(tBTA_DM_MSG *p_data); +extern void bta_dm_bond (tBTA_DM_MSG *p_data); +extern void bta_dm_bond_cancel (tBTA_DM_MSG *p_data); +extern void bta_dm_pin_reply (tBTA_DM_MSG *p_data); +extern void bta_dm_acl_change(tBTA_DM_MSG *p_data); +extern void bta_dm_add_device (tBTA_DM_MSG *p_data); +extern void bta_dm_remove_device (tBTA_DM_MSG *p_data); +extern void bta_dm_close_acl(tBTA_DM_MSG *p_data); + + +extern void bta_dm_pm_btm_status(tBTA_DM_MSG *p_data); +extern void bta_dm_pm_timer(tBTA_DM_MSG *p_data); +extern void bta_dm_add_ampkey (tBTA_DM_MSG *p_data); + +#if BLE_INCLUDED == TRUE +extern void bta_dm_add_blekey (tBTA_DM_MSG *p_data); +extern void bta_dm_add_ble_device (tBTA_DM_MSG *p_data); +extern void bta_dm_ble_passkey_reply (tBTA_DM_MSG *p_data); +extern void bta_dm_ble_confirm_reply (tBTA_DM_MSG *p_data); +extern void bta_dm_security_grant (tBTA_DM_MSG *p_data); +extern void bta_dm_ble_set_bg_conn_type (tBTA_DM_MSG *p_data); +extern void bta_dm_ble_set_conn_params (tBTA_DM_MSG *p_data); +extern void bta_dm_ble_set_scan_params(tBTA_DM_MSG *p_data); +extern void bta_dm_ble_set_conn_scan_params (tBTA_DM_MSG *p_data); +extern void bta_dm_close_gatt_conn(tBTA_DM_MSG *p_data); +extern void bta_dm_ble_observe (tBTA_DM_MSG *p_data); +extern void bta_dm_ble_update_conn_params (tBTA_DM_MSG *p_data); +extern void bta_dm_ble_set_rand_address(tBTA_DM_MSG *p_data); +extern void bta_dm_ble_config_local_privacy (tBTA_DM_MSG *p_data); +extern void bta_dm_ble_set_adv_params (tBTA_DM_MSG *p_data); +extern void bta_dm_ble_set_adv_config (tBTA_DM_MSG *p_data); +extern void bta_dm_ble_set_scan_rsp (tBTA_DM_MSG *p_data); +extern void bta_dm_ble_broadcast (tBTA_DM_MSG *p_data); +extern void bta_dm_ble_set_data_length(tBTA_DM_MSG *p_data); + +#if BLE_ANDROID_CONTROLLER_SCAN_FILTER == TRUE +extern void bta_dm_cfg_filter_cond (tBTA_DM_MSG *p_data); +extern void bta_dm_scan_filter_param_setup (tBTA_DM_MSG *p_data); +extern void bta_dm_enable_scan_filter(tBTA_DM_MSG *p_data); +#endif +extern void btm_dm_ble_multi_adv_disable(tBTA_DM_MSG *p_data); +extern void bta_dm_ble_multi_adv_data(tBTA_DM_MSG *p_data); +extern void bta_dm_ble_multi_adv_upd_param(tBTA_DM_MSG *p_data); +extern void bta_dm_ble_multi_adv_enb(tBTA_DM_MSG *p_data); + +extern void bta_dm_ble_setup_storage(tBTA_DM_MSG *p_data); +extern void bta_dm_ble_enable_batch_scan(tBTA_DM_MSG * p_data); +extern void bta_dm_ble_disable_batch_scan(tBTA_DM_MSG * p_data); +extern void bta_dm_ble_read_scan_reports(tBTA_DM_MSG * p_data); +extern void bta_dm_ble_track_advertiser(tBTA_DM_MSG * p_data); +extern void bta_dm_ble_get_energy_info(tBTA_DM_MSG *p_data); + +#endif +extern void bta_dm_set_encryption(tBTA_DM_MSG *p_data); +extern void bta_dm_confirm(tBTA_DM_MSG *p_data); +#if (BTM_OOB_INCLUDED == TRUE) +extern void bta_dm_loc_oob(tBTA_DM_MSG *p_data); +extern void bta_dm_ci_io_req_act(tBTA_DM_MSG *p_data); +extern void bta_dm_ci_rmt_oob_act(tBTA_DM_MSG *p_data); +#endif /* BTM_OOB_INCLUDED */ + +extern void bta_dm_init_pm(void); +extern void bta_dm_disable_pm(void); + +extern UINT8 bta_dm_get_av_count(void); +extern void bta_dm_search_start (tBTA_DM_MSG *p_data); +extern void bta_dm_search_cancel (tBTA_DM_MSG *p_data); +extern void bta_dm_discover (tBTA_DM_MSG *p_data); +extern void bta_dm_di_disc (tBTA_DM_MSG *p_data); +extern void bta_dm_inq_cmpl (tBTA_DM_MSG *p_data); +extern void bta_dm_rmt_name (tBTA_DM_MSG *p_data); +extern void bta_dm_sdp_result (tBTA_DM_MSG *p_data); +extern void bta_dm_search_cmpl (tBTA_DM_MSG *p_data); +extern void bta_dm_free_sdp_db (tBTA_DM_MSG *p_data); +extern void bta_dm_disc_result (tBTA_DM_MSG *p_data); +extern void bta_dm_search_result (tBTA_DM_MSG *p_data); +extern void bta_dm_discovery_cmpl (tBTA_DM_MSG *p_data); +extern void bta_dm_queue_search (tBTA_DM_MSG *p_data); +extern void bta_dm_queue_disc (tBTA_DM_MSG *p_data); +extern void bta_dm_search_clear_queue (tBTA_DM_MSG *p_data); +extern void bta_dm_search_cancel_cmpl (tBTA_DM_MSG *p_data); +extern void bta_dm_search_cancel_notify (tBTA_DM_MSG *p_data); +extern void bta_dm_search_cancel_transac_cmpl(tBTA_DM_MSG *p_data); +extern void bta_dm_disc_rmt_name (tBTA_DM_MSG *p_data); +extern tBTA_DM_PEER_DEVICE * bta_dm_find_peer_device(BD_ADDR peer_addr); + +extern void bta_dm_pm_active(BD_ADDR peer_addr); + +void bta_dm_eir_update_uuid(UINT16 uuid16, BOOLEAN adding); + +extern void bta_dm_enable_test_mode(tBTA_DM_MSG *p_data); +extern void bta_dm_disable_test_mode(tBTA_DM_MSG *p_data); +extern void bta_dm_execute_callback(tBTA_DM_MSG *p_data); + + +extern void bta_dm_remove_all_acl(tBTA_DM_MSG *p_data); +#endif /* BTA_DM_INT_H */ diff --git a/components/bt/bluedroid/bta/dm/bta_dm_main.c b/components/bt/bluedroid/bta/dm/bta_dm_main.c new file mode 100755 index 0000000000..40f8e0b214 --- /dev/null +++ b/components/bt/bluedroid/bta/dm/bta_dm_main.c @@ -0,0 +1,376 @@ +/****************************************************************************** + * + * Copyright (C) 2003-2012 Broadcom Corporation + * + * 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 is the main implementation file for the BTA device manager. + * + ******************************************************************************/ + +#include "bta_api.h" +#include "bta_sys.h" +#include "bta_dm_int.h" + + +/***************************************************************************** +** Constants and types +*****************************************************************************/ + +#if BTA_DYNAMIC_MEMORY == FALSE +tBTA_DM_CB bta_dm_cb; +tBTA_DM_SEARCH_CB bta_dm_search_cb; +tBTA_DM_DI_CB bta_dm_di_cb; +#endif + + +#define BTA_DM_NUM_ACTIONS (BTA_DM_MAX_EVT & 0x00ff) + +/* type for action functions */ +typedef void (*tBTA_DM_ACTION)(tBTA_DM_MSG *p_data); + +/* action function list */ +const tBTA_DM_ACTION bta_dm_action[BTA_DM_MAX_EVT] = +{ + + /* device manager local device API events */ + bta_dm_enable, /* 0 BTA_DM_API_ENABLE_EVT */ + bta_dm_disable, /* 1 BTA_DM_API_DISABLE_EVT */ + bta_dm_set_dev_name, /* 2 BTA_DM_API_SET_NAME_EVT */ + bta_dm_set_visibility, /* 3 BTA_DM_API_SET_VISIBILITY_EVT */ + bta_dm_acl_change, /* 8 BTA_DM_ACL_CHANGE_EVT */ + bta_dm_add_device, /* 9 BTA_DM_API_ADD_DEVICE_EVT */ + bta_dm_close_acl, /* 10 BTA_DM_API_ADD_DEVICE_EVT */ + + /* security API events */ + bta_dm_bond, /* 11 BTA_DM_API_BOND_EVT */ + bta_dm_bond_cancel, /* 12 BTA_DM_API_BOND_CANCEL_EVT */ + bta_dm_pin_reply, /* 13 BTA_DM_API_PIN_REPLY_EVT */ + + /* power manger events */ + bta_dm_pm_btm_status, /* 16 BTA_DM_PM_BTM_STATUS_EVT */ + bta_dm_pm_timer, /* 17 BTA_DM_PM_TIMER_EVT*/ + + /* simple pairing events */ + bta_dm_confirm, /* 18 BTA_DM_API_CONFIRM_EVT */ + + bta_dm_set_encryption, /* BTA_DM_API_SET_ENCRYPTION_EVT */ + +#if (BTM_OOB_INCLUDED == TRUE) + bta_dm_loc_oob, /* 20 BTA_DM_API_LOC_OOB_EVT */ + bta_dm_ci_io_req_act, /* 21 BTA_DM_CI_IO_REQ_EVT */ + bta_dm_ci_rmt_oob_act, /* 22 BTA_DM_CI_RMT_OOB_EVT */ +#endif /* BTM_OOB_INCLUDED */ + + +#if BLE_INCLUDED == TRUE + bta_dm_add_blekey, /* BTA_DM_API_ADD_BLEKEY_EVT */ + bta_dm_add_ble_device, /* BTA_DM_API_ADD_BLEDEVICE_EVT */ + bta_dm_ble_passkey_reply, /* BTA_DM_API_BLE_PASSKEY_REPLY_EVT */ + bta_dm_ble_confirm_reply, /* BTA_DM_API_BLE_CONFIRM_REPLY_EVT */ + bta_dm_security_grant, + bta_dm_ble_set_bg_conn_type, + bta_dm_ble_set_conn_params, /* BTA_DM_API_BLE_CONN_PARAM_EVT */ + bta_dm_ble_set_conn_scan_params, /* BTA_DM_API_BLE_CONN_SCAN_PARAM_EVT */ + bta_dm_ble_set_scan_params, /* BTA_DM_API_BLE_SCAN_PARAM_EVT */ + bta_dm_ble_observe, + bta_dm_ble_update_conn_params, /* BTA_DM_API_UPDATE_CONN_PARAM_EVT */ + /*******This handler function added by Yulong at 2016/9/9 to + support the random address setting for the APP******/ + bta_dm_ble_set_rand_address, /*BTA_DM_API_SET_RAND_ADDR_EVT*/ +#if BLE_PRIVACY_SPT == TRUE + bta_dm_ble_config_local_privacy, /* BTA_DM_API_LOCAL_PRIVACY_EVT */ +#endif + bta_dm_ble_set_adv_params, /* BTA_DM_API_BLE_ADV_PARAM_EVT */ + bta_dm_ble_set_adv_config, /* BTA_DM_API_BLE_SET_ADV_CONFIG_EVT */ + bta_dm_ble_set_scan_rsp, /* BTA_DM_API_BLE_SET_SCAN_RSPT */ + bta_dm_ble_broadcast, /* BTA_DM_API_BLE_BROADCAST_EVT */ + bta_dm_ble_set_data_length, /* BTA_DM_API_SET_DATA_LENGTH_EVT */ +#if BLE_ANDROID_CONTROLLER_SCAN_FILTER == TRUE + bta_dm_cfg_filter_cond, /* BTA_DM_API_CFG_FILTER_COND_EVT */ + bta_dm_scan_filter_param_setup, /* BTA_DM_API_SCAN_FILTER_SETUP_EVT */ + bta_dm_enable_scan_filter, /* BTA_DM_API_SCAN_FILTER_ENABLE_EVT */ +#endif + bta_dm_ble_multi_adv_enb, /* BTA_DM_API_BLE_MULTI_ADV_ENB_EVT*/ + bta_dm_ble_multi_adv_upd_param, /* BTA_DM_API_BLE_MULTI_ADV_PARAM_UPD_EVT */ + bta_dm_ble_multi_adv_data, /* BTA_DM_API_BLE_MULTI_ADV_DATA_EVT */ + btm_dm_ble_multi_adv_disable, /* BTA_DM_API_BLE_MULTI_ADV_DISABLE_EVT */ + bta_dm_ble_setup_storage, /* BTA_DM_API_BLE_SETUP_STORAGE_EVT */ + bta_dm_ble_enable_batch_scan, /* BTA_DM_API_BLE_ENABLE_BATCH_SCAN_EVT */ + bta_dm_ble_disable_batch_scan, /* BTA_DM_API_BLE_DISABLE_BATCH_SCAN_EVT */ + bta_dm_ble_read_scan_reports, /* BTA_DM_API_BLE_READ_SCAN_REPORTS_EVT */ + bta_dm_ble_track_advertiser, /* BTA_DM_API_BLE_TRACK_ADVERTISER_EVT */ + bta_dm_ble_get_energy_info, /* BTA_DM_API_BLE_ENERGY_INFO_EVT */ +#endif + + bta_dm_enable_test_mode, /* BTA_DM_API_ENABLE_TEST_MODE_EVT */ + bta_dm_disable_test_mode, /* BTA_DM_API_DISABLE_TEST_MODE_EVT */ + bta_dm_execute_callback, /* BTA_DM_API_EXECUTE_CBACK_EVT */ + + bta_dm_remove_all_acl, /* BTA_DM_API_REMOVE_ALL_ACL_EVT */ + bta_dm_remove_device, /* BTA_DM_API_REMOVE_DEVICE_EVT */ +}; + + + +/* state machine action enumeration list */ +enum +{ + BTA_DM_API_SEARCH, /* 0 bta_dm_search_start */ + BTA_DM_API_SEARCH_CANCEL, /* 1 bta_dm_search_cancel */ + BTA_DM_API_DISCOVER, /* 2 bta_dm_discover */ + BTA_DM_INQUIRY_CMPL, /* 3 bta_dm_inq_cmpl */ + BTA_DM_REMT_NAME, /* 4 bta_dm_rmt_name */ + BTA_DM_SDP_RESULT, /* 5 bta_dm_sdp_result */ + BTA_DM_SEARCH_CMPL, /* 6 bta_dm_search_cmpl*/ + BTA_DM_FREE_SDP_DB, /* 7 bta_dm_free_sdp_db */ + BTA_DM_DISC_RESULT, /* 8 bta_dm_disc_result */ + BTA_DM_SEARCH_RESULT, /* 9 bta_dm_search_result */ + BTA_DM_QUEUE_SEARCH, /* 10 bta_dm_queue_search */ + BTA_DM_QUEUE_DISC, /* 11 bta_dm_queue_disc */ + BTA_DM_SEARCH_CLEAR_QUEUE, /* 12 bta_dm_search_clear_queue */ + BTA_DM_SEARCH_CANCEL_CMPL, /* 13 bta_dm_search_cancel_cmpl */ + BTA_DM_SEARCH_CANCEL_NOTIFY, /* 14 bta_dm_search_cancel_notify */ + BTA_DM_SEARCH_CANCEL_TRANSAC_CMPL, /* 15 bta_dm_search_cancel_transac_cmpl */ + BTA_DM_DISC_RMT_NAME, /* 16 bta_dm_disc_rmt_name */ + BTA_DM_API_DI_DISCOVER, /* 17 bta_dm_di_disc */ +#if BLE_INCLUDED == TRUE + BTA_DM_CLOSE_GATT_CONN, /* 18 bta_dm_close_gatt_conn */ +#endif + BTA_DM_SEARCH_NUM_ACTIONS /* 19 */ +}; + + +/* action function list */ +const tBTA_DM_ACTION bta_dm_search_action[] = +{ + + bta_dm_search_start, /* 0 BTA_DM_API_SEARCH */ + bta_dm_search_cancel, /* 1 BTA_DM_API_SEARCH_CANCEL */ + bta_dm_discover, /* 2 BTA_DM_API_DISCOVER */ + bta_dm_inq_cmpl, /* 3 BTA_DM_INQUIRY_CMPL */ + bta_dm_rmt_name, /* 4 BTA_DM_REMT_NAME */ + bta_dm_sdp_result, /* 5 BTA_DM_SDP_RESULT */ + bta_dm_search_cmpl, /* 6 BTA_DM_SEARCH_CMPL */ + bta_dm_free_sdp_db, /* 7 BTA_DM_FREE_SDP_DB */ + bta_dm_disc_result, /* 8 BTA_DM_DISC_RESULT */ + bta_dm_search_result, /* 9 BTA_DM_SEARCH_RESULT */ + bta_dm_queue_search, /* 10 BTA_DM_QUEUE_SEARCH */ + bta_dm_queue_disc, /* 11 BTA_DM_QUEUE_DISC */ + bta_dm_search_clear_queue, /* 12 BTA_DM_SEARCH_CLEAR_QUEUE */ + bta_dm_search_cancel_cmpl, /* 13 BTA_DM_SEARCH_CANCEL_CMPL */ + bta_dm_search_cancel_notify, /* 14 BTA_DM_SEARCH_CANCEL_NOTIFY */ + bta_dm_search_cancel_transac_cmpl, /* 15 BTA_DM_SEARCH_CANCEL_TRANSAC_CMPL */ + bta_dm_disc_rmt_name, /* 16 BTA_DM_DISC_RMT_NAME */ + bta_dm_di_disc /* 17 BTA_DM_API_DI_DISCOVER */ +#if BLE_INCLUDED == TRUE + ,bta_dm_close_gatt_conn +#endif +}; + +#define BTA_DM_SEARCH_IGNORE BTA_DM_SEARCH_NUM_ACTIONS +/* state table information */ +#define BTA_DM_SEARCH_ACTIONS 2 /* number of actions */ +#define BTA_DM_SEARCH_NEXT_STATE 2 /* position of next state */ +#define BTA_DM_SEARCH_NUM_COLS 3 /* number of columns in state tables */ + + + +/* state table for listen state */ +const UINT8 bta_dm_search_idle_st_table[][BTA_DM_SEARCH_NUM_COLS] = +{ + +/* Event Action 1 Action 2 Next State */ +/* API_SEARCH */ {BTA_DM_API_SEARCH, BTA_DM_SEARCH_IGNORE, BTA_DM_SEARCH_ACTIVE}, +/* API_SEARCH_CANCEL */ {BTA_DM_SEARCH_CANCEL_NOTIFY, BTA_DM_SEARCH_IGNORE, BTA_DM_SEARCH_IDLE}, +/* API_SEARCH_DISC */ {BTA_DM_API_DISCOVER, BTA_DM_SEARCH_IGNORE, BTA_DM_DISCOVER_ACTIVE}, +/* INQUIRY_CMPL */ {BTA_DM_SEARCH_IGNORE, BTA_DM_SEARCH_IGNORE, BTA_DM_SEARCH_IDLE}, +/* REMT_NAME_EVT */ {BTA_DM_SEARCH_IGNORE, BTA_DM_SEARCH_IGNORE, BTA_DM_SEARCH_IDLE}, +/* SDP_RESULT_EVT */ {BTA_DM_FREE_SDP_DB, BTA_DM_SEARCH_IGNORE, BTA_DM_SEARCH_IDLE}, +/* SEARCH_CMPL_EVT */ {BTA_DM_SEARCH_IGNORE, BTA_DM_SEARCH_IGNORE, BTA_DM_SEARCH_IDLE}, +/* DISCV_RES_EVT */ {BTA_DM_SEARCH_IGNORE, BTA_DM_SEARCH_IGNORE, BTA_DM_SEARCH_IDLE}, +/* API_DI_DISCOVER_EVT */ {BTA_DM_API_DI_DISCOVER, BTA_DM_SEARCH_IGNORE, BTA_DM_SEARCH_ACTIVE} +#if BLE_INCLUDED == TRUE +/* DISC_CLOSE_TOUT_EVT */ ,{BTA_DM_CLOSE_GATT_CONN, BTA_DM_SEARCH_IGNORE, BTA_DM_SEARCH_IDLE} +#endif +}; +const UINT8 bta_dm_search_search_active_st_table[][BTA_DM_SEARCH_NUM_COLS] = +{ + +/* Event Action 1 Action 2 Next State */ +/* API_SEARCH */ {BTA_DM_SEARCH_IGNORE, BTA_DM_SEARCH_IGNORE, BTA_DM_SEARCH_ACTIVE}, +/* API_SEARCH_CANCEL */ {BTA_DM_API_SEARCH_CANCEL, BTA_DM_SEARCH_IGNORE, BTA_DM_SEARCH_CANCELLING}, +/* API_SEARCH_DISC */ {BTA_DM_SEARCH_IGNORE, BTA_DM_SEARCH_IGNORE, BTA_DM_SEARCH_ACTIVE}, +/* INQUIRY_CMPL */ {BTA_DM_INQUIRY_CMPL, BTA_DM_SEARCH_IGNORE, BTA_DM_SEARCH_ACTIVE}, +/* REMT_NAME_EVT */ {BTA_DM_REMT_NAME, BTA_DM_SEARCH_IGNORE, BTA_DM_SEARCH_ACTIVE}, +/* SDP_RESULT_EVT */ {BTA_DM_SDP_RESULT, BTA_DM_SEARCH_IGNORE, BTA_DM_SEARCH_ACTIVE}, +/* SEARCH_CMPL_EVT */ {BTA_DM_SEARCH_CMPL, BTA_DM_SEARCH_IGNORE, BTA_DM_SEARCH_IDLE}, +/* DISCV_RES_EVT */ {BTA_DM_SEARCH_RESULT, BTA_DM_SEARCH_IGNORE, BTA_DM_SEARCH_ACTIVE}, +/* API_DI_DISCOVER_EVT */ {BTA_DM_SEARCH_IGNORE, BTA_DM_SEARCH_IGNORE, BTA_DM_SEARCH_ACTIVE} +#if BLE_INCLUDED == TRUE +/* DISC_CLOSE_TOUT_EVT */ ,{BTA_DM_CLOSE_GATT_CONN, BTA_DM_SEARCH_IGNORE, BTA_DM_SEARCH_ACTIVE} +#endif + +}; + +const UINT8 bta_dm_search_search_cancelling_st_table[][BTA_DM_SEARCH_NUM_COLS] = +{ + +/* Event Action 1 Action 2 Next State */ +/* API_SEARCH */ {BTA_DM_QUEUE_SEARCH, BTA_DM_SEARCH_IGNORE, BTA_DM_SEARCH_CANCELLING}, +/* API_SEARCH_CANCEL */ {BTA_DM_SEARCH_CLEAR_QUEUE, BTA_DM_SEARCH_CANCEL_NOTIFY, BTA_DM_SEARCH_CANCELLING}, +/* API_SEARCH_DISC */ {BTA_DM_QUEUE_DISC, BTA_DM_SEARCH_IGNORE, BTA_DM_SEARCH_CANCELLING}, +/* INQUIRY_CMPL */ {BTA_DM_SEARCH_CANCEL_CMPL, BTA_DM_SEARCH_IGNORE, BTA_DM_SEARCH_IDLE}, +/* REMT_NAME_EVT */ {BTA_DM_SEARCH_CANCEL_TRANSAC_CMPL, BTA_DM_SEARCH_CANCEL_CMPL, BTA_DM_SEARCH_IDLE}, +/* SDP_RESULT_EVT */ {BTA_DM_SEARCH_CANCEL_TRANSAC_CMPL, BTA_DM_SEARCH_CANCEL_CMPL, BTA_DM_SEARCH_IDLE}, +/* SEARCH_CMPL_EVT */ {BTA_DM_SEARCH_CANCEL_TRANSAC_CMPL, BTA_DM_SEARCH_CANCEL_CMPL, BTA_DM_SEARCH_IDLE}, +/* DISCV_RES_EVT */ {BTA_DM_SEARCH_CANCEL_TRANSAC_CMPL, BTA_DM_SEARCH_CANCEL_CMPL, BTA_DM_SEARCH_IDLE}, +/* API_DI_DISCOVER_EVT */ {BTA_DM_SEARCH_IGNORE, BTA_DM_SEARCH_IGNORE, BTA_DM_SEARCH_CANCELLING} +#if BLE_INCLUDED == TRUE +/* DISC_CLOSE_TOUT_EVT */ ,{BTA_DM_SEARCH_IGNORE, BTA_DM_SEARCH_IGNORE, BTA_DM_SEARCH_CANCELLING} +#endif + +}; + +const UINT8 bta_dm_search_disc_active_st_table[][BTA_DM_SEARCH_NUM_COLS] = +{ + +/* Event Action 1 Action 2 Next State */ +/* API_SEARCH */ {BTA_DM_SEARCH_IGNORE, BTA_DM_SEARCH_IGNORE, BTA_DM_DISCOVER_ACTIVE}, +/* API_SEARCH_CANCEL */ {BTA_DM_SEARCH_CANCEL_NOTIFY, BTA_DM_SEARCH_IGNORE, BTA_DM_SEARCH_CANCELLING}, +/* API_SEARCH_DISC */ {BTA_DM_SEARCH_IGNORE, BTA_DM_SEARCH_IGNORE, BTA_DM_DISCOVER_ACTIVE}, +/* INQUIRY_CMPL */ {BTA_DM_SEARCH_IGNORE, BTA_DM_SEARCH_IGNORE, BTA_DM_DISCOVER_ACTIVE}, +/* REMT_NAME_EVT */ {BTA_DM_DISC_RMT_NAME, BTA_DM_SEARCH_IGNORE, BTA_DM_DISCOVER_ACTIVE}, +/* SDP_RESULT_EVT */ {BTA_DM_SDP_RESULT, BTA_DM_SEARCH_IGNORE, BTA_DM_DISCOVER_ACTIVE}, +/* SEARCH_CMPL_EVT */ {BTA_DM_SEARCH_CMPL, BTA_DM_SEARCH_IGNORE, BTA_DM_SEARCH_IDLE}, +/* DISCV_RES_EVT */ {BTA_DM_DISC_RESULT, BTA_DM_SEARCH_IGNORE, BTA_DM_DISCOVER_ACTIVE}, +/* API_DI_DISCOVER_EVT */ {BTA_DM_SEARCH_IGNORE, BTA_DM_SEARCH_IGNORE, BTA_DM_DISCOVER_ACTIVE} + +#if BLE_INCLUDED == TRUE +/* DISC_CLOSE_TOUT_EVT */ ,{BTA_DM_SEARCH_IGNORE, BTA_DM_SEARCH_IGNORE, BTA_DM_DISCOVER_ACTIVE} +#endif +}; + +typedef const UINT8 (*tBTA_DM_ST_TBL)[BTA_DM_SEARCH_NUM_COLS]; + +/* state table */ +const tBTA_DM_ST_TBL bta_dm_search_st_tbl[] = { + bta_dm_search_idle_st_table, + bta_dm_search_search_active_st_table, + bta_dm_search_search_cancelling_st_table, + bta_dm_search_disc_active_st_table +}; + + +/******************************************************************************* +** +** Function bta_dm_sm_disable +** +** Description unregister BTA DM +** +** +** Returns void +** +*******************************************************************************/ +void bta_dm_sm_disable( ) +{ + bta_sys_deregister( BTA_ID_DM ); +} + + +/******************************************************************************* +** +** Function bta_dm_sm_execute +** +** Description State machine event handling function for DM +** +** +** Returns void +** +*******************************************************************************/ +BOOLEAN bta_dm_sm_execute(BT_HDR *p_msg) +{ + UINT16 event = p_msg->event & 0x00ff; + + APPL_TRACE_EVENT("bta_dm_sm_execute event:0x%x", event); + + /* execute action functions */ + if(event < BTA_DM_NUM_ACTIONS) + { + (*bta_dm_action[event])( (tBTA_DM_MSG*) p_msg); + } + + return TRUE; +} + +/******************************************************************************* +** +** Function bta_dm_sm_search_disable +** +** Description unregister BTA SEARCH DM +** +** +** Returns void +** +*******************************************************************************/ +void bta_dm_search_sm_disable( ) +{ + bta_sys_deregister( BTA_ID_DM_SEARCH ); + +} + + +/******************************************************************************* +** +** Function bta_dm_search_sm_execute +** +** Description State machine event handling function for DM +** +** +** Returns void +** +*******************************************************************************/ +BOOLEAN bta_dm_search_sm_execute(BT_HDR *p_msg) +{ + tBTA_DM_ST_TBL state_table; + UINT8 action; + int i; + + APPL_TRACE_EVENT("bta_dm_search_sm_execute state:%d, event:0x%x", + bta_dm_search_cb.state, p_msg->event); + + /* look up the state table for the current state */ + state_table = bta_dm_search_st_tbl[bta_dm_search_cb.state]; + + bta_dm_search_cb.state = state_table[p_msg->event & 0x00ff][BTA_DM_SEARCH_NEXT_STATE]; + + + /* execute action functions */ + for (i = 0; i < BTA_DM_SEARCH_ACTIONS; i++) + { + if ((action = state_table[p_msg->event & 0x00ff][i]) != BTA_DM_SEARCH_IGNORE) + { + (*bta_dm_search_action[action])( (tBTA_DM_MSG*) p_msg); + } + else + { + break; + } + } + return TRUE; +} + diff --git a/components/bt/bluedroid/bta/dm/bta_dm_pm.c b/components/bt/bluedroid/bta/dm/bta_dm_pm.c new file mode 100755 index 0000000000..87061eb9b0 --- /dev/null +++ b/components/bt/bluedroid/bta/dm/bta_dm_pm.c @@ -0,0 +1,1242 @@ +/****************************************************************************** + * + * Copyright (C) 2003-2012 Broadcom Corporation + * + * 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 action functions for device manager state + * machine. + * + ******************************************************************************/ + +// #include +#include + +#include "gki.h" +#include "bta_sys.h" +#include "bta_api.h" +#include "bta_dm_int.h" +#include "btm_api.h" + + +static void bta_dm_pm_cback(tBTA_SYS_CONN_STATUS status, UINT8 id, UINT8 app_id, BD_ADDR peer_addr); +static void bta_dm_pm_set_mode(BD_ADDR peer_addr, tBTA_DM_PM_ACTION pm_mode, + tBTA_DM_PM_REQ pm_req); +static void bta_dm_pm_timer_cback(void *p_tle); +static void bta_dm_pm_btm_cback(BD_ADDR bd_addr, tBTM_PM_STATUS status, UINT16 value, UINT8 hci_status); +static BOOLEAN bta_dm_pm_park(BD_ADDR peer_addr); +static BOOLEAN bta_dm_pm_sniff(tBTA_DM_PEER_DEVICE *p_peer_dev, UINT8 index); +static BOOLEAN bta_dm_pm_is_sco_active (); +static void bta_dm_pm_hid_check(BOOLEAN bScoActive); +static void bta_dm_pm_set_sniff_policy(tBTA_DM_PEER_DEVICE *p_dev, BOOLEAN bDisable); +static void bta_dm_pm_stop_timer_by_index(tBTA_PM_TIMER *p_timer, + UINT8 timer_idx); + +#if (BTM_SSR_INCLUDED == TRUE) +#if (defined BTA_HH_INCLUDED && BTA_HH_INCLUDED == TRUE) +#include "../hh/bta_hh_int.h" +/* BTA_DM_PM_SSR1 will be dedicated for HH SSR setting entry, no other profile can use it */ +#define BTA_DM_PM_SSR_HH BTA_DM_PM_SSR1 +#endif +static void bta_dm_pm_ssr(BD_ADDR peer_addr); +#endif + +tBTA_DM_CONNECTED_SRVCS bta_dm_conn_srvcs; + + +/******************************************************************************* +** +** Function bta_dm_init_pm +** +** Description Initializes the BT low power manager +** +** +** Returns void +** +*******************************************************************************/ +void bta_dm_init_pm(void) +{ + memset(&bta_dm_conn_srvcs, 0x00, sizeof(bta_dm_conn_srvcs)); + + /* if there are no power manger entries, so not register */ + if(p_bta_dm_pm_cfg[0].app_id != 0) + { + bta_sys_pm_register((tBTA_SYS_CONN_CBACK*)bta_dm_pm_cback); + + BTM_PmRegister((BTM_PM_REG_SET | BTM_PM_REG_NOTIF), &bta_dm_cb.pm_id, + bta_dm_pm_btm_cback); + } + + /* Need to initialize all PM timer service IDs */ + for (int i = 0; i < BTA_DM_NUM_PM_TIMER; i++) + { + for (int j = 0; j < BTA_DM_PM_MODE_TIMER_MAX; j++) + bta_dm_cb.pm_timer[i].srvc_id[j] = BTA_ID_MAX; + } +} + + +/******************************************************************************* +** +** Function bta_dm_disable_pm +** +** Description Disable PM +** +** +** Returns void +** +*******************************************************************************/ +void bta_dm_disable_pm(void) +{ + BTM_PmRegister( BTM_PM_DEREG, &bta_dm_cb.pm_id, NULL); + + /* + * Deregister the PM callback from the system handling to prevent + * re-enabling the PM timers after this call if the callback is invoked. + */ + bta_sys_pm_register((tBTA_SYS_CONN_CBACK*)NULL); + + /* Need to stop all active timers. */ + for (int i = 0; i < BTA_DM_NUM_PM_TIMER; i++) + { + for (int j = 0; j < BTA_DM_PM_MODE_TIMER_MAX; j++) + { + bta_dm_pm_stop_timer_by_index(&bta_dm_cb.pm_timer[i], j); + bta_dm_cb.pm_timer[i].pm_action[j] = BTA_DM_PM_NO_ACTION; + } + } +} + +/******************************************************************************* +** +** Function bta_dm_get_av_count +** +** Description Get the number of connected AV +** +** +** Returns number of av connections +** +*******************************************************************************/ +UINT8 bta_dm_get_av_count(void) +{ + UINT8 count = 0; + for (int i = 0; i < bta_dm_conn_srvcs.count; i++) + { + if (bta_dm_conn_srvcs.conn_srvc[i].id == BTA_ID_AV) + ++count; + } + return count; +} + +/******************************************************************************* +** +** Function bta_dm_pm_stop_timer +** +** Description stop a PM timer +** +** +** Returns void +** +*******************************************************************************/ +static void bta_dm_pm_stop_timer(BD_ADDR peer_addr) +{ + APPL_TRACE_DEBUG("%s: ", __func__); + + for(int i=0; iin_use = TRUE; + p_timer->timer[timer_idx].p_cback = bta_dm_pm_timer_cback; + + if (p_timer->srvc_id[timer_idx] == BTA_ID_MAX) + p_timer->active++; + + if (p_timer->pm_action[timer_idx] < pm_action) + p_timer->pm_action[timer_idx] = pm_action; + + p_timer->srvc_id[timer_idx] = srvc_id; + + bta_sys_start_timer(&p_timer->timer[timer_idx], 0, timeout); +} + +/******************************************************************************* +** +** Function bta_dm_pm_stop_timer_by_index +** +** Description stop a PM timer +** +** +** Returns void +** +*******************************************************************************/ +static void bta_dm_pm_stop_timer_by_index(tBTA_PM_TIMER *p_timer, + UINT8 timer_idx) +{ + if ((p_timer == NULL) || (timer_idx >= BTA_DM_PM_MODE_TIMER_MAX)) + return; + + if (p_timer->srvc_id[timer_idx] == BTA_ID_MAX) + return; /* The timer was not scheduled */ + + assert(p_timer->in_use && (p_timer->active > 0)); + + bta_sys_stop_timer(&p_timer->timer[timer_idx]); + p_timer->srvc_id[timer_idx] = BTA_ID_MAX; + /* NOTE: pm_action[timer_idx] intentionally not reset */ + + p_timer->active--; + if (p_timer->active == 0) + p_timer->in_use = FALSE; +} + +UINT32 bta_dm_pm_get_remaining_ticks (TIMER_LIST_ENT *p_target_tle) +{ + return bta_sys_get_remaining_ticks(p_target_tle); +} + +/******************************************************************************* +** +** 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; + UINT8 *p = NULL; + tBTA_DM_PEER_DEVICE *p_dev; + +#if (BTM_SSR_INCLUDED == TRUE) + int index = BTA_DM_PM_SSR0; +#endif + + APPL_TRACE_DEBUG("bta_dm_pm_cback: st(%d), id(%d), app(%d)", status, id, app_id); + + p_dev = bta_dm_find_peer_device(peer_addr); + + /* 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 subsystem in p_bta_dm_pm_spec*/ + if(i> p_bta_dm_pm_cfg[0].app_id) + return; + + bta_dm_pm_stop_timer_by_srvc_id(peer_addr, id); + /*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; jpm_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 + ) + { + 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("%s: SCO inactive, reset SSR to zero", __func__); + BTM_SetSsrParams (peer_addr, 0,0,0 ); + } + else if (status == BTA_SYS_SCO_CLOSE) + { + APPL_TRACE_DEBUG("%s: SCO active, back to old SSR", __func__); + bta_dm_pm_ssr(peer_addr); + } + } + } +#endif + + bta_dm_pm_set_mode(peer_addr, BTA_DM_PM_NO_ACTION, BTA_DM_PM_NEW_REQ); + + /* perform the HID link workaround if needed + ** 1. If SCO up/down event is received OR + ** 2. If HID connection open is received and SCO is already active. + ** This will handle the case where HID connects when SCO already active + */ + if ( BTM_IsDeviceUp() && + ( ((status == BTA_SYS_SCO_OPEN) || (status == BTA_SYS_SCO_CLOSE)) || + ((status == BTA_SYS_CONN_OPEN) && (id == BTA_ID_HH) && bta_dm_pm_is_sco_active()) ) ) + { + BOOLEAN bScoActive; + if (status == BTA_SYS_CONN_OPEN) + bScoActive = TRUE; + else + bScoActive = (status == BTA_SYS_SCO_OPEN); + + bta_dm_pm_hid_check(bScoActive); + } + +} + + +/******************************************************************************* +** +** Function bta_dm_pm_set_mode +** +** Description Set the power mode for the device +** +** +** Returns void +** +*******************************************************************************/ + +static void bta_dm_pm_set_mode(BD_ADDR peer_addr, tBTA_DM_PM_ACTION pm_request, + tBTA_DM_PM_REQ pm_req ) +{ + + tBTA_DM_PM_ACTION pm_action = BTA_DM_PM_NO_ACTION; + UINT16 timeout = 0; + UINT8 i,j; + tBTA_DM_PM_ACTION failed_pm = 0; + tBTA_DM_PEER_DEVICE *p_peer_device = NULL; + tBTA_DM_PM_ACTION allowed_modes = 0; + tBTA_DM_PM_ACTION pref_modes = 0; + tBTA_DM_PM_CFG *p_pm_cfg; + tBTA_DM_PM_SPEC *p_pm_spec; + tBTA_DM_PM_ACTN *p_act0, *p_act1; + tBTA_DM_SRVCS *p_srvcs = NULL; + BOOLEAN timer_started = FALSE; + UINT8 timer_idx, available_timer = BTA_DM_PM_MODE_TIMER_MAX; + UINT32 remaining_ticks = 0; + + if(!bta_dm_cb.device_list.count) + return; + + /* see if any attempt to put device in low power mode failed */ + p_peer_device = bta_dm_find_peer_device(peer_addr); + /* if no peer device found return */ + if (p_peer_device == NULL) + return; + + failed_pm = p_peer_device->pm_mode_failed; + + for(i=0; ipeer_bdaddr, peer_addr)) + { + + /* p_bta_dm_pm_cfg[0].app_id is the number of entries */ + for(j=1; j<=p_bta_dm_pm_cfg[0].app_id; j++) + { + if((p_bta_dm_pm_cfg[j].id == p_srvcs->id) + && ((p_bta_dm_pm_cfg[j].app_id == BTA_ALL_APP_ID ) || + (p_bta_dm_pm_cfg[j].app_id == p_srvcs->app_id))) + break; + } + + p_pm_cfg = &p_bta_dm_pm_cfg[j]; + p_pm_spec = &p_bta_dm_pm_spec[p_pm_cfg->spec_idx]; + p_act0 = &p_pm_spec->actn_tbl[p_srvcs->state][0]; + p_act1 = &p_pm_spec->actn_tbl[p_srvcs->state][1]; + + APPL_TRACE_DEBUG("bta_dm_pm_set_mode: srvcsid: %d, state: %d, j: %d", p_srvcs->id, p_srvcs->state, j); + allowed_modes |= p_pm_spec->allow_mask; + + /* PM actions are in the order of strictness */ + + /* first check if the first preference is ok */ + if(!(failed_pm & p_act0->power_mode)) + { + pref_modes |= p_act0->power_mode; + + if(p_act0->power_mode >= pm_action) + { + pm_action = p_act0->power_mode; + + if (pm_req != BTA_DM_PM_NEW_REQ || p_srvcs->new_request) + { + p_srvcs->new_request = FALSE; + timeout = p_act0->timeout; + } + } + } + /* if first preference has already failed, try second preference */ + else if(!(failed_pm & p_act1->power_mode)) + { + pref_modes |= p_act1->power_mode; + + if(p_act1->power_mode > pm_action) + { + pm_action = p_act1->power_mode; + timeout = p_act1->timeout; + } + } + } + } + + if(pm_action & (BTA_DM_PM_PARK | BTA_DM_PM_SNIFF)) + { + /* some service don't like the mode */ + if(!(allowed_modes & pm_action)) + { + + /* select the other mode if its allowed and preferred, otherwise 0 which is BTA_DM_PM_NO_ACTION */ + pm_action = (allowed_modes & (BTA_DM_PM_PARK | BTA_DM_PM_SNIFF) & pref_modes); + + /* no timeout needed if no action is required */ + if(pm_action == BTA_DM_PM_NO_ACTION) + { + timeout = 0; + } + + } + } + /* if need to start a timer */ + if((pm_req != BTA_DM_PM_EXECUTE) && timeout) + { + for(i=0; iid, pm_action); + } + timer_started = TRUE; + } + break; + } + else if (!bta_dm_cb.pm_timer[i].in_use) + { + APPL_TRACE_DEBUG("%s dm_pm_timer:%d, %d", __func__, i, timeout); + if (available_timer == BTA_DM_PM_MODE_TIMER_MAX) + available_timer = i; + } + } + /* new power mode for a new active connection */ + if (!timer_started) + { + if( available_timer != BTA_DM_PM_MODE_TIMER_MAX) + { + bdcpy(bta_dm_cb.pm_timer[available_timer].peer_bdaddr, peer_addr); + if ((timer_idx = bta_pm_action_to_timer_idx(pm_action)) != BTA_DM_PM_MODE_TIMER_MAX) + { + bta_dm_pm_start_timer(&bta_dm_cb.pm_timer[available_timer], timer_idx, timeout, p_srvcs->id, pm_action); + timer_started = TRUE; + } + } + /* no more timers */ + else + { + APPL_TRACE_WARNING("bta_dm_act dm_pm_timer no more"); + } + } + return; + } + /* if pending power mode timer expires, and currecnt link is in a + lower power mode than current profile requirement, igonre it */ + if (pm_req == BTA_DM_PM_EXECUTE && pm_request < pm_action) + { + APPL_TRACE_ERROR("Ignore the power mode request: %d", pm_request) + return; + } + if(pm_action == BTA_DM_PM_PARK) + { + p_peer_device->pm_mode_attempted = BTA_DM_PM_PARK; + bta_dm_pm_park(peer_addr); + } + else if(pm_action & BTA_DM_PM_SNIFF) + { + /* dont initiate SNIFF, if link_policy has it disabled */ + if (p_peer_device->link_policy & HCI_ENABLE_SNIFF_MODE) + { + p_peer_device->pm_mode_attempted = BTA_DM_PM_SNIFF; + bta_dm_pm_sniff(p_peer_device, (UINT8)(pm_action & 0x0F) ); + } + else + { + APPL_TRACE_DEBUG("bta_dm_pm_set_mode: Link policy disallows SNIFF, ignore request"); + } + } + else if(pm_action == BTA_DM_PM_ACTIVE) + { + bta_dm_pm_active(peer_addr); + } +} +/******************************************************************************* +** +** Function bta_ag_pm_park +** +** Description Switch to park mode. +** +** +** Returns TRUE if park attempted, FALSE otherwise. +** +*******************************************************************************/ +static BOOLEAN bta_dm_pm_park(BD_ADDR peer_addr) +{ + + tBTM_PM_MODE mode = BTM_PM_STS_ACTIVE; + + /* if not in park mode, switch to park */ + BTM_ReadPowerMode(peer_addr, &mode); + + if(mode != BTM_PM_MD_PARK) + { + BTM_SetPowerMode (bta_dm_cb.pm_id, peer_addr, &p_bta_dm_pm_md[BTA_DM_PM_PARK_IDX]); + } + return TRUE; + +} + +/******************************************************************************* +** +** Function bta_ag_pm_sniff +** +** Description Switch to sniff mode. +** +** +** Returns TRUE if sniff attempted, FALSE otherwise. +** +*******************************************************************************/ +static BOOLEAN bta_dm_pm_sniff(tBTA_DM_PEER_DEVICE *p_peer_dev, UINT8 index) +{ + tBTM_PM_MODE mode = BTM_PM_STS_ACTIVE; + tBTM_PM_PWR_MD pwr_md; + tBTM_STATUS status; +#if (BTM_SSR_INCLUDED == TRUE) + UINT8 *p_rem_feat = NULL; +#endif + + BTM_ReadPowerMode(p_peer_dev->peer_bdaddr, &mode); + p_rem_feat = BTM_ReadRemoteFeatures (p_peer_dev->peer_bdaddr); +#if (BTM_SSR_INCLUDED == TRUE) + APPL_TRACE_DEBUG("bta_dm_pm_sniff cur:%d, idx:%d, info:x%x", mode, index, p_peer_dev->info); + if (mode != BTM_PM_MD_SNIFF || + (HCI_SNIFF_SUB_RATE_SUPPORTED(BTM_ReadLocalFeatures ()) && p_rem_feat && + HCI_SNIFF_SUB_RATE_SUPPORTED(p_rem_feat) && + !(p_peer_dev->info & BTA_DM_DI_USE_SSR))) +#else + APPL_TRACE_DEBUG("bta_dm_pm_sniff cur:%d, idx:%d", mode, index); + if(mode != BTM_PM_MD_SNIFF) +#endif + { +#if (BTM_SSR_INCLUDED == TRUE) + /* Dont initiate Sniff if controller has alreay accepted + * remote sniff params. This avoid sniff loop issue with + * some agrresive headsets who use sniff latencies more than + * DUT supported range of Sniff intervals.*/ + if ((mode == BTM_PM_MD_SNIFF) && (p_peer_dev->info & BTA_DM_DI_ACP_SNIFF)) + { + APPL_TRACE_DEBUG("%s: already in remote initiate sniff", __func__); + return TRUE; + } +#endif + /* if the current mode is not sniff, issue the sniff command. + * If sniff, but SSR is not used in this link, still issue the command */ + memcpy(&pwr_md, &p_bta_dm_pm_md[index], sizeof (tBTM_PM_PWR_MD)); + if (p_peer_dev->info & BTA_DM_DI_INT_SNIFF) + { + pwr_md.mode |= BTM_PM_MD_FORCE; + } + status = BTM_SetPowerMode (bta_dm_cb.pm_id, p_peer_dev->peer_bdaddr, &pwr_md); + if (status == BTM_CMD_STORED|| status == BTM_CMD_STARTED) + { + p_peer_dev->info &= ~(BTA_DM_DI_INT_SNIFF|BTA_DM_DI_ACP_SNIFF); + p_peer_dev->info |= BTA_DM_DI_SET_SNIFF; + } + else if (status == BTM_SUCCESS) + { + APPL_TRACE_DEBUG("bta_dm_pm_sniff BTM_SetPowerMode() returns BTM_SUCCESS"); + p_peer_dev->info &= ~(BTA_DM_DI_INT_SNIFF|BTA_DM_DI_ACP_SNIFF|BTA_DM_DI_SET_SNIFF); + } + else /* error */ + { + APPL_TRACE_ERROR("bta_dm_pm_sniff BTM_SetPowerMode() returns ERROR status=%d", status); + p_peer_dev->info &= ~(BTA_DM_DI_INT_SNIFF|BTA_DM_DI_ACP_SNIFF|BTA_DM_DI_SET_SNIFF); + } + } + return TRUE; + +} +/******************************************************************************* +** +** Function bta_dm_pm_ssr +** +** Description checks and sends SSR parameters +** +** Returns void +** +*******************************************************************************/ +#if (BTM_SSR_INCLUDED == TRUE) +static void bta_dm_pm_ssr(BD_ADDR peer_addr) +{ + tBTA_DM_SSR_SPEC *p_spec, *p_spec_cur; + UINT8 i,j; + int ssr = BTA_DM_PM_SSR0; + + /* go through the connected services */ + for(i=0; imax_lat, &p_spec_cur->min_rmt_to) == BTA_HH_ERR) + continue; + } +#endif + if (p_spec_cur->max_lat < p_spec->max_lat || + (ssr == BTA_DM_PM_SSR0 && p_bta_dm_pm_spec[p_bta_dm_pm_cfg[j].spec_idx].ssr != BTA_DM_PM_SSR0)) + { + ssr = p_bta_dm_pm_spec[p_bta_dm_pm_cfg[j].spec_idx].ssr; + } + + } + } + + p_spec = &p_bta_dm_ssr_spec[ssr]; + APPL_TRACE_WARNING("bta_dm_pm_ssr:%d, lat:%d", ssr, p_spec->max_lat); + if(p_spec->max_lat) + { + /* set the SSR parameters. */ + BTM_SetSsrParams (peer_addr, p_spec->max_lat, + p_spec->min_rmt_to, p_spec->min_loc_to); + } +} +#endif +/******************************************************************************* +** +** Function bta_dm_pm_active +** +** Description Brings connection to active mode +** +** +** Returns void +** +*******************************************************************************/ +void bta_dm_pm_active(BD_ADDR peer_addr) +{ + tBTM_PM_PWR_MD pm; + + memset( (void*)&pm, 0, sizeof(pm)); + + /* switch to active mode */ + pm.mode = BTM_PM_MD_ACTIVE; + BTM_SetPowerMode (bta_dm_cb.pm_id, peer_addr, &pm); + + +} + + +/******************************************************************************* +** +** Function bta_dm_pm_btm_cback +** +** Description BTM power manager callback. +** +** +** Returns void +** +*******************************************************************************/ +static void bta_dm_pm_btm_cback(BD_ADDR bd_addr, tBTM_PM_STATUS status, UINT16 value, UINT8 hci_status) +{ + tBTA_DM_PM_BTM_STATUS *p_buf; + + if ((p_buf = (tBTA_DM_PM_BTM_STATUS *) GKI_getbuf(sizeof(tBTA_DM_PM_BTM_STATUS))) != NULL) + { + p_buf->hdr.event = BTA_DM_PM_BTM_STATUS_EVT; + p_buf->status = status; + p_buf->value = value; + p_buf->hci_status = hci_status; + bdcpy(p_buf->bd_addr, bd_addr); + bta_sys_sendmsg(p_buf); + } +} + +/******************************************************************************* +** +** Function bta_dm_pm_timer_cback +** +** Description Power management timer callback. +** +** +** Returns void +** +*******************************************************************************/ +static void bta_dm_pm_timer_cback(void *p_tle) +{ + UINT8 i, j; + + for (i=0; ihdr.event = BTA_DM_PM_TIMER_EVT; + p_buf->pm_request = bta_dm_cb.pm_timer[i].pm_action[j]; + bdcpy(p_buf->bd_addr, bta_dm_cb.pm_timer[i].peer_bdaddr); + bta_sys_sendmsg(p_buf); + } +} + +/******************************************************************************* +** +** Function bta_dm_pm_btm_status +** +** Description Process pm status event from btm +** +** +** Returns void +** +*******************************************************************************/ +void bta_dm_pm_btm_status(tBTA_DM_MSG *p_data) +{ + APPL_TRACE_DEBUG("%s status: %d", __func__, p_data->pm_status.status); + + tBTA_DM_PEER_DEVICE *p_dev = bta_dm_find_peer_device(p_data->pm_status.bd_addr); + if (NULL == p_dev) + return; + + tBTA_DM_DEV_INFO info = p_dev->info; + /* check new mode */ + switch (p_data->pm_status.status) + { + case BTM_PM_STS_ACTIVE: + /* if our sniff or park attempt failed + we should not try it again*/ + if (p_data->pm_status.hci_status != 0) + { + APPL_TRACE_ERROR("%s hci_status=%d", __func__, p_data->pm_status.hci_status); + p_dev->info &= ~(BTA_DM_DI_INT_SNIFF|BTA_DM_DI_ACP_SNIFF|BTA_DM_DI_SET_SNIFF); + + if(p_dev->pm_mode_attempted &(BTA_DM_PM_PARK | BTA_DM_PM_SNIFF)) + { + p_dev->pm_mode_failed + |= ((BTA_DM_PM_PARK | BTA_DM_PM_SNIFF) & p_dev->pm_mode_attempted); + bta_dm_pm_stop_timer_by_mode(p_data->pm_status.bd_addr, p_dev->pm_mode_attempted); + bta_dm_pm_set_mode(p_data->pm_status.bd_addr, BTA_DM_PM_NO_ACTION, BTA_DM_PM_RESTART); + } + } + else + { +#if (BTM_SSR_INCLUDED == TRUE) + if(p_dev->prev_low) + { + /* need to send the SSR paramaters to controller again */ + bta_dm_pm_ssr(p_dev->peer_bdaddr); + } + p_dev->prev_low = BTM_PM_STS_ACTIVE; +#endif + /* link to active mode, need to restart the timer for next low power mode if needed */ + bta_dm_pm_stop_timer(p_data->pm_status.bd_addr); + bta_dm_pm_set_mode(p_data->pm_status.bd_addr, BTA_DM_PM_NO_ACTION, BTA_DM_PM_RESTART); + } + break; + +#if (BTM_SSR_INCLUDED == TRUE) + case BTM_PM_STS_PARK: + case BTM_PM_STS_HOLD: + /* save the previous low power mode - for SSR. + * SSR parameters are sent to controller on "conn open". + * the numbers stay good until park/hold/detach */ + if(p_dev->info & BTA_DM_DI_USE_SSR) + p_dev->prev_low = p_data->pm_status.status; + break; + + case BTM_PM_STS_SSR: + if(p_data->pm_status.value) + p_dev->info |= BTA_DM_DI_USE_SSR; + else + p_dev->info &= ~BTA_DM_DI_USE_SSR; + break; +#endif + case BTM_PM_STS_SNIFF: + if (p_data->pm_status.hci_status == 0) + { + /* Stop PM timer now if already active for + * particular device since link is already + * put in sniff mode by remote device, and + * PM timer sole purpose is to put the link + * in sniff mode from host side. + */ + bta_dm_pm_stop_timer(p_data->pm_status.bd_addr); + } + else + { + p_dev->info &= ~(BTA_DM_DI_SET_SNIFF | BTA_DM_DI_INT_SNIFF | BTA_DM_DI_ACP_SNIFF); + if (info & BTA_DM_DI_SET_SNIFF) + p_dev->info |= BTA_DM_DI_INT_SNIFF; + else + p_dev->info |= BTA_DM_DI_ACP_SNIFF; + } + break; + + case BTM_PM_STS_ERROR: + p_dev->info &= ~BTA_DM_DI_SET_SNIFF; + break; + + default: + break; + } + + + +} + +/******************************************************************************* +** +** Function bta_dm_pm_timer +** +** Description Process pm timer event from btm +** +** +** Returns void +** +*******************************************************************************/ +void bta_dm_pm_timer(tBTA_DM_MSG *p_data) +{ + APPL_TRACE_EVENT("%s", __func__); + bta_dm_pm_set_mode(p_data->pm_timer.bd_addr, p_data->pm_timer.pm_request, BTA_DM_PM_EXECUTE); +} + +/******************************************************************************* +** +** Function bta_dm_find_peer_device +** +** Description Given an address, find the associated control block. +** +** Returns tBTA_DM_PEER_DEVICE +** +*******************************************************************************/ +tBTA_DM_PEER_DEVICE * bta_dm_find_peer_device(BD_ADDR peer_addr) +{ + tBTA_DM_PEER_DEVICE *p_dev = NULL; + + for (int i=0; ipeer_bdaddr); + + /* update device record and set link policy */ + p_dev->link_policy = policy_setting; + BTM_SetLinkPolicy(p_dev->peer_bdaddr, &policy_setting); + +} + +#if ((defined BLE_INCLUDED) && (BLE_INCLUDED == TRUE)) +/******************************************************************************* +** +** Function bta_dm_pm_obtain_controller_state +** +** Description This function obtains the consolidated controller power state +** +** Parameters: +** +*******************************************************************************/ +tBTA_DM_CONTRL_STATE bta_dm_pm_obtain_controller_state(void) +{ + /* Did not use counts as it is not sure, how accurate the count values are in + ** bta_dm_cb.device_list.count > 0 || bta_dm_cb.device_list.le_count > 0 */ + + tBTA_DM_CONTRL_STATE cur_state = BTA_DM_CONTRL_UNKNOWN; + cur_state = BTM_PM_ReadControllerState(); + + APPL_TRACE_DEBUG("bta_dm_pm_obtain_controller_state: %d", cur_state); + return cur_state; +} +#endif diff --git a/components/bt/bluedroid/bta/dm/bta_dm_sco.c b/components/bt/bluedroid/bta/dm/bta_dm_sco.c new file mode 100755 index 0000000000..109140a4d2 --- /dev/null +++ b/components/bt/bluedroid/bta/dm/bta_dm_sco.c @@ -0,0 +1,695 @@ +/****************************************************************************** + * + * Copyright (C) 2003-2012 Broadcom Corporation + * + * 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 down sampling utility to convert PCM samples in + * 16k/32k/48k/44.1k/22050/11025 sampling rate into 8K/16bits samples + * required for SCO channel format. One API function isprovided and only + * possible to be used when transmitting SCO data is sent via HCI + * interface. + * + ******************************************************************************/ +#include +#include "bta_api.h" +#include "bta_sys.h" + +#if (BTM_SCO_HCI_INCLUDED == TRUE) + +#ifndef BTA_DM_SCO_DEBUG +#define BTA_DM_SCO_DEBUG FALSE +#endif +/***************************************************************************** +** Constants +*****************************************************************************/ + +#define BTA_DM_PCM_OVERLAP_SIZE 48 + +#define BTA_DM_PCM_SMPL_RATE_44100 44100 +#define BTA_DM_PCM_SMPL_RATE_22050 22050 +#define BTA_DM_PCM_SMPL_RATE_11025 11025 + +/***************************************************************************** +** Data types for PCM Resampling utility +*****************************************************************************/ + +typedef INT32 (*PCONVERT_TO_BT_FILTERED) (UINT8 *pSrc, void *pDst, UINT32 dwSrcSamples, + UINT32 dwSrcSps,INT32 *pLastCurPos, UINT8 *pOverlapArea); +typedef INT32 (*PCONVERT_TO_BT_NOFILTER) (void *pSrc, void *pDst, UINT32 dwSrcSamples, + UINT32 dwSrcSps); +typedef struct +{ + UINT8 overlap_area[BTA_DM_PCM_OVERLAP_SIZE * 4]; + UINT32 cur_pos; /* current position */ + UINT32 src_sps; /* samples per second (source audio data) */ + PCONVERT_TO_BT_FILTERED filter; /* the action function to do the + conversion 44100, 22050, 11025*/ + PCONVERT_TO_BT_NOFILTER nofilter; /* the action function to do + the conversion 48000, 32000, 16000*/ + UINT32 bits; /* number of bits per pcm sample */ + UINT32 n_channels; /* number of channels (i.e. mono(1), stereo(2)...) */ + UINT32 sample_size; + UINT32 can_be_filtered; + UINT32 divisor; +} tBTA_DM_PCM_RESAMPLE_CB; + +tBTA_DM_PCM_RESAMPLE_CB bta_dm_pcm_cb; + +/***************************************************************************** +** Macro Definition +*****************************************************************************/ + + +#define CHECK_SATURATION16(x) \ + if (x > 32767) \ + x = 32767; \ + else if (x < -32768) \ + x = -32768; + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// +#define CONVERT_44100_TO_BLUETOOTH(pStart, pEnd) \ + { \ + INT32 out1, out2, out3, out4, out5; \ + SRC_TYPE *pS = (SRC_TYPE *)pStart; \ + SRC_TYPE *pSEnd = (SRC_TYPE *)pEnd; \ + \ + while (pS < pSEnd) \ + { \ + CurrentPos -= 8000; \ + \ + if (CurrentPos >= 0) \ + { \ + pS += SRC_CHANNELS; \ + continue; \ + } \ + CurrentPos += dwSrcSps; \ + \ + out1 = (SRC_SAMPLE(0) * 1587) \ + + ((SRC_SAMPLE(1) + SRC_SAMPLE(-1)) * 1522) \ + + ((SRC_SAMPLE(2) + SRC_SAMPLE(-2)) * 1337) \ + + ((SRC_SAMPLE(3) + SRC_SAMPLE(-3)) * 1058); \ + \ + out1 = out1 / 30000; \ + \ + out2 = ((SRC_SAMPLE(4) + SRC_SAMPLE(-4)) * 725) \ + + ((SRC_SAMPLE(5) + SRC_SAMPLE(-5)) * 384) \ + + ((SRC_SAMPLE(6) + SRC_SAMPLE(-6)) * 79); \ + \ + out2 = out2 / 30000; \ + \ + out3 = ((SRC_SAMPLE(7) + SRC_SAMPLE(-7)) * 156) \ + + ((SRC_SAMPLE(8) + SRC_SAMPLE(-8)) * 298) \ + + ((SRC_SAMPLE(9) + SRC_SAMPLE(-9)) * 345); \ + \ + out3 = out3 / 30000; \ + \ + out4 = ((SRC_SAMPLE(10) + SRC_SAMPLE(-10)) * 306) \ + + ((SRC_SAMPLE(11) + SRC_SAMPLE(-11)) * 207) \ + + ((SRC_SAMPLE(12) + SRC_SAMPLE(-12)) * 78); \ + \ + out4 = out4 / 30000; \ + \ + out5 = out1 + out2 - out3 - out4; \ + \ + CHECK_SATURATION16(out5); \ + *psBtOut++ = (INT16)out5; \ + \ + pS += SRC_CHANNELS; \ + } \ + } + + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// +#define CONVERT_22050_TO_BLUETOOTH(pStart, pEnd) \ + { \ + INT32 out1, out2, out3, out4, out5; \ + SRC_TYPE *pS = (SRC_TYPE *)pStart; \ + SRC_TYPE *pSEnd = (SRC_TYPE *)pEnd; \ + \ + while (pS < pSEnd) \ + { \ + CurrentPos -= 8000; \ + \ + if (CurrentPos >= 0) \ + { \ + pS += SRC_CHANNELS; \ + continue; \ + } \ + CurrentPos += dwSrcSps; \ + \ + out1 = (SRC_SAMPLE(0) * 2993) \ + + ((SRC_SAMPLE(1) + SRC_SAMPLE(-1)) * 2568) \ + + ((SRC_SAMPLE(2) + SRC_SAMPLE(-2)) * 1509) \ + + ((SRC_SAMPLE(3) + SRC_SAMPLE(-3)) * 331); \ + \ + out1 = out1 / 30000; \ + \ + out2 = ((SRC_SAMPLE(4) + SRC_SAMPLE(-4)) * 454) \ + + ((SRC_SAMPLE(5) + SRC_SAMPLE(-5)) * 620) \ + + ((SRC_SAMPLE(6) + SRC_SAMPLE(-6)) * 305); \ + \ + out2 = out2 / 30000; \ + \ + out3 = ((SRC_SAMPLE(7) + SRC_SAMPLE(-7)) * 127) \ + + ((SRC_SAMPLE(8) + SRC_SAMPLE(-8)) * 350) \ + + ((SRC_SAMPLE(9) + SRC_SAMPLE(-9)) * 265) \ + + ((SRC_SAMPLE(10) + SRC_SAMPLE(-10)) * 6); \ + \ + out3 = out3 / 30000; \ + \ + out4 = ((SRC_SAMPLE(11) + SRC_SAMPLE(-11)) * 201); \ + \ + out4 = out4 / 30000; \ + \ + out5 = out1 - out2 + out3 - out4; \ + \ + CHECK_SATURATION16(out5); \ + *psBtOut++ = (INT16)out5; \ + \ + pS += SRC_CHANNELS; \ + } \ + } + + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// +#define CONVERT_11025_TO_BLUETOOTH(pStart, pEnd) \ + { \ + INT32 out1; \ + SRC_TYPE *pS = (SRC_TYPE *)pStart; \ + SRC_TYPE *pSEnd = (SRC_TYPE *)pEnd; \ + \ + while (pS < pSEnd) \ + { \ + CurrentPos -= 8000; \ + \ + if (CurrentPos >= 0) \ + { \ + pS += SRC_CHANNELS; \ + continue; \ + } \ + CurrentPos += dwSrcSps; \ + \ + out1 = (SRC_SAMPLE(0) * 6349) \ + + ((SRC_SAMPLE(1) + SRC_SAMPLE(-1)) * 2874) \ + - ((SRC_SAMPLE(2) + SRC_SAMPLE(-2)) * 1148) \ + - ((SRC_SAMPLE(3) + SRC_SAMPLE(-3)) * 287) \ + + ((SRC_SAMPLE(4) + SRC_SAMPLE(-4)) * 675) \ + - ((SRC_SAMPLE(5) + SRC_SAMPLE(-5)) * 258) \ + - ((SRC_SAMPLE(6) + SRC_SAMPLE(-6)) * 206) \ + + ((SRC_SAMPLE(7) + SRC_SAMPLE(-7)) * 266); \ + \ + out1 = out1 / 30000; \ + \ + CHECK_SATURATION16(out1); \ + *psBtOut++ = (INT16)out1; \ + \ + pS += SRC_CHANNELS; \ + } \ + } + + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// +#undef SRC_CHANNELS +#undef SRC_SAMPLE +#undef SRC_TYPE + +#define SRC_TYPE UINT8 +#define SRC_CHANNELS 1 +#define SRC_SAMPLE(x) ((pS[x] - 0x80) << 8) + +/***************************************************************************** +** Local Function +*****************************************************************************/ +INT32 Convert_8M_ToBT_Filtered (UINT8 *pSrc, void *pDst, UINT32 dwSrcSamples, + UINT32 dwSrcSps, INT32 *pLastCurPos, UINT8 *pOverlapArea) +{ + INT32 CurrentPos = *pLastCurPos; + SRC_TYPE *pIn, *pInEnd; + SRC_TYPE *pOv, *pOvEnd; + INT16 *psBtOut = (INT16 *)pDst; +#if BTA_DM_SCO_DEBUG + APPL_TRACE_DEBUG("Convert_8M_ToBT_Filtered, CurrentPos %d\n", CurrentPos); +#endif + memcpy (pOverlapArea + (BTA_DM_PCM_OVERLAP_SIZE * 2), pSrc, BTA_DM_PCM_OVERLAP_SIZE * 2); + + pOv = (SRC_TYPE *)(pOverlapArea + BTA_DM_PCM_OVERLAP_SIZE); + pOvEnd = (SRC_TYPE *)(pOverlapArea + (BTA_DM_PCM_OVERLAP_SIZE * 3)); + + pIn = (SRC_TYPE *)(pSrc + BTA_DM_PCM_OVERLAP_SIZE); + pInEnd = (SRC_TYPE *)(pSrc + (dwSrcSamples * SRC_CHANNELS * sizeof (SRC_TYPE)) - \ + BTA_DM_PCM_OVERLAP_SIZE); + + if (dwSrcSps == BTA_DM_PCM_SMPL_RATE_44100) + { + CONVERT_44100_TO_BLUETOOTH(pOv, pOvEnd); + CONVERT_44100_TO_BLUETOOTH(pIn, pInEnd); + } + else if (dwSrcSps == BTA_DM_PCM_SMPL_RATE_22050) + { + CONVERT_22050_TO_BLUETOOTH(pOv, pOvEnd); + CONVERT_22050_TO_BLUETOOTH(pIn, pInEnd); + } + else if (dwSrcSps == BTA_DM_PCM_SMPL_RATE_11025) + { + CONVERT_11025_TO_BLUETOOTH(pOv, pOvEnd); + CONVERT_11025_TO_BLUETOOTH(pIn, pInEnd); + } + + memcpy (pOverlapArea, pSrc + (dwSrcSamples * SRC_CHANNELS * sizeof (SRC_TYPE)) - \ + (BTA_DM_PCM_OVERLAP_SIZE * 2), BTA_DM_PCM_OVERLAP_SIZE * 2); + + *pLastCurPos = CurrentPos; + + return (psBtOut - (INT16 *)pDst); +} + +INT32 Convert_8M_ToBT_NoFilter (void *pSrc, void *pDst, UINT32 dwSrcSamples, UINT32 dwSrcSps) +{ + INT32 CurrentPos; + UINT8 *pbSrc = (UINT8 *)pSrc; + INT16 *psDst = (INT16 *)pDst; + INT16 sWorker; + + // start at dwSpsSrc / 2, decrement by 8000 + // + CurrentPos = (dwSrcSps >> 1); + + while (dwSrcSamples--) + { + CurrentPos -= 8000; + + if (CurrentPos >= 0) + pbSrc++; + else + { + sWorker = *pbSrc++; + sWorker -= 0x80; + sWorker <<= 8; + + *psDst++ = sWorker; + + CurrentPos += dwSrcSps; + } + } + + return (psDst - (INT16 *)pDst); +} + + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// +#undef SRC_CHANNELS +#undef SRC_SAMPLE +#undef SRC_TYPE + +#define SRC_TYPE INT16 +#define SRC_CHANNELS 1 +#define SRC_SAMPLE(x) pS[x] + +INT32 Convert_16M_ToBT_Filtered (UINT8 *pSrc, void *pDst, UINT32 dwSrcSamples, + UINT32 dwSrcSps, INT32 *pLastCurPos, UINT8 *pOverlapArea) +{ + INT32 CurrentPos = *pLastCurPos; + SRC_TYPE *pIn, *pInEnd; + SRC_TYPE *pOv, *pOvEnd; + INT16 *psBtOut = (INT16 *)pDst; + + memcpy (pOverlapArea + (BTA_DM_PCM_OVERLAP_SIZE * 2), pSrc, BTA_DM_PCM_OVERLAP_SIZE * 2); + + pOv = (SRC_TYPE *)(pOverlapArea + BTA_DM_PCM_OVERLAP_SIZE); + pOvEnd = (SRC_TYPE *)(pOverlapArea + (BTA_DM_PCM_OVERLAP_SIZE * 3)); + + pIn = (SRC_TYPE *)(pSrc + BTA_DM_PCM_OVERLAP_SIZE); + pInEnd = (SRC_TYPE *)(pSrc + (dwSrcSamples * SRC_CHANNELS * sizeof (SRC_TYPE)) - BTA_DM_PCM_OVERLAP_SIZE); + + if (dwSrcSps == BTA_DM_PCM_SMPL_RATE_44100) + { + CONVERT_44100_TO_BLUETOOTH(pOv, pOvEnd); + CONVERT_44100_TO_BLUETOOTH(pIn, pInEnd); + } + else if (dwSrcSps == BTA_DM_PCM_SMPL_RATE_22050) + { + CONVERT_22050_TO_BLUETOOTH(pOv, pOvEnd); + CONVERT_22050_TO_BLUETOOTH(pIn, pInEnd); + } + else if (dwSrcSps == BTA_DM_PCM_SMPL_RATE_11025) + { + CONVERT_11025_TO_BLUETOOTH(pOv, pOvEnd); + CONVERT_11025_TO_BLUETOOTH(pIn, pInEnd); + } + + memcpy (pOverlapArea, pSrc + (dwSrcSamples * SRC_CHANNELS * sizeof (SRC_TYPE)) - \ + (BTA_DM_PCM_OVERLAP_SIZE * 2), BTA_DM_PCM_OVERLAP_SIZE * 2); + + *pLastCurPos = CurrentPos; + + return (psBtOut - (INT16 *)pDst); +} + +INT32 Convert_16M_ToBT_NoFilter (void *pSrc, void *pDst, UINT32 dwSrcSamples, UINT32 dwSrcSps) +{ + INT32 CurrentPos; + INT16 *psSrc = (INT16 *)pSrc; + INT16 *psDst = (INT16 *)pDst; + + // start at dwSpsSrc / 2, decrement by 8000 + // + CurrentPos = (dwSrcSps >> 1); + + while (dwSrcSamples--) + { + CurrentPos -= 8000; + + if (CurrentPos >= 0) + psSrc++; + else + { + *psDst++ = *psSrc++; + + CurrentPos += dwSrcSps; + } + } + + return (psDst - (INT16 *)pDst); +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// +#undef SRC_CHANNELS +#undef SRC_SAMPLE +#undef SRC_TYPE + +#define SRC_TYPE UINT8 +#define SRC_CHANNELS 2 +#define SRC_SAMPLE(x) ((((pS[x * 2] - 0x80) << 8) + ((pS[(x * 2) + 1] - 0x80) << 8)) >> 1) + +INT32 Convert_8S_ToBT_Filtered (UINT8 *pSrc, void *pDst, UINT32 dwSrcSamples, + UINT32 dwSrcSps, INT32 *pLastCurPos, UINT8 *pOverlapArea) +{ + INT32 CurrentPos = *pLastCurPos; + SRC_TYPE *pIn, *pInEnd; + SRC_TYPE *pOv, *pOvEnd; + INT16 *psBtOut = (INT16 *)pDst; + +#if BTA_DM_SCO_DEBUG + APPL_TRACE_DEBUG("Convert_8S_ToBT_Filtered CurrentPos %d, SRC_TYPE %d, SRC_CHANNELS %d, \ + dwSrcSamples %d, dwSrcSps %d", CurrentPos, sizeof (SRC_TYPE), SRC_CHANNELS, \ + dwSrcSamples, dwSrcSps); +#endif + memcpy (pOverlapArea + (BTA_DM_PCM_OVERLAP_SIZE * 2), pSrc, BTA_DM_PCM_OVERLAP_SIZE * 2); + + pOv = (SRC_TYPE *)(pOverlapArea + BTA_DM_PCM_OVERLAP_SIZE); + pOvEnd = (SRC_TYPE *)(pOverlapArea + (BTA_DM_PCM_OVERLAP_SIZE * 3)); + + pIn = (SRC_TYPE *)(pSrc + BTA_DM_PCM_OVERLAP_SIZE); + pInEnd = (SRC_TYPE *)(pSrc + (dwSrcSamples * SRC_CHANNELS * sizeof (SRC_TYPE)) - BTA_DM_PCM_OVERLAP_SIZE); + + if (dwSrcSps == BTA_DM_PCM_SMPL_RATE_44100) + { + CONVERT_44100_TO_BLUETOOTH(pOv, pOvEnd); + CONVERT_44100_TO_BLUETOOTH(pIn, pInEnd); + } + else if (dwSrcSps == BTA_DM_PCM_SMPL_RATE_22050) + { + CONVERT_22050_TO_BLUETOOTH(pOv, pOvEnd); + CONVERT_22050_TO_BLUETOOTH(pIn, pInEnd); + } + else if (dwSrcSps == BTA_DM_PCM_SMPL_RATE_11025) + { + CONVERT_11025_TO_BLUETOOTH(pOv, pOvEnd); + CONVERT_11025_TO_BLUETOOTH(pIn, pInEnd); + } + + memcpy (pOverlapArea, pSrc + (dwSrcSamples * SRC_CHANNELS * sizeof (SRC_TYPE)) - \ + (BTA_DM_PCM_OVERLAP_SIZE * 2), BTA_DM_PCM_OVERLAP_SIZE * 2); + + *pLastCurPos = CurrentPos; + + return (psBtOut - (INT16 *)pDst); +} + +INT32 Convert_8S_ToBT_NoFilter (void *pSrc, void *pDst, UINT32 dwSrcSamples, UINT32 dwSrcSps) +{ + INT32 CurrentPos; + UINT8 *pbSrc = (UINT8 *)pSrc; + INT16 *psDst = (INT16 *)pDst; + INT16 sWorker, sWorker2; + + // start at dwSpsSrc / 2, decrement by 8000 + // + CurrentPos = (dwSrcSps >> 1); + + while (dwSrcSamples--) + { + CurrentPos -= 8000; + + if (CurrentPos >= 0) + pbSrc += 2; + else + { + sWorker = *(unsigned char *)pbSrc; + sWorker -= 0x80; + sWorker <<= 8; + pbSrc++; + + sWorker2 = *(unsigned char *)pbSrc; + sWorker2 -= 0x80; + sWorker2 <<= 8; + pbSrc++; + + sWorker += sWorker2; + sWorker >>= 1; + + *psDst++ = sWorker; + + CurrentPos += dwSrcSps; + } + } + + return (psDst - (INT16 *)pDst); +} + + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// +#undef SRC_CHANNELS +#undef SRC_SAMPLE +#undef SRC_TYPE + +#define SRC_TYPE INT16 +#define SRC_CHANNELS 2 +#define SRC_SAMPLE(x) ((pS[x * 2] + pS[(x * 2) + 1]) >> 1) + +INT32 Convert_16S_ToBT_Filtered (UINT8 *pSrc, void *pDst, UINT32 dwSrcSamples, + UINT32 dwSrcSps, INT32 *pLastCurPos, UINT8 *pOverlapArea) +{ + INT32 CurrentPos = *pLastCurPos; + SRC_TYPE *pIn, *pInEnd; + SRC_TYPE *pOv, *pOvEnd; + INT16 *psBtOut = (INT16 *)pDst; + + memcpy (pOverlapArea + (BTA_DM_PCM_OVERLAP_SIZE * 2), pSrc, BTA_DM_PCM_OVERLAP_SIZE * 2); + + pOv = (SRC_TYPE *)(pOverlapArea + BTA_DM_PCM_OVERLAP_SIZE); + pOvEnd = (SRC_TYPE *)(pOverlapArea + (BTA_DM_PCM_OVERLAP_SIZE * 3)); + + pIn = (SRC_TYPE *)(pSrc + BTA_DM_PCM_OVERLAP_SIZE); + pInEnd = (SRC_TYPE *)(pSrc + (dwSrcSamples * SRC_CHANNELS * sizeof (SRC_TYPE)) - BTA_DM_PCM_OVERLAP_SIZE); + + if (dwSrcSps == BTA_DM_PCM_SMPL_RATE_44100) + { + CONVERT_44100_TO_BLUETOOTH(pOv, pOvEnd); + CONVERT_44100_TO_BLUETOOTH(pIn, pInEnd); + } + else if (dwSrcSps == BTA_DM_PCM_SMPL_RATE_22050) + { + CONVERT_22050_TO_BLUETOOTH(pOv, pOvEnd); + CONVERT_22050_TO_BLUETOOTH(pIn, pInEnd); + } + else if (dwSrcSps == BTA_DM_PCM_SMPL_RATE_11025) + { + CONVERT_11025_TO_BLUETOOTH(pOv, pOvEnd); + CONVERT_11025_TO_BLUETOOTH(pIn, pInEnd); + } + + memcpy (pOverlapArea, pSrc + (dwSrcSamples * SRC_CHANNELS * sizeof (SRC_TYPE)) - \ + (BTA_DM_PCM_OVERLAP_SIZE * 2), BTA_DM_PCM_OVERLAP_SIZE * 2); + + *pLastCurPos = CurrentPos; + + return (psBtOut - (INT16 *)pDst); +} + +INT32 Convert_16S_ToBT_NoFilter (void *pSrc, void *pDst, UINT32 dwSrcSamples, UINT32 dwSrcSps) +{ + INT32 CurrentPos; + INT16 *psSrc = (INT16 *)pSrc; + INT16 *psDst = (INT16 *)pDst; + INT16 sWorker; + + // start at dwSpsSrc / 2, decrement by 8000 + // + CurrentPos = (dwSrcSps >> 1); + + while (dwSrcSamples--) + { + CurrentPos -= 8000; + + if (CurrentPos >= 0) + psSrc += 2; + else + { + /* CR 82894, to avoid overflow, divide before add */ + sWorker = ((*psSrc) >> 1 ); + psSrc++; + sWorker += ((*psSrc) >> 1 ); + psSrc++; + + *psDst++ = sWorker; + + CurrentPos += dwSrcSps; + } + } + + return (psDst - (INT16 *)pDst); +} + +/******************************************************************************* +** +** Function BTA_DmPcmInitSamples +** +** Description initialize the down sample converter. +** +** src_sps: original samples per second (source audio data) +** (ex. 44100, 48000) +** bits: number of bits per pcm sample (16) +** n_channels: number of channels (i.e. mono(1), stereo(2)...) +** +** Returns none +** +*******************************************************************************/ +void BTA_DmPcmInitSamples (UINT32 src_sps, UINT32 bits, UINT32 n_channels) +{ + tBTA_DM_PCM_RESAMPLE_CB *p_cb = &bta_dm_pcm_cb; + + p_cb->cur_pos = src_sps / 2; + p_cb->src_sps = src_sps; + p_cb->bits = bits; + p_cb->n_channels = n_channels; + p_cb->sample_size = 2; + p_cb->divisor = 2; + + memset(p_cb->overlap_area, 0, sizeof(p_cb->overlap_area) ); + + if ((src_sps == BTA_DM_PCM_SMPL_RATE_44100) || + (src_sps == BTA_DM_PCM_SMPL_RATE_22050) || + (src_sps == BTA_DM_PCM_SMPL_RATE_11025)) + p_cb->can_be_filtered = 1; + else + p_cb->can_be_filtered = 0; + +#if BTA_DM_SCO_DEBUG + APPL_TRACE_DEBUG("bta_dm_pcm_init_samples: n_channels = %d bits = %d", n_channels, bits); +#endif + if(n_channels == 1) + { + /* mono */ + if(bits == 8) + { + p_cb->filter = (PCONVERT_TO_BT_FILTERED) Convert_8M_ToBT_Filtered; + p_cb->nofilter = (PCONVERT_TO_BT_NOFILTER) Convert_8M_ToBT_NoFilter; + p_cb->divisor = 1; + } + else + { + p_cb->filter = (PCONVERT_TO_BT_FILTERED) Convert_16M_ToBT_Filtered; + p_cb->nofilter = (PCONVERT_TO_BT_NOFILTER) Convert_16M_ToBT_NoFilter; + } + } + else + { + /* stereo */ + if(bits == 8) + { + p_cb->filter = (PCONVERT_TO_BT_FILTERED) Convert_8S_ToBT_Filtered; + p_cb->nofilter = (PCONVERT_TO_BT_NOFILTER) Convert_8S_ToBT_NoFilter; + } + else + { + p_cb->filter = (PCONVERT_TO_BT_FILTERED) Convert_16S_ToBT_Filtered; + p_cb->nofilter = (PCONVERT_TO_BT_NOFILTER) Convert_16S_ToBT_NoFilter; + p_cb->divisor = 4; + } + } + +#if BTA_DM_SCO_DEBUG + APPL_TRACE_DEBUG("bta_pcm_init_dwn_sample: cur_pos %d, src_sps %d", \ + p_cb->cur_pos, p_cb->src_sps); + APPL_TRACE_DEBUG("bta_pcm_init_dwn_sample: bits %d, n_channels %d, sample_size %d, ", \ + p_cb->bits, p_cb->n_channels, p_cb->sample_size); + APPL_TRACE_DEBUG("bta_pcm_init_dwn_sample: can_be_filtered %d, n_channels: %d, \ + divisor %d", p_cb->can_be_filtered, p_cb->n_channels, p_cb->divisor); +#endif + +} + +/************************************************************************************** +** Function BTA_DmPcmResample +** +** Description Down sampling utility to convert higher sampling rate into 8K/16bits +** PCM samples. +** +** Parameters p_src: pointer to the buffer where the original sampling PCM +** are stored. +** in_bytes: Length of the input PCM sample buffer in byte. +** p_dst: pointer to the buffer which is to be used to store +** the converted PCM samples. +** +** +** Returns INT32: number of samples converted. +** +**************************************************************************************/ +INT32 BTA_DmPcmResample (void *p_src, UINT32 in_bytes, void *p_dst) +{ + UINT32 out_sample; + +#if BTA_DM_SCO_DEBUG + APPL_TRACE_DEBUG("bta_pcm_resample : insamples %d", (in_bytes / bta_dm_pcm_cb.divisor)); +#endif + if(bta_dm_pcm_cb.can_be_filtered) + { + out_sample = (*bta_dm_pcm_cb.filter) (p_src, p_dst, (in_bytes / bta_dm_pcm_cb.divisor), + bta_dm_pcm_cb.src_sps, (INT32 *) &bta_dm_pcm_cb.cur_pos, bta_dm_pcm_cb.overlap_area); + } + else + { + out_sample = (*bta_dm_pcm_cb.nofilter) (p_src, p_dst, + (in_bytes / bta_dm_pcm_cb.divisor), bta_dm_pcm_cb.src_sps); + } + +#if BTA_DM_SCO_DEBUG + APPL_TRACE_DEBUG("bta_pcm_resample : outsamples %d", out_sample); +#endif + + return (out_sample * bta_dm_pcm_cb.sample_size); +} +#endif diff --git a/components/bt/bluedroid/bta/gatt/bta_gattc_act.c b/components/bt/bluedroid/bta/gatt/bta_gattc_act.c new file mode 100755 index 0000000000..116641ebb8 --- /dev/null +++ b/components/bt/bluedroid/bta/gatt/bta_gattc_act.c @@ -0,0 +1,2379 @@ +/****************************************************************************** + * + * Copyright (C) 2003-2012 Broadcom Corporation + * + * 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 GATT client action functions for the state + * machine. + * + ******************************************************************************/ +#define LOG_TAG "bt_bta_gattc" + +#include "bt_target.h" + +#include "utl.h" +#include "gki.h" +#include "bta_sys.h" + +#include "bta_gattc_int.h" +#include "l2c_api.h" + +#if (defined BTA_HH_LE_INCLUDED && BTA_HH_LE_INCLUDED == TRUE) +#include "bta_hh_int.h" +#endif + +// #include "btif/include/btif_debug_conn.h" + +#include + +// #include "osi/include/log.h" + +#if BTA_GATT_INCLUDED && BLE_INCLUDED == TRUE + +/***************************************************************************** +** Constants +*****************************************************************************/ +static void bta_gattc_conn_cback(tGATT_IF gattc_if, BD_ADDR bda, UINT16 conn_id, + BOOLEAN connected, tGATT_DISCONN_REASON reason, + tBT_TRANSPORT transport); + +static void bta_gattc_cmpl_cback(UINT16 conn_id, tGATTC_OPTYPE op, tGATT_STATUS status, + tGATT_CL_COMPLETE *p_data); +static void bta_gattc_cmpl_sendmsg(UINT16 conn_id, tGATTC_OPTYPE op, + tBTA_GATT_STATUS status, + tGATT_CL_COMPLETE *p_data); + +static void bta_gattc_deregister_cmpl(tBTA_GATTC_RCB *p_clreg); +static void bta_gattc_enc_cmpl_cback(tGATT_IF gattc_if, BD_ADDR bda); +static void bta_gattc_cong_cback (UINT16 conn_id, BOOLEAN congested); + +static tGATT_CBACK bta_gattc_cl_cback = +{ + bta_gattc_conn_cback, + bta_gattc_cmpl_cback, + bta_gattc_disc_res_cback, + bta_gattc_disc_cmpl_cback, + NULL, + bta_gattc_enc_cmpl_cback, + bta_gattc_cong_cback +}; + +/* opcode(tGATTC_OPTYPE) order has to be comply with internal event order */ +static UINT16 bta_gattc_opcode_to_int_evt[] = +{ + BTA_GATTC_API_READ_EVT, + BTA_GATTC_API_WRITE_EVT, + BTA_GATTC_API_EXEC_EVT, + BTA_GATTC_API_CFG_MTU_EVT +}; + +#if (BT_TRACE_VERBOSE == TRUE) +static const char *bta_gattc_op_code_name[] = +{ + "Unknown", + "Discovery", + "Read", + "Write", + "Exec", + "Config", + "Notification", + "Indication" +}; +#endif +/***************************************************************************** +** Action Functions +*****************************************************************************/ + +/******************************************************************************* +** +** Function bta_gattc_enable +** +** Description Enables GATTC module +** +** +** Returns void +** +*******************************************************************************/ +static void bta_gattc_enable(tBTA_GATTC_CB *p_cb) +{ + APPL_TRACE_DEBUG("bta_gattc_enable"); + + if (p_cb->state == BTA_GATTC_STATE_DISABLED) + { + /* initialize control block */ + memset(&bta_gattc_cb, 0, sizeof(tBTA_GATTC_CB)); + p_cb->state = BTA_GATTC_STATE_ENABLED; + } + else + { + APPL_TRACE_DEBUG("GATTC is arelady enabled"); + } +} + + +/******************************************************************************* +** +** Function bta_gattc_disable +** +** Description Disable GATTC module by cleaning up all active connections +** and deregister all application. +** +** Returns void +** +*******************************************************************************/ +void bta_gattc_disable(tBTA_GATTC_CB *p_cb) +{ + UINT8 i; + + APPL_TRACE_DEBUG("bta_gattc_disable"); + + if (p_cb->state != BTA_GATTC_STATE_ENABLED) + { + APPL_TRACE_ERROR("not enabled or disable in pogress"); + return; + } + + for (i = 0; i cl_rcb[i].in_use) + { + p_cb->state = BTA_GATTC_STATE_DISABLING; + /* don't deregister HH GATT IF */ + /* HH GATT IF will be deregistered by bta_hh_le_deregister when disable HH */ +#if (defined BTA_HH_LE_INCLUDED && BTA_HH_LE_INCLUDED == TRUE) + if (!bta_hh_le_is_hh_gatt_if(p_cb->cl_rcb[i].client_if)) { +#endif + bta_gattc_deregister(p_cb, &p_cb->cl_rcb[i]); +#if (defined BTA_HH_LE_INCLUDED && BTA_HH_LE_INCLUDED == TRUE) + } +#endif + } + } + + /* no registered apps, indicate disable completed */ + if (p_cb->state != BTA_GATTC_STATE_DISABLING) + { + p_cb->state = BTA_GATTC_STATE_DISABLED; + memset(p_cb, 0, sizeof(tBTA_GATTC_CB)); + } +} + +/******************************************************************************* +** +** Function bta_gattc_register +** +** Description Register a GATT client application with BTA. +** +** Returns void +** +*******************************************************************************/ +void bta_gattc_register(tBTA_GATTC_CB *p_cb, tBTA_GATTC_DATA *p_data) +{ + tBTA_GATTC cb_data; + UINT8 i; + tBT_UUID *p_app_uuid = &p_data->api_reg.app_uuid; + tBTA_GATTC_INT_START_IF *p_buf; + tBTA_GATT_STATUS status = BTA_GATT_NO_RESOURCES; + + + APPL_TRACE_DEBUG("bta_gattc_register state %d",p_cb->state); + memset(&cb_data, 0, sizeof(cb_data)); + cb_data.reg_oper.status = BTA_GATT_NO_RESOURCES; + + /* check if GATTC module is already enabled . Else enable */ + if (p_cb->state == BTA_GATTC_STATE_DISABLED) + { + bta_gattc_enable (p_cb); + } + /* todo need to check duplicate uuid */ + for (i = 0; i < BTA_GATTC_CL_MAX; i ++) + { + if (!p_cb->cl_rcb[i].in_use) + { + if ((p_app_uuid == NULL) || (p_cb->cl_rcb[i].client_if = GATT_Register(p_app_uuid, &bta_gattc_cl_cback)) == 0) + { + APPL_TRACE_ERROR("Register with GATT stack failed."); + status = BTA_GATT_ERROR; + } + else + { + p_cb->cl_rcb[i].in_use = TRUE; + p_cb->cl_rcb[i].p_cback = p_data->api_reg.p_cback; + memcpy(&p_cb->cl_rcb[i].app_uuid, p_app_uuid, sizeof(tBT_UUID)); + + /* BTA use the same client interface as BTE GATT statck */ + cb_data.reg_oper.client_if = p_cb->cl_rcb[i].client_if; + + if ((p_buf = (tBTA_GATTC_INT_START_IF *) GKI_getbuf(sizeof(tBTA_GATTC_INT_START_IF))) != NULL) + { + p_buf->hdr.event = BTA_GATTC_INT_START_IF_EVT; + p_buf->client_if = p_cb->cl_rcb[i].client_if; + + bta_sys_sendmsg(p_buf); + status = BTA_GATT_OK; + } + else + { + GATT_Deregister(p_cb->cl_rcb[i].client_if); + + status = BTA_GATT_NO_RESOURCES; + memset( &p_cb->cl_rcb[i], 0 , sizeof(tBTA_GATTC_RCB)); + } + break; + } + } + } + + /* callback with register event */ + if (p_data->api_reg.p_cback) + { + if (p_app_uuid != NULL) + memcpy(&(cb_data.reg_oper.app_uuid),p_app_uuid,sizeof(tBT_UUID)); + + cb_data.reg_oper.status = status; + (*p_data->api_reg.p_cback)(BTA_GATTC_REG_EVT, (tBTA_GATTC *)&cb_data); + } +} +/******************************************************************************* +** +** Function bta_gattc_start_if +** +** Description start an application interface. +** +** Returns none. +** +*******************************************************************************/ +void bta_gattc_start_if(tBTA_GATTC_CB *p_cb, tBTA_GATTC_DATA *p_msg) +{ + UNUSED(p_cb); + + if (bta_gattc_cl_get_regcb(p_msg->int_start_if.client_if) !=NULL ) + { + GATT_StartIf(p_msg->int_start_if.client_if); + } + else + { + APPL_TRACE_ERROR("Unable to start app.: Unknown interface =%d",p_msg->int_start_if.client_if ); + } +} +/******************************************************************************* +** +** Function bta_gattc_deregister +** +** Description De-Register a GATT client application with BTA. +** +** Returns void +** +*******************************************************************************/ +void bta_gattc_deregister(tBTA_GATTC_CB *p_cb, tBTA_GATTC_RCB *p_clreg) +{ + UINT8 i; + BT_HDR buf; + + if (p_clreg != NULL) + { + /* remove bg connection associated with this rcb */ + for (i = 0; i < BTA_GATTC_KNOWN_SR_MAX; i ++) + { + if (p_cb->bg_track[i].in_use) + { + if (p_cb->bg_track[i].cif_mask & (1 <<(p_clreg->client_if - 1))) + { + bta_gattc_mark_bg_conn(p_clreg->client_if, p_cb->bg_track[i].remote_bda, FALSE, FALSE); + GATT_CancelConnect(p_clreg->client_if, p_cb->bg_track[i].remote_bda, FALSE); + } + if (p_cb->bg_track[i].cif_adv_mask & (1 <<(p_clreg->client_if - 1))) + { + bta_gattc_mark_bg_conn(p_clreg->client_if, p_cb->bg_track[i].remote_bda, FALSE, TRUE); + } + } + } + + if (p_clreg->num_clcb > 0) + { + /* close all CLCB related to this app */ + for (i= 0; i < BTA_GATTC_CLCB_MAX; i ++) + { + if (p_cb->clcb[i].in_use && (p_cb->clcb[i].p_rcb == p_clreg)) + { + p_clreg->dereg_pending = TRUE; + + buf.event = BTA_GATTC_API_CLOSE_EVT; + buf.layer_specific = p_cb->clcb[i].bta_conn_id; + bta_gattc_close(&p_cb->clcb[i], (tBTA_GATTC_DATA *)&buf) ; + } + } + } + else + bta_gattc_deregister_cmpl(p_clreg); + } + else + { + APPL_TRACE_ERROR("bta_gattc_deregister Deregister Failedm unknown client cif"); + } +} +/******************************************************************************* +** +** Function bta_gattc_process_api_open +** +** Description process connect API request. +** +** Returns void +** +*******************************************************************************/ +void bta_gattc_process_api_open (tBTA_GATTC_CB *p_cb, tBTA_GATTC_DATA * p_msg) +{ + UINT16 event = ((BT_HDR *)p_msg)->event; + tBTA_GATTC_CLCB *p_clcb = NULL; + tBTA_GATTC_RCB *p_clreg = bta_gattc_cl_get_regcb(p_msg->api_conn.client_if); + UNUSED(p_cb); + + if (p_clreg != NULL) + { + if (p_msg->api_conn.is_direct) + { + if ((p_clcb = bta_gattc_find_alloc_clcb(p_msg->api_conn.client_if, + p_msg->api_conn.remote_bda, + p_msg->api_conn.transport)) != NULL) + { + bta_gattc_sm_execute(p_clcb, event, p_msg); + } + else + { + APPL_TRACE_ERROR("No resources to open a new connection."); + + bta_gattc_send_open_cback(p_clreg, + BTA_GATT_NO_RESOURCES, + p_msg->api_conn.remote_bda, + BTA_GATT_INVALID_CONN_ID, + p_msg->api_conn.transport, 0); + } + } + else + { + bta_gattc_init_bk_conn(&p_msg->api_conn, p_clreg); + } + } + else + { + APPL_TRACE_ERROR("bta_gattc_process_api_open Failed, unknown client_if: %d", + p_msg->api_conn.client_if); + } +} +/******************************************************************************* +** +** Function bta_gattc_process_api_open_cancel +** +** Description process connect API request. +** +** Returns void +** +*******************************************************************************/ +void bta_gattc_process_api_open_cancel (tBTA_GATTC_CB *p_cb, tBTA_GATTC_DATA * p_msg) +{ + UINT16 event = ((BT_HDR *)p_msg)->event; + tBTA_GATTC_CLCB *p_clcb = NULL; + tBTA_GATTC_RCB *p_clreg; + tBTA_GATTC cb_data; + UNUSED(p_cb); + + if (p_msg->api_cancel_conn.is_direct) + { + if ((p_clcb = bta_gattc_find_clcb_by_cif(p_msg->api_cancel_conn.client_if, + p_msg->api_cancel_conn.remote_bda, + BTA_GATT_TRANSPORT_LE)) != NULL) + { + bta_gattc_sm_execute(p_clcb, event, p_msg); + } + else + { + APPL_TRACE_ERROR("No such connection need to be cancelled"); + + p_clreg = bta_gattc_cl_get_regcb(p_msg->api_cancel_conn.client_if); + + if (p_clreg && p_clreg->p_cback) + { + cb_data.status = BTA_GATT_ERROR; + (*p_clreg->p_cback)(BTA_GATTC_CANCEL_OPEN_EVT, &cb_data); + } + } + } + else + { + bta_gattc_cancel_bk_conn(&p_msg->api_cancel_conn); + + } +} + +/******************************************************************************* +** +** Function bta_gattc_process_enc_cmpl +** +** Description process encryption complete message. +** +** Returns void +** +*******************************************************************************/ +void bta_gattc_process_enc_cmpl(tBTA_GATTC_CB *p_cb, tBTA_GATTC_DATA *p_msg) +{ + tBTA_GATTC_RCB *p_clreg; + tBTA_GATTC cb_data; + UNUSED(p_cb); + + p_clreg = bta_gattc_cl_get_regcb(p_msg->enc_cmpl.client_if); + + if (p_clreg && p_clreg->p_cback) + { + memset(&cb_data, 0, sizeof(tBTA_GATTC)); + + cb_data.enc_cmpl.client_if = p_msg->enc_cmpl.client_if; + bdcpy(cb_data.enc_cmpl.remote_bda, p_msg->enc_cmpl.remote_bda); + + (*p_clreg->p_cback)(BTA_GATTC_ENC_CMPL_CB_EVT, &cb_data); + } +} + +/******************************************************************************* +** +** Function bta_gattc_cancel_open_error +** +** Description +** +** Returns void +** +*******************************************************************************/ +void bta_gattc_cancel_open_error(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data) +{ + tBTA_GATTC cb_data; + UNUSED(p_data); + + cb_data.status=BTA_GATT_ERROR; + + if ( p_clcb && p_clcb->p_rcb && p_clcb->p_rcb->p_cback ) + (*p_clcb->p_rcb->p_cback)(BTA_GATTC_CANCEL_OPEN_EVT, &cb_data); +} + +/******************************************************************************* +** +** Function bta_gattc_open_error +** +** Description +** +** Returns void +** +*******************************************************************************/ +void bta_gattc_open_error(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data) +{ + UNUSED(p_data); + + APPL_TRACE_ERROR("Connection already opened. wrong state"); + + bta_gattc_send_open_cback(p_clcb->p_rcb, + BTA_GATT_OK, + p_clcb->bda, + p_clcb->bta_conn_id, + p_clcb->transport, + 0); +} +/******************************************************************************* +** +** Function bta_gattc_open_fail +** +** Description +** +** Returns void +** +*******************************************************************************/ +void bta_gattc_open_fail(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data) +{ + UNUSED(p_data); + + bta_gattc_send_open_cback(p_clcb->p_rcb, + BTA_GATT_ERROR, + p_clcb->bda, + p_clcb->bta_conn_id, + p_clcb->transport, + 0); + /* open failure, remove clcb */ + bta_gattc_clcb_dealloc(p_clcb); +} + +/******************************************************************************* +** +** Function bta_gattc_open +** +** Description Process API connection function. +** +** Returns void +** +*******************************************************************************/ +void bta_gattc_open(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data) +{ + tBTA_GATTC_DATA gattc_data; + + /* open/hold a connection */ + if (!GATT_Connect(p_clcb->p_rcb->client_if, p_data->api_conn.remote_bda, + TRUE, p_data->api_conn.transport)) + { + APPL_TRACE_ERROR("Connection open failure"); + + bta_gattc_sm_execute(p_clcb, BTA_GATTC_INT_OPEN_FAIL_EVT, p_data); + } + else + { + /* a connected remote device */ + if (GATT_GetConnIdIfConnected(p_clcb->p_rcb->client_if, + p_data->api_conn.remote_bda, + &p_clcb->bta_conn_id, + p_data->api_conn.transport)) + { + gattc_data.int_conn.hdr.layer_specific = p_clcb->bta_conn_id; + + bta_gattc_sm_execute(p_clcb, BTA_GATTC_INT_CONN_EVT, &gattc_data); + } + /* else wait for the callback event */ + } +} +/******************************************************************************* +** +** Function bta_gattc_init_bk_conn +** +** Description Process API Open for a background connection +** +** Returns void +** +*******************************************************************************/ +void bta_gattc_init_bk_conn(tBTA_GATTC_API_OPEN *p_data, tBTA_GATTC_RCB *p_clreg) +{ + tBTA_GATT_STATUS status = BTA_GATT_NO_RESOURCES; + UINT16 conn_id; + tBTA_GATTC_CLCB *p_clcb; + tBTA_GATTC_DATA gattc_data; + + if (bta_gattc_mark_bg_conn(p_data->client_if, p_data->remote_bda, TRUE, FALSE)) + { + /* always call open to hold a connection */ + if (!GATT_Connect(p_data->client_if, p_data->remote_bda, FALSE, p_data->transport)) + { + uint8_t *bda = (uint8_t *)p_data->remote_bda; + status = BTA_GATT_ERROR; + APPL_TRACE_ERROR("%s unable to connect to remote bd_addr:%02x:%02x:%02x:%02x:%02x:%02x", + __func__, bda[0], bda[1], bda[2], bda[3], bda[4], bda[5]); + + } + else + { + status = BTA_GATT_OK; + + /* if is a connected remote device */ + if (GATT_GetConnIdIfConnected(p_data->client_if, + p_data->remote_bda, + &conn_id, + p_data->transport)) + { + if ((p_clcb = bta_gattc_find_alloc_clcb(p_data->client_if, p_data->remote_bda, + BTA_GATT_TRANSPORT_LE)) != NULL) + { + gattc_data.hdr.layer_specific = p_clcb->bta_conn_id = conn_id; + + /* open connection */ + bta_gattc_sm_execute(p_clcb, BTA_GATTC_INT_CONN_EVT, &gattc_data); + status = BTA_GATT_OK; + } + } + } + } + + /* open failure, report OPEN_EVT */ + if (status != BTA_GATT_OK) + { + bta_gattc_send_open_cback(p_clreg, status, p_data->remote_bda, + BTA_GATT_INVALID_CONN_ID, BTA_GATT_TRANSPORT_LE, 0); + } +} +/******************************************************************************* +** +** Function bta_gattc_cancel_bk_conn +** +** Description Process API Cancel Open for a background connection +** +** Returns void +** +*******************************************************************************/ +void bta_gattc_cancel_bk_conn(tBTA_GATTC_API_CANCEL_OPEN *p_data) +{ + tBTA_GATTC_RCB *p_clreg; + tBTA_GATTC cb_data; + cb_data.status = BTA_GATT_ERROR; + + /* remove the device from the bg connection mask */ + if (bta_gattc_mark_bg_conn(p_data->client_if, p_data->remote_bda, FALSE, FALSE)) + { + if (GATT_CancelConnect(p_data->client_if, p_data->remote_bda, FALSE)) + { + cb_data.status = BTA_GATT_OK; + } + else + { + APPL_TRACE_ERROR("bta_gattc_cancel_bk_conn failed"); + } + } + p_clreg = bta_gattc_cl_get_regcb(p_data->client_if); + + if (p_clreg && p_clreg->p_cback) + { + (*p_clreg->p_cback)(BTA_GATTC_CANCEL_OPEN_EVT, &cb_data); + } + +} +/******************************************************************************* +** +** Function bta_gattc_int_cancel_open_ok +** +** Description +** +** Returns void +** +*******************************************************************************/ +void bta_gattc_cancel_open_ok(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data) +{ + tBTA_GATTC cb_data; + UNUSED(p_data); + + if ( p_clcb->p_rcb->p_cback ) + { + cb_data.status = BTA_GATT_OK; + (*p_clcb->p_rcb->p_cback)(BTA_GATTC_CANCEL_OPEN_EVT, &cb_data); + } + + bta_gattc_clcb_dealloc(p_clcb); +} +/******************************************************************************* +** +** Function bta_gattc_cancel_open +** +** Description +** +** Returns void +** +*******************************************************************************/ +void bta_gattc_cancel_open(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data) +{ + tBTA_GATTC cb_data; + + if (GATT_CancelConnect(p_clcb->p_rcb->client_if, p_data->api_cancel_conn.remote_bda, TRUE)) + { + bta_gattc_sm_execute(p_clcb, BTA_GATTC_INT_CANCEL_OPEN_OK_EVT, p_data); + } + else + { + if ( p_clcb->p_rcb->p_cback ) + { + cb_data.status = BTA_GATT_ERROR; + (*p_clcb->p_rcb->p_cback)(BTA_GATTC_CANCEL_OPEN_EVT, &cb_data); + } + } +} +/******************************************************************************* +** +** Function bta_gattc_conn +** +** Description receive connection callback from stack +** +** Returns void +** +*******************************************************************************/ +void bta_gattc_conn(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data) +{ + tBTA_GATTC_IF gatt_if; + APPL_TRACE_DEBUG("bta_gattc_conn server cache state=%d",p_clcb->p_srcb->state); + + if (p_data != NULL) + { + APPL_TRACE_DEBUG("bta_gattc_conn conn_id=%d",p_data->hdr.layer_specific); + p_clcb->bta_conn_id = p_data->int_conn.hdr.layer_specific; + + GATT_GetConnectionInfor(p_data->hdr.layer_specific, + &gatt_if, p_clcb->bda, &p_clcb->transport); + } + + p_clcb->p_srcb->connected = TRUE; + + if (p_clcb->p_srcb->mtu == 0) + p_clcb->p_srcb->mtu = GATT_DEF_BLE_MTU_SIZE; + + /* start database cache if needed */ + if (p_clcb->p_srcb->p_srvc_cache == NULL || + p_clcb->p_srcb->state != BTA_GATTC_SERV_IDLE) + { + if (p_clcb->p_srcb->state == BTA_GATTC_SERV_IDLE) + { + p_clcb->p_srcb->state = BTA_GATTC_SERV_LOAD; + bta_gattc_sm_execute(p_clcb, BTA_GATTC_START_CACHE_EVT, NULL); + } + else /* cache is building */ + p_clcb->state = BTA_GATTC_DISCOVER_ST; + } + + else + { + /* a pending service handle change indication */ + if (p_clcb->p_srcb->srvc_hdl_chg) + { + p_clcb->p_srcb->srvc_hdl_chg = FALSE; + /* start discovery */ + bta_gattc_sm_execute(p_clcb, BTA_GATTC_INT_DISCOVER_EVT, NULL); + } + } + + if (p_clcb->p_rcb) + { + /* there is no RM for GATT */ + if (p_clcb->transport == BTA_TRANSPORT_BR_EDR) + bta_sys_conn_open(BTA_ID_GATTC, BTA_ALL_APP_ID, p_clcb->bda); + + bta_gattc_send_open_cback(p_clcb->p_rcb, + BTA_GATT_OK, + p_clcb->bda, + p_clcb->bta_conn_id, + p_clcb->transport, + p_clcb->p_srcb->mtu); + } + } +/******************************************************************************* +** +** Function bta_gattc_close_fail +** +** Description close a connection. +** +** Returns void +** +*******************************************************************************/ +void bta_gattc_close_fail(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data) +{ + tBTA_GATTC cb_data; + + if ( p_clcb->p_rcb->p_cback ) + { + memset(&cb_data, 0, sizeof(tBTA_GATTC)); + cb_data.close.client_if = p_clcb->p_rcb->client_if; + cb_data.close.conn_id = p_data->hdr.layer_specific; + bdcpy(cb_data.close.remote_bda, p_clcb->bda); + cb_data.close.status = BTA_GATT_ERROR; + cb_data.close.reason = BTA_GATT_CONN_NONE; + + + (*p_clcb->p_rcb->p_cback)(BTA_GATTC_CLOSE_EVT, &cb_data); + } +} +/******************************************************************************* +** +** Function bta_gattc_api_close +** +** Description close a GATTC connection. +** +** Returns void +** +*******************************************************************************/ +void bta_gattc_close(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data) +{ + tBTA_GATTC_CBACK *p_cback = p_clcb->p_rcb->p_cback; + tBTA_GATTC_RCB *p_clreg = p_clcb->p_rcb; + tBTA_GATTC cb_data; + + APPL_TRACE_DEBUG("bta_gattc_close conn_id=%d",p_clcb->bta_conn_id); + + cb_data.close.client_if = p_clcb->p_rcb->client_if; + cb_data.close.conn_id = p_clcb->bta_conn_id; + cb_data.close.reason = p_clcb->reason; + cb_data.close.status = p_clcb->status; + bdcpy(cb_data.close.remote_bda, p_clcb->bda); + + if (p_clcb->transport == BTA_TRANSPORT_BR_EDR) + bta_sys_conn_close( BTA_ID_GATTC ,BTA_ALL_APP_ID, p_clcb->bda); + + bta_gattc_clcb_dealloc(p_clcb); + + if (p_data->hdr.event == BTA_GATTC_API_CLOSE_EVT) + { + cb_data.close.status = GATT_Disconnect(p_data->hdr.layer_specific); + } + else if (p_data->hdr.event == BTA_GATTC_INT_DISCONN_EVT) + { + cb_data.close.status = p_data->int_conn.reason; + cb_data.close.reason = p_data->int_conn.reason; + } + + if(p_cback) + (* p_cback)(BTA_GATTC_CLOSE_EVT, (tBTA_GATTC *)&cb_data); + + if (p_clreg->num_clcb == 0 && p_clreg->dereg_pending) + { + bta_gattc_deregister_cmpl(p_clreg); + } +} +/******************************************************************************* +** +** Function bta_gattc_reset_discover_st +** +** Description when a SRCB finished discovery, tell all related clcb. +** +** Returns None. +** +*******************************************************************************/ +void bta_gattc_reset_discover_st(tBTA_GATTC_SERV *p_srcb, tBTA_GATT_STATUS status) +{ + tBTA_GATTC_CB *p_cb = &bta_gattc_cb; + UINT8 i; + + for (i = 0; i < BTA_GATTC_CLCB_MAX; i ++) + { + if (p_cb->clcb[i].p_srcb == p_srcb) + { + p_cb->clcb[i].status = status; + bta_gattc_sm_execute(&p_cb->clcb[i], BTA_GATTC_DISCOVER_CMPL_EVT, NULL); + } + } +} +/******************************************************************************* +** +** Function bta_gattc_disc_close +** +** Description close a GATTC connection while in discovery state. +** +** Returns void +** +*******************************************************************************/ +void bta_gattc_disc_close(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data) +{ + APPL_TRACE_DEBUG("%s: Discovery cancel conn_id=%d", __func__, + p_clcb->bta_conn_id); + + if (p_clcb->disc_active) + bta_gattc_reset_discover_st(p_clcb->p_srcb, BTA_GATT_ERROR); + else + p_clcb->state = BTA_GATTC_CONN_ST; + + // This function only gets called as the result of a BTA_GATTC_API_CLOSE_EVT + // while in the BTA_GATTC_DISCOVER_ST state. Once the state changes, the + // connection itself still needs to be closed to resolve the original event. + if (p_clcb->state == BTA_GATTC_CONN_ST) + { + APPL_TRACE_DEBUG("State is back to BTA_GATTC_CONN_ST. " + "Trigger connection close"); + bta_gattc_close(p_clcb, p_data); + } +} +/******************************************************************************* +** +** Function bta_gattc_set_discover_st +** +** Description when a SRCB start discovery, tell all related clcb and set +** the state. +** +** Returns None. +** +*******************************************************************************/ +void bta_gattc_set_discover_st(tBTA_GATTC_SERV *p_srcb) +{ + tBTA_GATTC_CB *p_cb = &bta_gattc_cb; + UINT8 i; + +#if BLE_INCLUDED == TRUE + L2CA_EnableUpdateBleConnParams(p_srcb->server_bda, FALSE); +#endif + for (i = 0; i < BTA_GATTC_CLCB_MAX; i ++) + { + if (p_cb->clcb[i].p_srcb == p_srcb) + { + p_cb->clcb[i].status = BTA_GATT_OK; + p_cb->clcb[i].state = BTA_GATTC_DISCOVER_ST; + } + } +} +/******************************************************************************* +** +** Function bta_gattc_restart_discover +** +** Description process service change in discovery state, mark up the auto +** update flag and set status to be discovery cancel for current +** discovery. +** +** Returns None. +** +*******************************************************************************/ +void bta_gattc_restart_discover(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data) +{ + UNUSED(p_data); + + p_clcb->status = BTA_GATT_CANCEL; + p_clcb->auto_update = BTA_GATTC_DISC_WAITING; +} + +/******************************************************************************* +** +** Function bta_gattc_cfg_mtu +** +** Description Configure MTU size on the GATT connection. +** +** Returns None. +** +*******************************************************************************/ +void bta_gattc_cfg_mtu(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data) +{ + tBTA_GATT_STATUS status; + + if (bta_gattc_enqueue(p_clcb, p_data)) + { + status = GATTC_ConfigureMTU (p_clcb->bta_conn_id, p_data->api_mtu.mtu); + + /* if failed, return callback here */ + if (status != GATT_SUCCESS && status != GATT_CMD_STARTED) + { + /* Dequeue the data, if it was enqueued */ + if (p_clcb->p_q_cmd == p_data) + p_clcb->p_q_cmd = NULL; + + bta_gattc_cmpl_sendmsg(p_clcb->bta_conn_id, GATTC_OPTYPE_CONFIG, status, NULL); + } + } +} +/******************************************************************************* +** +** Function bta_gattc_start_discover +** +** Description Start a discovery send to server. +** +** Returns None. +** +*******************************************************************************/ +void bta_gattc_start_discover(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data) +{ + UNUSED(p_data); + + APPL_TRACE_DEBUG("bta_gattc_start_discover conn_id=%d p_clcb->p_srcb->state = %d ", + p_clcb->bta_conn_id, p_clcb->p_srcb->state); + + if (((p_clcb->p_q_cmd == NULL || p_clcb->auto_update == BTA_GATTC_REQ_WAITING) && + p_clcb->p_srcb->state == BTA_GATTC_SERV_IDLE) || + p_clcb->p_srcb->state == BTA_GATTC_SERV_DISC) + /* no pending operation, start discovery right away */ + { + p_clcb->auto_update = BTA_GATTC_NO_SCHEDULE; + + if (p_clcb->p_srcb != NULL) + { + /* clear the service change mask */ + p_clcb->p_srcb->srvc_hdl_chg = FALSE; + p_clcb->p_srcb->update_count = 0; + p_clcb->p_srcb->state = BTA_GATTC_SERV_DISC_ACT; + + if (p_clcb->transport == BTA_TRANSPORT_LE) + L2CA_EnableUpdateBleConnParams(p_clcb->p_srcb->server_bda, FALSE); + + /* set all srcb related clcb into discovery ST */ + bta_gattc_set_discover_st(p_clcb->p_srcb); + + if ((p_clcb->status = bta_gattc_init_cache(p_clcb->p_srcb)) == BTA_GATT_OK) + { + p_clcb->status = bta_gattc_discover_pri_service(p_clcb->bta_conn_id, + p_clcb->p_srcb, GATT_DISC_SRVC_ALL); + } + if (p_clcb->status != BTA_GATT_OK) + { + APPL_TRACE_ERROR("discovery on server failed"); + bta_gattc_reset_discover_st(p_clcb->p_srcb, p_clcb->status); + } + else + p_clcb->disc_active = TRUE; + } + else + { + APPL_TRACE_ERROR("unknown device, can not start discovery"); + } + } + /* pending operation, wait until it finishes */ + else + { + p_clcb->auto_update = BTA_GATTC_DISC_WAITING; + + if (p_clcb->p_srcb->state == BTA_GATTC_SERV_IDLE) + p_clcb->state = BTA_GATTC_CONN_ST; /* set clcb state */ + } + +} +/******************************************************************************* +** +** Function bta_gattc_disc_cmpl +** +** Description discovery on server is finished +** +** Returns None. +** +*******************************************************************************/ +void bta_gattc_disc_cmpl(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data) +{ + tBTA_GATTC_DATA *p_q_cmd = p_clcb->p_q_cmd; + UNUSED(p_data); + + APPL_TRACE_DEBUG("bta_gattc_disc_cmpl conn_id=%d",p_clcb->bta_conn_id); + +#if BLE_INCLUDED == TRUE + if(p_clcb->transport == BTA_TRANSPORT_LE) + L2CA_EnableUpdateBleConnParams(p_clcb->p_srcb->server_bda, TRUE); +#endif + p_clcb->p_srcb->state = BTA_GATTC_SERV_IDLE; + p_clcb->disc_active = FALSE; + + if (p_clcb->status != GATT_SUCCESS) + { + /* clean up cache */ + if(p_clcb->p_srcb && p_clcb->p_srcb->p_srvc_cache) + { + while (!GKI_queue_is_empty(&p_clcb->p_srcb->cache_buffer)) + { + GKI_freebuf (GKI_dequeue (&p_clcb->p_srcb->cache_buffer)); + } + p_clcb->p_srcb->p_srvc_cache = NULL; + } + + /* used to reset cache in application */ + bta_gattc_co_cache_reset(p_clcb->p_srcb->server_bda); + } + /* release pending attribute list buffer */ + utl_freebuf((void **)&p_clcb->p_srcb->p_srvc_list); + + if (p_clcb->auto_update == BTA_GATTC_DISC_WAITING) + { + /* start discovery again */ + bta_gattc_sm_execute(p_clcb, BTA_GATTC_INT_DISCOVER_EVT, NULL); + } + /* get any queued command to proceed */ + else if (p_q_cmd != NULL) + { + p_clcb->p_q_cmd = NULL; + + bta_gattc_sm_execute(p_clcb, p_q_cmd->hdr.event, p_q_cmd); + /* if the command executed requeued the cmd, we don't + * want to free the underlying buffer that's being + * referenced by p_clcb->p_q_cmd + */ + if (p_q_cmd != p_clcb->p_q_cmd) { + utl_freebuf((void **)&p_q_cmd); + } + } +} +/******************************************************************************* +** +** Function bta_gattc_read +** +** Description Read an attribute +** +** Returns None. +** +*******************************************************************************/ +void bta_gattc_read(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data) +{ + UINT16 handle = 0; + tGATT_READ_PARAM read_param; + tBTA_GATT_STATUS status; + + memset (&read_param, 0 ,sizeof(tGATT_READ_PARAM)); + + if (bta_gattc_enqueue(p_clcb, p_data)) + { + if ((handle = bta_gattc_id2handle(p_clcb->p_srcb, + &p_data->api_read.srvc_id, + &p_data->api_read.char_id, + p_data->api_read.p_descr_type)) == 0) + { + status = BTA_GATT_ERROR; + } + else + { + read_param.by_handle.handle = handle; + read_param.by_handle.auth_req = p_data->api_read.auth_req; + + status = GATTC_Read(p_clcb->bta_conn_id, GATT_READ_BY_HANDLE, &read_param); + } + + /* read fail */ + if (status != BTA_GATT_OK) + { + /* Dequeue the data, if it was enqueued */ + if (p_clcb->p_q_cmd == p_data) + p_clcb->p_q_cmd = NULL; + + bta_gattc_cmpl_sendmsg(p_clcb->bta_conn_id, GATTC_OPTYPE_READ, status, NULL); + } + } +} +/******************************************************************************* +** +** Function bta_gattc_read_multi +** +** Description read multiple +** +** Returns None. +*********************************************************************************/ +void bta_gattc_read_multi(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data) +{ + UINT16 i, handle; + tBTA_GATT_STATUS status = BTA_GATT_OK; + tGATT_READ_PARAM read_param; + tBTA_GATTC_ATTR_ID *p_id; + + if (bta_gattc_enqueue(p_clcb, p_data)) + { + memset(&read_param, 0, sizeof(tGATT_READ_PARAM)); + + p_id = p_data->api_read_multi.p_id_list; + + for (i = 0; i < p_data->api_read_multi.num_attr && p_id; i ++, p_id ++) + { + handle = 0; + + if (p_id->id_type == BTA_GATT_TYPE_CHAR) + { + handle = bta_gattc_id2handle(p_clcb->p_srcb, + &p_id->id_value.char_id.srvc_id, + &p_id->id_value.char_id.char_id, + NULL); + } + else if (p_id->id_type == BTA_GATT_TYPE_CHAR_DESCR) + { + handle = bta_gattc_id2handle(p_clcb->p_srcb, + &p_id->id_value.char_descr_id.char_id.srvc_id, + &p_id->id_value.char_descr_id.char_id.char_id, + &p_id->id_value.char_descr_id.descr_id); + } + else + { + APPL_TRACE_ERROR("invalud ID type: %d", p_id->id_type); + } + + if (handle == 0) + { + status = BTA_GATT_ERROR; + break; + } + } + if (status == BTA_GATT_OK) + { + read_param.read_multiple.num_handles = p_data->api_read_multi.num_attr; + read_param.read_multiple.auth_req = p_data->api_read_multi.auth_req; + + status = GATTC_Read(p_clcb->bta_conn_id, GATT_READ_MULTIPLE, &read_param); + } + + /* read fail */ + if (status != BTA_GATT_OK) + { + /* Dequeue the data, if it was enqueued */ + if (p_clcb->p_q_cmd == p_data) + p_clcb->p_q_cmd = NULL; + + bta_gattc_cmpl_sendmsg(p_clcb->bta_conn_id, GATTC_OPTYPE_READ, status, NULL); + } + } +} +/******************************************************************************* +** +** Function bta_gattc_write +** +** Description Write an attribute +** +** Returns None. +** +*******************************************************************************/ +void bta_gattc_write(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data) +{ + UINT16 handle = 0; + tGATT_VALUE attr = {0}; + tBTA_GATT_STATUS status = BTA_GATT_OK; + + if (bta_gattc_enqueue(p_clcb, p_data)) + { + if ((handle = bta_gattc_id2handle(p_clcb->p_srcb, + &p_data->api_write.srvc_id, + &p_data->api_write.char_id, + p_data->api_write.p_descr_type)) == 0) + { + status = BTA_GATT_ERROR; + } + else + { + attr.handle= handle; + attr.offset = p_data->api_write.offset; + attr.len = p_data->api_write.len; + attr.auth_req = p_data->api_write.auth_req; + + if (p_data->api_write.p_value) + memcpy(attr.value, p_data->api_write.p_value, p_data->api_write.len); + + status = GATTC_Write(p_clcb->bta_conn_id, p_data->api_write.write_type, &attr); + } + + /* write fail */ + if (status != BTA_GATT_OK) + { + /* Dequeue the data, if it was enqueued */ + if (p_clcb->p_q_cmd == p_data) + p_clcb->p_q_cmd = NULL; + + bta_gattc_cmpl_sendmsg(p_clcb->bta_conn_id, GATTC_OPTYPE_WRITE, status, NULL); + } + } +} +/******************************************************************************* +** +** Function bta_gattc_execute +** +** Description send execute write +** +** Returns None. +*********************************************************************************/ +void bta_gattc_execute(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data) +{ + tBTA_GATT_STATUS status; + + if (bta_gattc_enqueue(p_clcb, p_data)) + { + status = GATTC_ExecuteWrite(p_clcb->bta_conn_id, p_data->api_exec.is_execute); + + if (status != BTA_GATT_OK) + { + /* Dequeue the data, if it was enqueued */ + if (p_clcb->p_q_cmd == p_data) + p_clcb->p_q_cmd = NULL; + + bta_gattc_cmpl_sendmsg(p_clcb->bta_conn_id, GATTC_OPTYPE_EXE_WRITE, status, NULL); + } + } +} +/******************************************************************************* +** +** Function bta_gattc_confirm +** +** Description send handle value confirmation +** +** Returns None. +** +*******************************************************************************/ +void bta_gattc_confirm(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data) +{ + UINT16 handle; + + if ((handle = bta_gattc_id2handle(p_clcb->p_srcb, + &p_data->api_confirm.srvc_id, + &p_data->api_confirm.char_id, + NULL)) == 0) + { + APPL_TRACE_ERROR("Can not map service/char ID into valid handle"); + } + else + { + if (GATTC_SendHandleValueConfirm(p_data->api_confirm.hdr.layer_specific, handle) + != GATT_SUCCESS) + { + APPL_TRACE_ERROR("bta_gattc_confirm to handle [0x%04x] failed", handle); + } + else + { + /* if over BR_EDR, inform PM for mode change */ + if (p_clcb->transport == BTA_TRANSPORT_BR_EDR) + { + bta_sys_busy(BTA_ID_GATTC, BTA_ALL_APP_ID, p_clcb->bda); + bta_sys_idle(BTA_ID_GATTC, BTA_ALL_APP_ID, p_clcb->bda); + } + } + } +} +/******************************************************************************* +** +** Function bta_gattc_read_cmpl +** +** Description read complete +** +** Returns None. +** +*******************************************************************************/ +void bta_gattc_read_cmpl(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_OP_CMPL *p_data) +{ + UINT8 event; + tBTA_GATTC cb_data; + tBTA_GATT_READ_VAL read_value; + + memset(&cb_data, 0, sizeof(tBTA_GATTC)); + memset(&read_value, 0, sizeof(tBTA_GATT_READ_VAL)); + + cb_data.read.status = p_data->status; + + if (p_data->p_cmpl != NULL && p_data->status == BTA_GATT_OK) + { + if (bta_gattc_handle2id(p_clcb->p_srcb, + p_data->p_cmpl->att_value.handle, + &cb_data.read.srvc_id, + &cb_data.read.char_id, + &cb_data.read.descr_type) == FALSE) + { + cb_data.read.status = BTA_GATT_INTERNAL_ERROR; + APPL_TRACE_ERROR("can not map to GATT ID. handle = 0x%04x", + p_data->p_cmpl->att_value.handle); + } + else + { + cb_data.read.status = bta_gattc_pack_read_cb_data(p_clcb->p_srcb, + &cb_data.read.descr_type.uuid, + &p_data->p_cmpl->att_value, + &read_value); + cb_data.read.p_value = &read_value; + } + } + else + { + cb_data.read.srvc_id = p_clcb->p_q_cmd->api_read.srvc_id; + cb_data.read.char_id = p_clcb->p_q_cmd->api_read.char_id; + if (p_clcb->p_q_cmd->api_read.p_descr_type) + memcpy(&cb_data.read.descr_type, p_clcb->p_q_cmd->api_read.p_descr_type, + sizeof(tBTA_GATT_ID)); + } + + event = (p_clcb->p_q_cmd->api_read.p_descr_type == NULL) ? + BTA_GATTC_READ_CHAR_EVT: BTA_GATTC_READ_DESCR_EVT; + cb_data.read.conn_id = p_clcb->bta_conn_id; + + utl_freebuf((void **)&p_clcb->p_q_cmd); + /* read complete, callback */ + ( *p_clcb->p_rcb->p_cback)(event, (tBTA_GATTC *)&cb_data); + +} +/******************************************************************************* +** +** Function bta_gattc_write_cmpl +** +** Description write complete +** +** Returns None. +** +*******************************************************************************/ +void bta_gattc_write_cmpl(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_OP_CMPL *p_data) +{ + tBTA_GATTC cb_data = {0}; + UINT8 event; + + memset(&cb_data, 0, sizeof(tBTA_GATTC)); + + cb_data.write.status = p_data->status; + + if (p_data->p_cmpl != NULL) + { + bta_gattc_handle2id(p_clcb->p_srcb, p_data->p_cmpl->att_value.handle, + &cb_data.write.srvc_id, &cb_data.write.char_id, + &cb_data.write.descr_type); + } + else + { + memcpy(&cb_data.write.srvc_id, &p_clcb->p_q_cmd->api_write.srvc_id, + sizeof(tBTA_GATT_SRVC_ID)); + memcpy(&cb_data.write.char_id, &p_clcb->p_q_cmd->api_write.char_id, + sizeof(tBTA_GATT_ID)); + if (p_clcb->p_q_cmd->api_write.p_descr_type) + memcpy(&cb_data.write.descr_type, p_clcb->p_q_cmd->api_write.p_descr_type, + sizeof(tBTA_GATT_ID)); + } + + if (p_clcb->p_q_cmd->api_write.hdr.event == BTA_GATTC_API_WRITE_EVT && + p_clcb->p_q_cmd->api_write.write_type == BTA_GATTC_WRITE_PREPARE) + + event = BTA_GATTC_PREP_WRITE_EVT; + + else if (p_clcb->p_q_cmd->api_write.p_descr_type == NULL) + + event = BTA_GATTC_WRITE_CHAR_EVT; + + else + event = BTA_GATTC_WRITE_DESCR_EVT; + + utl_freebuf((void **)&p_clcb->p_q_cmd); + cb_data.write.conn_id = p_clcb->bta_conn_id; + /* write complete, callback */ + ( *p_clcb->p_rcb->p_cback)(event, (tBTA_GATTC *)&cb_data); + +} +/******************************************************************************* +** +** Function bta_gattc_exec_cmpl +** +** Description execute write complete +** +** Returns None. +** +*******************************************************************************/ +void bta_gattc_exec_cmpl(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_OP_CMPL *p_data) +{ + tBTA_GATTC cb_data; + + utl_freebuf((void **)&p_clcb->p_q_cmd); + + p_clcb->status = BTA_GATT_OK; + + /* execute complete, callback */ + cb_data.exec_cmpl.conn_id = p_clcb->bta_conn_id; + cb_data.exec_cmpl.status = p_data->status; + + ( *p_clcb->p_rcb->p_cback)(BTA_GATTC_EXEC_EVT, &cb_data); + +} + +/******************************************************************************* +** +** Function bta_gattc_cfg_mtu_cmpl +** +** Description configure MTU operation complete +** +** Returns None. +** +*******************************************************************************/ +void bta_gattc_cfg_mtu_cmpl(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_OP_CMPL *p_data) +{ + tBTA_GATTC cb_data; + + utl_freebuf((void **)&p_clcb->p_q_cmd); + + + if (p_data->p_cmpl && p_data->status == BTA_GATT_OK) + p_clcb->p_srcb->mtu = p_data->p_cmpl->mtu; + + /* configure MTU complete, callback */ + p_clcb->status = p_data->status; + cb_data.cfg_mtu.conn_id = p_clcb->bta_conn_id; + cb_data.cfg_mtu.status = p_data->status; + cb_data.cfg_mtu.mtu = p_clcb->p_srcb->mtu; + + (*p_clcb->p_rcb->p_cback) (BTA_GATTC_CFG_MTU_EVT, &cb_data); + +} +/******************************************************************************* +** +** Function bta_gattc_op_cmpl +** +** Description operation completed. +** +** Returns None. +** +*******************************************************************************/ +void bta_gattc_op_cmpl(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data) +{ + UINT8 op = (UINT8)p_data->op_cmpl.op_code; + UINT8 mapped_op = 0; + + APPL_TRACE_DEBUG("bta_gattc_op_cmpl op = %d", op); + + if (op == GATTC_OPTYPE_INDICATION || op == GATTC_OPTYPE_NOTIFICATION) + { + APPL_TRACE_ERROR("unexpected operation, ignored"); + } + else if (op >= GATTC_OPTYPE_READ) + { + if (p_clcb->p_q_cmd == NULL) + { + APPL_TRACE_ERROR("No pending command"); + return; + } + if (p_clcb->p_q_cmd->hdr.event != bta_gattc_opcode_to_int_evt[op - GATTC_OPTYPE_READ]) + { + mapped_op = p_clcb->p_q_cmd->hdr.event - BTA_GATTC_API_READ_EVT + GATTC_OPTYPE_READ; + if ( mapped_op > GATTC_OPTYPE_INDICATION) mapped_op = 0; + +#if (BT_TRACE_VERBOSE == TRUE) + APPL_TRACE_ERROR("expect op:(%s :0x%04x), receive unexpected operation (%s).", + bta_gattc_op_code_name[mapped_op] , p_clcb->p_q_cmd->hdr.event, + bta_gattc_op_code_name[op]); +#else + APPL_TRACE_ERROR("expect op:(%u :0x%04x), receive unexpected operation (%u).", + mapped_op , p_clcb->p_q_cmd->hdr.event, op); +#endif + return; + } + + /* discard responses if service change indication is received before operation completed */ + if (p_clcb->auto_update == BTA_GATTC_DISC_WAITING && p_clcb->p_srcb->srvc_hdl_chg) + { + APPL_TRACE_DEBUG("Discard all responses when service change indication is received."); + p_data->op_cmpl.status = GATT_ERROR; + } + + /* service handle change void the response, discard it */ + if (op == GATTC_OPTYPE_READ) + bta_gattc_read_cmpl(p_clcb, &p_data->op_cmpl); + + else if (op == GATTC_OPTYPE_WRITE) + bta_gattc_write_cmpl(p_clcb, &p_data->op_cmpl); + + else if (op == GATTC_OPTYPE_EXE_WRITE) + bta_gattc_exec_cmpl(p_clcb, &p_data->op_cmpl); + + else if (op == GATTC_OPTYPE_CONFIG) + bta_gattc_cfg_mtu_cmpl(p_clcb, &p_data->op_cmpl); + + if (p_clcb->auto_update == BTA_GATTC_DISC_WAITING) + { + p_clcb->auto_update = BTA_GATTC_REQ_WAITING; + bta_gattc_sm_execute(p_clcb, BTA_GATTC_INT_DISCOVER_EVT, NULL); + } + } +} +/******************************************************************************* +** +** Function bta_gattc_op_cmpl +** +** Description operation completed. +** +** Returns None. +** +*******************************************************************************/ +void bta_gattc_ignore_op_cmpl(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data) +{ + UNUSED(p_clcb); + + /* receive op complete when discovery is started, ignore the response, + and wait for discovery finish and resent */ + APPL_TRACE_DEBUG("bta_gattc_ignore_op_cmpl op = %d", p_data->hdr.layer_specific); + +} +/******************************************************************************* +** +** Function bta_gattc_search +** +** Description start a search in the local server cache +** +** Returns None. +** +*******************************************************************************/ +void bta_gattc_search(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data) +{ + tBTA_GATT_STATUS status = GATT_INTERNAL_ERROR; + tBTA_GATTC cb_data; + APPL_TRACE_DEBUG("bta_gattc_search conn_id=%d",p_clcb->bta_conn_id); + if (p_clcb->p_srcb && p_clcb->p_srcb->p_srvc_cache) + { + status = BTA_GATT_OK; + /* search the local cache of a server device */ + bta_gattc_search_service(p_clcb, p_data->api_search.p_srvc_uuid); + } + cb_data.search_cmpl.status = status; + cb_data.search_cmpl.conn_id = p_clcb->bta_conn_id; + + /* end of search or no server cache available */ + ( *p_clcb->p_rcb->p_cback)(BTA_GATTC_SEARCH_CMPL_EVT, &cb_data); +} +/******************************************************************************* +** +** Function bta_gattc_q_cmd +** +** Description enqueue a command into control block, usually because discovery +** operation is busy. +** +** Returns None. +** +*******************************************************************************/ +void bta_gattc_q_cmd(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data) +{ + bta_gattc_enqueue(p_clcb, p_data); +} +/******************************************************************************* +** +** Function bta_gattc_cache_open +** +** Description open a NV cache for loading +** +** Returns void +** +*******************************************************************************/ +void bta_gattc_cache_open(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data) +{ + UNUSED(p_data); + + bta_gattc_set_discover_st(p_clcb->p_srcb); + + APPL_TRACE_DEBUG("bta_gattc_cache_open conn_id=%d",p_clcb->bta_conn_id); + bta_gattc_co_cache_open(p_clcb->p_srcb->server_bda, BTA_GATTC_CI_CACHE_OPEN_EVT, + p_clcb->bta_conn_id, FALSE); +} +/******************************************************************************* +** +** Function bta_gattc_start_load +** +** Description start cache loading by sending callout open cache +** +** Returns None. +** +*******************************************************************************/ +void bta_gattc_ci_open(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data) +{ + APPL_TRACE_DEBUG("bta_gattc_ci_open conn_id=%d server state=%d" , + p_clcb->bta_conn_id, p_clcb->p_srcb->state); + if (p_clcb->p_srcb->state == BTA_GATTC_SERV_LOAD) + { + if (p_data->ci_open.status == BTA_GATT_OK) + { + p_clcb->p_srcb->attr_index = 0; + bta_gattc_co_cache_load(p_clcb->p_srcb->server_bda, + BTA_GATTC_CI_CACHE_LOAD_EVT, + p_clcb->p_srcb->attr_index, + p_clcb->bta_conn_id); + } + else + { + p_clcb->p_srcb->state = BTA_GATTC_SERV_DISC; + /* cache open failure, start discovery */ + bta_gattc_start_discover(p_clcb, NULL); + } + } + if (p_clcb->p_srcb->state == BTA_GATTC_SERV_SAVE) + { + if (p_data->ci_open.status == BTA_GATT_OK) + { + if (!bta_gattc_cache_save(p_clcb->p_srcb, p_clcb->bta_conn_id)) + { + p_data->ci_open.status = BTA_GATT_ERROR; + } + } + if (p_data->ci_open.status != BTA_GATT_OK) + { + p_clcb->p_srcb->attr_index = 0; + bta_gattc_co_cache_close(p_clcb->p_srcb->server_bda, p_clcb->bta_conn_id); + bta_gattc_reset_discover_st(p_clcb->p_srcb, p_clcb->status); + + } + } +} +/******************************************************************************* +** +** Function bta_gattc_ci_load +** +** Description cache loading received. +** +** Returns None. +** +*******************************************************************************/ +void bta_gattc_ci_load(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data) +{ + + APPL_TRACE_DEBUG("bta_gattc_ci_load conn_id=%d load status=%d", + p_clcb->bta_conn_id, p_data->ci_load.status); + + if (p_data->ci_load.status == BTA_GATT_OK || + p_data->ci_load.status == BTA_GATT_MORE) + { + if (p_data->ci_load.num_attr != 0) + bta_gattc_rebuild_cache(p_clcb->p_srcb, p_data->ci_load.num_attr, + p_data->ci_load.attr, p_clcb->p_srcb->attr_index); + + if (p_data->ci_load.status == BTA_GATT_OK) + { + p_clcb->p_srcb->attr_index = 0; + bta_gattc_reset_discover_st(p_clcb->p_srcb, BTA_GATT_OK); + bta_gattc_co_cache_close(p_clcb->p_srcb->server_bda, 0); + } + else /* load more */ + { + p_clcb->p_srcb->attr_index += p_data->ci_load.num_attr; + + bta_gattc_co_cache_load(p_clcb->p_srcb->server_bda, + BTA_GATTC_CI_CACHE_LOAD_EVT, + p_clcb->p_srcb->attr_index, + p_clcb->bta_conn_id); + } + } + else + { + bta_gattc_co_cache_close(p_clcb->p_srcb->server_bda, 0); + p_clcb->p_srcb->state = BTA_GATTC_SERV_DISC; + p_clcb->p_srcb->attr_index = 0; + /* cache load failure, start discovery */ + bta_gattc_start_discover(p_clcb, NULL); + } +} +/******************************************************************************* +** +** Function bta_gattc_ci_save +** +** Description cache loading received. +** +** Returns None. +** +*******************************************************************************/ +void bta_gattc_ci_save(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data) +{ + UNUSED(p_data); + + APPL_TRACE_DEBUG("bta_gattc_ci_save conn_id=%d " , + p_clcb->bta_conn_id ); + + if (!bta_gattc_cache_save(p_clcb->p_srcb, p_clcb->bta_conn_id)) + { + p_clcb->p_srcb->attr_index = 0; + bta_gattc_co_cache_close(p_clcb->p_srcb->server_bda, 0); + bta_gattc_reset_discover_st(p_clcb->p_srcb, p_clcb->status); + } +} +/******************************************************************************* +** +** Function bta_gattc_fail +** +** Description report API call failure back to apps +** +** Returns None. +** +*******************************************************************************/ +void bta_gattc_fail(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data) +{ + UNUSED(p_data); + + if (p_clcb->status == BTA_GATT_OK) + { + APPL_TRACE_ERROR("operation not supported at current state [%d]", p_clcb->state); + } +} + +/******************************************************************************* +** +** Function bta_gattc_deregister_cmpl +** +** Description De-Register a GATT client application with BTA completed. +** +** Returns void +** +*******************************************************************************/ +static void bta_gattc_deregister_cmpl(tBTA_GATTC_RCB *p_clreg) +{ + tBTA_GATTC_CB *p_cb = &bta_gattc_cb; + tBTA_GATTC_IF client_if = p_clreg->client_if; + tBTA_GATTC cb_data; + tBTA_GATTC_CBACK *p_cback = p_clreg->p_cback; + + memset(&cb_data, 0, sizeof(tBTA_GATTC)); + + GATT_Deregister(p_clreg->client_if); + memset(p_clreg, 0, sizeof(tBTA_GATTC_RCB)); + + cb_data.reg_oper.client_if = client_if; + cb_data.reg_oper.status = BTA_GATT_OK; + + if (p_cback) + /* callback with de-register event */ + (*p_cback)(BTA_GATTC_DEREG_EVT, (tBTA_GATTC *)&cb_data); + + if (bta_gattc_num_reg_app() == 0 && p_cb->state == BTA_GATTC_STATE_DISABLING) + { + p_cb->state = BTA_GATTC_STATE_DISABLED; + } +} +/******************************************************************************* +** +** Function bta_gattc_conn_cback +** +** Description callback functions to GATT client stack. +** +** Returns void +** +*******************************************************************************/ +static void bta_gattc_conn_cback(tGATT_IF gattc_if, BD_ADDR bda, UINT16 conn_id, + BOOLEAN connected, tGATT_DISCONN_REASON reason, + tBT_TRANSPORT transport) +{ + tBTA_GATTC_DATA *p_buf; + + if (reason != 0) + { + APPL_TRACE_WARNING("%s() - cif=%d connected=%d conn_id=%d reason=0x%04x", + __FUNCTION__, gattc_if, connected, conn_id, reason); + } + + bt_bdaddr_t bdaddr; + bdcpy(bdaddr.address, bda); + /* + if (connected) + btif_debug_conn_state(bdaddr, BTIF_DEBUG_CONNECTED, GATT_CONN_UNKNOWN); + else + btif_debug_conn_state(bdaddr, BTIF_DEBUG_DISCONNECTED, reason); + */ + if ((p_buf = (tBTA_GATTC_DATA *) GKI_getbuf(sizeof(tBTA_GATTC_DATA))) != NULL) + { + memset(p_buf, 0, sizeof(tBTA_GATTC_DATA)); + + p_buf->int_conn.hdr.event = connected ? BTA_GATTC_INT_CONN_EVT: + BTA_GATTC_INT_DISCONN_EVT; + p_buf->int_conn.hdr.layer_specific = conn_id; + p_buf->int_conn.client_if = gattc_if; + p_buf->int_conn.role = L2CA_GetBleConnRole(bda); + p_buf->int_conn.reason = reason; + p_buf->int_conn.transport = transport; + bdcpy(p_buf->int_conn.remote_bda, bda); + + bta_sys_sendmsg(p_buf); + } +} + +/******************************************************************************* +** +** Function bta_gattc_enc_cmpl_cback +** +** Description encryption complete callback function to GATT client stack. +** +** Returns void +** +*******************************************************************************/ +static void bta_gattc_enc_cmpl_cback(tGATT_IF gattc_if, BD_ADDR bda) +{ + tBTA_GATTC_DATA *p_buf; + tBTA_GATTC_CLCB *p_clcb = NULL; + + if ((p_clcb = bta_gattc_find_clcb_by_cif(gattc_if, bda, BTA_GATT_TRANSPORT_LE)) == NULL) + { + return; + } + +#if (defined BTA_HH_LE_INCLUDED && BTA_HH_LE_INCLUDED == TRUE) + /* filter this event just for BTA HH LE GATT client, + In the future, if we want to enable encryption complete event + for all GATT clients, we can remove this code */ + if (!bta_hh_le_is_hh_gatt_if(gattc_if)) + { + return; + } +#endif + + APPL_TRACE_DEBUG("bta_gattc_enc_cmpl_cback: cif = %d", gattc_if); + + if ((p_buf = (tBTA_GATTC_DATA *) GKI_getbuf(sizeof(tBTA_GATTC_DATA))) != NULL) + { + memset(p_buf, 0, sizeof(tBTA_GATTC_DATA)); + + p_buf->enc_cmpl.hdr.event = BTA_GATTC_ENC_CMPL_EVT; + p_buf->enc_cmpl.hdr.layer_specific = p_clcb->bta_conn_id; + p_buf->enc_cmpl.client_if = gattc_if; + bdcpy(p_buf->enc_cmpl.remote_bda, bda); + + bta_sys_sendmsg(p_buf); + } +} + +/******************************************************************************* +** +** Function bta_gattc_process_api_refresh +** +** Description process refresh API to delete cache and start a new discovery +** if currently connected. +** +** Returns None. +** +*******************************************************************************/ +void bta_gattc_process_api_refresh(tBTA_GATTC_CB *p_cb, tBTA_GATTC_DATA * p_msg) +{ + tBTA_GATTC_SERV *p_srvc_cb = bta_gattc_find_srvr_cache(p_msg->api_conn.remote_bda); + tBTA_GATTC_CLCB *p_clcb = &bta_gattc_cb.clcb[0]; + BOOLEAN found = FALSE; + UINT8 i; + UNUSED(p_cb); + + if (p_srvc_cb != NULL) + { + /* try to find a CLCB */ + if (p_srvc_cb->connected && p_srvc_cb->num_clcb != 0) + { + for (i = 0; i < BTA_GATTC_CLCB_MAX; i ++, p_clcb ++) + { + if (p_clcb->in_use && p_clcb->p_srcb == p_srvc_cb) + { + found = TRUE; + break; + } + } + if (found) + { + bta_gattc_sm_execute(p_clcb, BTA_GATTC_INT_DISCOVER_EVT, NULL); + return; + } + } + /* in all other cases, mark it and delete the cache */ + if (p_srvc_cb->p_srvc_cache != NULL) + { + while (!GKI_queue_is_empty(&p_srvc_cb->cache_buffer)) + GKI_freebuf (GKI_dequeue (&p_srvc_cb->cache_buffer)); + + p_srvc_cb->p_srvc_cache = NULL; + } + } + /* used to reset cache in application */ + bta_gattc_co_cache_reset(p_msg->api_conn.remote_bda); + +} +/******************************************************************************* +** +** Function bta_gattc_process_srvc_chg_ind +** +** Description process service change indication. +** +** Returns None. +** +*******************************************************************************/ +BOOLEAN bta_gattc_process_srvc_chg_ind(UINT16 conn_id, + tBTA_GATTC_RCB *p_clrcb, + tBTA_GATTC_SERV *p_srcb, + tBTA_GATTC_CLCB *p_clcb, + tBTA_GATTC_NOTIFY *p_notify, + UINT16 handle) +{ + tBT_UUID gattp_uuid, srvc_chg_uuid; + BOOLEAN processed = FALSE; + UINT8 i; + + gattp_uuid.len = 2; + gattp_uuid.uu.uuid16 = UUID_SERVCLASS_GATT_SERVER; + + srvc_chg_uuid.len = 2; + srvc_chg_uuid.uu.uuid16 = GATT_UUID_GATT_SRV_CHGD; + + if (bta_gattc_uuid_compare(&p_notify->char_id.srvc_id.id.uuid, &gattp_uuid, TRUE) && + bta_gattc_uuid_compare(&p_notify->char_id.char_id.uuid, &srvc_chg_uuid, TRUE)) + { + processed = TRUE; + /* mark service handle change pending */ + p_srcb->srvc_hdl_chg = TRUE; + /* clear up all notification/indication registration */ + bta_gattc_clear_notif_registration(conn_id); + /* service change indication all received, do discovery update */ + if ( ++ p_srcb->update_count == bta_gattc_num_reg_app()) + { + /* not an opened connection; or connection busy */ + /* search for first available clcb and start discovery */ + if (p_clcb == NULL || (p_clcb && p_clcb->p_q_cmd != NULL)) + { + for (i = 0 ; i < BTA_GATTC_CLCB_MAX; i ++) + { + if (bta_gattc_cb.clcb[i].in_use && + bta_gattc_cb.clcb[i].p_srcb == p_srcb && + bta_gattc_cb.clcb[i].p_q_cmd == NULL) + { + p_clcb = &bta_gattc_cb.clcb[i]; + break; + } + } + } + /* send confirmation here if this is an indication, it should always be */ + GATTC_SendHandleValueConfirm(conn_id, handle); + + /* if connection available, refresh cache by doing discovery now */ + if (p_clcb != NULL) + bta_gattc_sm_execute(p_clcb, BTA_GATTC_INT_DISCOVER_EVT, NULL); + } + /* notify applicationf or service change */ + if (p_clrcb->p_cback != NULL) + { + (* p_clrcb->p_cback)(BTA_GATTC_SRVC_CHG_EVT, (tBTA_GATTC *)p_srcb->server_bda); + } + + } + + return processed; + +} +/******************************************************************************* +** +** Function bta_gattc_proc_other_indication +** +** Description process all non-service change indication/notification. +** +** Returns None. +** +*******************************************************************************/ +void bta_gattc_proc_other_indication(tBTA_GATTC_CLCB *p_clcb, UINT8 op, + tGATT_CL_COMPLETE *p_data, + tBTA_GATTC_NOTIFY *p_notify) +{ + APPL_TRACE_DEBUG("bta_gattc_proc_other_indication check \ + p_data->att_value.handle=%d p_data->handle=%d", + p_data->att_value.handle, p_data->handle); + APPL_TRACE_DEBUG("is_notify", p_notify->is_notify); + + p_notify->is_notify = (op == GATTC_OPTYPE_INDICATION) ? FALSE : TRUE; + p_notify->len = p_data->att_value.len; + bdcpy(p_notify->bda, p_clcb->bda); + memcpy(p_notify->value, p_data->att_value.value, p_data->att_value.len); + p_notify->conn_id = p_clcb->bta_conn_id; + + if (p_clcb->p_rcb->p_cback) + (*p_clcb->p_rcb->p_cback)(BTA_GATTC_NOTIF_EVT, (tBTA_GATTC *)p_notify); + +} +/******************************************************************************* +** +** Function bta_gattc_process_indicate +** +** Description process indication/notification. +** +** Returns None. +** +*******************************************************************************/ +void bta_gattc_process_indicate(UINT16 conn_id, tGATTC_OPTYPE op, tGATT_CL_COMPLETE *p_data) +{ + UINT16 handle = p_data->att_value.handle; + tBTA_GATTC_CLCB *p_clcb ; + tBTA_GATTC_RCB *p_clrcb = NULL; + tBTA_GATTC_SERV *p_srcb = NULL; + tBTA_GATTC_NOTIFY notify; + BD_ADDR remote_bda; + tBTA_GATTC_IF gatt_if; + tBTA_TRANSPORT transport; + + if (!GATT_GetConnectionInfor(conn_id, &gatt_if, remote_bda, &transport)) + { + APPL_TRACE_ERROR("%s indication/notif for unknown app", __func__); + if (op == GATTC_OPTYPE_INDICATION) + GATTC_SendHandleValueConfirm(conn_id, handle); + return; + } + + if ((p_clrcb = bta_gattc_cl_get_regcb(gatt_if)) == NULL) + { + APPL_TRACE_ERROR("%s indication/notif for unregistered app", __func__); + if (op == GATTC_OPTYPE_INDICATION) + GATTC_SendHandleValueConfirm(conn_id, handle); + return; + } + + if ((p_srcb = bta_gattc_find_srcb(remote_bda)) == NULL) + { + APPL_TRACE_ERROR("%s indication/notif for unknown device, ignore", __func__); + if (op == GATTC_OPTYPE_INDICATION) + GATTC_SendHandleValueConfirm(conn_id, handle); + return; + } + + p_clcb = bta_gattc_find_clcb_by_conn_id(conn_id); + + if (bta_gattc_handle2id(p_srcb, handle, + ¬ify.char_id.srvc_id, + ¬ify.char_id.char_id, + ¬ify.descr_type)) + { + /* if non-service change indication/notification, forward to application */ + if (!bta_gattc_process_srvc_chg_ind(conn_id, p_clrcb, p_srcb, p_clcb, ¬ify, handle)) + { + /* if app registered for the notification */ + if (bta_gattc_check_notif_registry(p_clrcb, p_srcb, ¬ify)) + { + /* connection not open yet */ + if (p_clcb == NULL) + { + if ((p_clcb = bta_gattc_clcb_alloc(gatt_if, remote_bda, transport)) != NULL) + { + p_clcb->bta_conn_id = conn_id; + p_clcb->transport = transport; + + bta_gattc_sm_execute(p_clcb, BTA_GATTC_INT_CONN_EVT, NULL); + } + else + { + APPL_TRACE_ERROR("No resources"); + } + } + + if (p_clcb != NULL) + bta_gattc_proc_other_indication(p_clcb, op, p_data, ¬ify); + } + /* no one intersted and need ack? */ + else if (op == GATTC_OPTYPE_INDICATION) + { + APPL_TRACE_DEBUG("%s no one interested, ack now", __func__); + GATTC_SendHandleValueConfirm(conn_id, handle); + } + } + } + else + { + APPL_TRACE_ERROR("%s Indi/Notif for Unknown handle[0x%04x], can not find in local cache.", + __func__, handle); + if (op == GATTC_OPTYPE_INDICATION) + GATTC_SendHandleValueConfirm(conn_id, handle); + } +} +/******************************************************************************* +** +** Function bta_gattc_cmpl_cback +** +** Description client operation complete callback register with BTE GATT. +** +** Returns None. +** +*******************************************************************************/ +static void bta_gattc_cmpl_cback(UINT16 conn_id, tGATTC_OPTYPE op, tGATT_STATUS status, + tGATT_CL_COMPLETE *p_data) +{ + tBTA_GATTC_CLCB *p_clcb; + APPL_TRACE_DEBUG("bta_gattc_cmpl_cback: conn_id = %d op = %d status = %d", + conn_id, op, status); + + /* notification and indication processed right away */ + if (op == GATTC_OPTYPE_NOTIFICATION || op == GATTC_OPTYPE_INDICATION) + { + bta_gattc_process_indicate(conn_id, op, p_data); + return; + } + /* for all other operation, not expected if w/o connection */ + else if ((p_clcb = bta_gattc_find_clcb_by_conn_id(conn_id)) == NULL) + { + APPL_TRACE_ERROR("bta_gattc_cmpl_cback unknown conn_id = %d, ignore data", conn_id); + return; + } + + /* if over BR_EDR, inform PM for mode change */ + if (p_clcb->transport == BTA_TRANSPORT_BR_EDR) + { + bta_sys_busy(BTA_ID_GATTC, BTA_ALL_APP_ID, p_clcb->bda); + bta_sys_idle(BTA_ID_GATTC, BTA_ALL_APP_ID, p_clcb->bda); + } + + bta_gattc_cmpl_sendmsg(conn_id, op, status, p_data); +} + +/******************************************************************************* +** +** Function bta_gattc_cmpl_sendmsg +** +** Description client operation complete send message +** +** Returns None. +** +*******************************************************************************/ +static void bta_gattc_cmpl_sendmsg(UINT16 conn_id, tGATTC_OPTYPE op, + tBTA_GATT_STATUS status, + tGATT_CL_COMPLETE *p_data) +{ + const UINT16 len = sizeof(tBTA_GATTC_OP_CMPL) + sizeof(tGATT_CL_COMPLETE); + tBTA_GATTC_OP_CMPL *p_buf = (tBTA_GATTC_OP_CMPL *) GKI_getbuf(len); + + if (p_buf != NULL) + { + memset(p_buf, 0, len); + p_buf->hdr.event = BTA_GATTC_OP_CMPL_EVT; + p_buf->hdr.layer_specific = conn_id; + p_buf->status = status; + p_buf->op_code = op; + + if (p_data != NULL) + { + p_buf->p_cmpl = (tGATT_CL_COMPLETE *)(p_buf + 1); + memcpy(p_buf->p_cmpl, p_data, sizeof(tGATT_CL_COMPLETE)); + } + + bta_sys_sendmsg(p_buf); + } +} + +/******************************************************************************* +** +** Function bta_gattc_cong_cback +** +** Description congestion callback for BTA GATT client. +** +** Returns void +** +********************************************************************************/ +static void bta_gattc_cong_cback (UINT16 conn_id, BOOLEAN congested) +{ + tBTA_GATTC_CLCB *p_clcb; + tBTA_GATTC cb_data; + + if ((p_clcb = bta_gattc_find_clcb_by_conn_id(conn_id)) != NULL) + { + if (p_clcb->p_rcb->p_cback) + { + cb_data.congest.conn_id = conn_id; + cb_data.congest.congested = congested; + + (*p_clcb->p_rcb->p_cback)(BTA_GATTC_CONGEST_EVT, &cb_data); + } + } +} + +#if BLE_INCLUDED == TRUE +/******************************************************************************* +** +** Function bta_gattc_init_clcb_conn +** +** Description Initaite a BTA CLCB connection +** +** Returns void +** +********************************************************************************/ +void bta_gattc_init_clcb_conn(UINT8 cif, BD_ADDR remote_bda) +{ + tBTA_GATTC_CLCB *p_clcb = NULL; + tBTA_GATTC_DATA gattc_data; + UINT16 conn_id; + + /* should always get the connection ID */ + if (GATT_GetConnIdIfConnected(cif, remote_bda, &conn_id, BTA_GATT_TRANSPORT_LE) == FALSE) + { + APPL_TRACE_ERROR("bta_gattc_init_clcb_conn ERROR: not a connected device"); + return; + } + + /* initaite a new connection here */ + if ((p_clcb = bta_gattc_clcb_alloc(cif, remote_bda, BTA_GATT_TRANSPORT_LE)) != NULL) + { + gattc_data.hdr.layer_specific = p_clcb->bta_conn_id = conn_id; + + gattc_data.api_conn.client_if = cif; + memcpy(gattc_data.api_conn.remote_bda, remote_bda, BD_ADDR_LEN); + gattc_data.api_conn.is_direct = TRUE; + + bta_gattc_sm_execute(p_clcb, BTA_GATTC_API_OPEN_EVT, &gattc_data); + } + else + { + APPL_TRACE_ERROR("No resources"); + } +} +/******************************************************************************* +** +** Function bta_gattc_process_listen_all +** +** Description process listen all, send open callback to application for all +** connected slave LE link. +** +** Returns void +** +********************************************************************************/ +void bta_gattc_process_listen_all(UINT8 cif) +{ + UINT8 i_conn = 0; + tBTA_GATTC_CONN *p_conn = &bta_gattc_cb.conn_track[0]; + + for (i_conn = 0; i_conn < BTA_GATTC_CONN_MAX; i_conn++, p_conn ++) + { + if (p_conn->in_use ) + { + if (bta_gattc_find_clcb_by_cif(cif, p_conn->remote_bda, BTA_GATT_TRANSPORT_LE) == NULL) + { + bta_gattc_init_clcb_conn(cif, p_conn->remote_bda); + } + /* else already connected */ + } + } +} +/******************************************************************************* +** +** Function bta_gattc_listen +** +** Description Start or stop a listen for connection +** +** Returns void +** +********************************************************************************/ +void bta_gattc_listen(tBTA_GATTC_CB *p_cb, tBTA_GATTC_DATA * p_msg) +{ + tBTA_GATTC_RCB *p_clreg = bta_gattc_cl_get_regcb(p_msg->api_listen.client_if); + tBTA_GATTC cb_data; + UNUSED(p_cb); + + cb_data.reg_oper.status = BTA_GATT_ERROR; + cb_data.reg_oper.client_if = p_msg->api_listen.client_if; + + if (p_clreg == NULL) + { + APPL_TRACE_ERROR("bta_gattc_listen failed, unknown client_if: %d", + p_msg->api_listen.client_if); + return; + } + /* mark bg conn record */ + if (bta_gattc_mark_bg_conn(p_msg->api_listen.client_if, + (BD_ADDR_PTR) p_msg->api_listen.remote_bda, + p_msg->api_listen.start, + TRUE)) + { + if (!GATT_Listen(p_msg->api_listen.client_if, + p_msg->api_listen.start, + p_msg->api_listen.remote_bda)) + { + APPL_TRACE_ERROR("Listen failure"); + (*p_clreg->p_cback)(BTA_GATTC_LISTEN_EVT, &cb_data); + } + else + { + cb_data.status = BTA_GATT_OK; + + (*p_clreg->p_cback)(BTA_GATTC_LISTEN_EVT, &cb_data); + + if (p_msg->api_listen.start) + { + /* if listen to a specific target */ + if (p_msg->api_listen.remote_bda != NULL) + { + + /* if is a connected remote device */ + if (L2CA_GetBleConnRole(p_msg->api_listen.remote_bda) == HCI_ROLE_SLAVE && + bta_gattc_find_clcb_by_cif(p_msg->api_listen.client_if, + p_msg->api_listen.remote_bda, + BTA_GATT_TRANSPORT_LE) == NULL) + { + + bta_gattc_init_clcb_conn(p_msg->api_listen.client_if, + p_msg->api_listen.remote_bda); + } + } + /* if listen to all */ + else + { + LOG_DEBUG("Listen For All now"); + /* go through all connected device and send + callback for all connected slave connection */ + bta_gattc_process_listen_all(p_msg->api_listen.client_if); + } + } + } + } +} + +/******************************************************************************* +** +** Function bta_gattc_broadcast +** +** Description Start or stop broadcasting +** +** Returns void +** +********************************************************************************/ +void bta_gattc_broadcast(tBTA_GATTC_CB *p_cb, tBTA_GATTC_DATA * p_msg) +{ + tBTA_GATTC_RCB *p_clreg = bta_gattc_cl_get_regcb(p_msg->api_listen.client_if); + tBTA_GATTC cb_data; + UNUSED(p_cb); + + cb_data.reg_oper.client_if = p_msg->api_listen.client_if; + cb_data.reg_oper.status = BTM_BleBroadcast(p_msg->api_listen.start); + + if (p_clreg && p_clreg->p_cback) + (*p_clreg->p_cback)(BTA_GATTC_LISTEN_EVT, &cb_data); +} +#endif +#endif diff --git a/components/bt/bluedroid/bta/gatt/bta_gattc_api.c b/components/bt/bluedroid/bta/gatt/bta_gattc_api.c new file mode 100755 index 0000000000..36e7b7d1a9 --- /dev/null +++ b/components/bt/bluedroid/bta/gatt/bta_gattc_api.c @@ -0,0 +1,1106 @@ +/****************************************************************************** + * + * Copyright (C) 2010-2012 Broadcom Corporation + * + * 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 is the implementation of the API for GATT module of BTA. + * + ******************************************************************************/ + +#include "bt_target.h" + +#if defined(BTA_GATT_INCLUDED) && (BTA_GATT_INCLUDED == TRUE) + +#include +#include "gki.h" +#include "bta_sys.h" +#include "bta_gatt_api.h" +#include "bta_gattc_int.h" + +/***************************************************************************** +** Constants +*****************************************************************************/ + +static const tBTA_SYS_REG bta_gattc_reg = +{ + bta_gattc_hdl_event, + BTA_GATTC_Disable +}; + + +/******************************************************************************* +** +** Function BTA_GATTC_Disable +** +** Description This function is called to disable GATTC module +** +** Parameters None. +** +** Returns None +** +*******************************************************************************/ +void BTA_GATTC_Disable(void) +{ + BT_HDR *p_buf; + + if (bta_sys_is_register(BTA_ID_GATTC) == FALSE) + { + APPL_TRACE_WARNING("GATTC Module not enabled/already disabled"); + return; + } + if ((p_buf = (BT_HDR *) GKI_getbuf(sizeof(BT_HDR))) != NULL) + { + p_buf->event = BTA_GATTC_API_DISABLE_EVT; + bta_sys_sendmsg(p_buf); + } + bta_sys_deregister(BTA_ID_GATTC); + +} + +/******************************************************************************* +** +** Function BTA_GATTC_AppRegister +** +** Description This function is called to register application callbacks +** with BTA GATTC module. +** +** Parameters p_app_uuid - applicaiton UUID +** p_client_cb - pointer to the application callback function. +** +** Returns None +** +*******************************************************************************/ +void BTA_GATTC_AppRegister(tBT_UUID *p_app_uuid, tBTA_GATTC_CBACK *p_client_cb) +{ + tBTA_GATTC_API_REG *p_buf; + + if (bta_sys_is_register(BTA_ID_GATTC) == FALSE) + { + bta_sys_register(BTA_ID_GATTC, &bta_gattc_reg); + } + + if ((p_buf = (tBTA_GATTC_API_REG *) GKI_getbuf(sizeof(tBTA_GATTC_API_REG))) != NULL) + { + p_buf->hdr.event = BTA_GATTC_API_REG_EVT; + if (p_app_uuid != NULL) + memcpy(&p_buf->app_uuid, p_app_uuid, sizeof(tBT_UUID)); + p_buf->p_cback = p_client_cb; + + bta_sys_sendmsg(p_buf); + } + return; +} + +/******************************************************************************* +** +** Function BTA_GATTC_AppDeregister +** +** Description This function is called to deregister an application +** from BTA GATTC module. +** +** Parameters client_if - client interface identifier. +** +** Returns None +** +*******************************************************************************/ +void BTA_GATTC_AppDeregister(tBTA_GATTC_IF client_if) +{ + tBTA_GATTC_API_DEREG *p_buf; + + if ((p_buf = (tBTA_GATTC_API_DEREG *) GKI_getbuf(sizeof(tBTA_GATTC_API_DEREG))) != NULL) + { + p_buf->hdr.event = BTA_GATTC_API_DEREG_EVT; + p_buf->client_if = client_if; + bta_sys_sendmsg(p_buf); + } + return; +} + +/******************************************************************************* +** +** Function BTA_GATTC_Open +** +** Description Open a direct connection or add a background auto connection +** bd address +** +** Parameters client_if: server interface. +** remote_bda: remote device BD address. +** is_direct: direct connection or background auto connection +** transport: Transport to be used for GATT connection (BREDR/LE) +** +** Returns void +** +*******************************************************************************/ +void BTA_GATTC_Open(tBTA_GATTC_IF client_if, BD_ADDR remote_bda, + BOOLEAN is_direct, tBTA_GATT_TRANSPORT transport) +{ + tBTA_GATTC_API_OPEN *p_buf; + + if ((p_buf = (tBTA_GATTC_API_OPEN *) GKI_getbuf(sizeof(tBTA_GATTC_API_OPEN))) != NULL) + { + p_buf->hdr.event = BTA_GATTC_API_OPEN_EVT; + + p_buf->client_if = client_if; + p_buf->is_direct = is_direct; + p_buf->transport = transport; + memcpy(p_buf->remote_bda, remote_bda, BD_ADDR_LEN); + + + bta_sys_sendmsg(p_buf); + } + return; +} + +/******************************************************************************* +** +** Function BTA_GATTC_CancelOpen +** +** Description Cancel a direct open connection or remove a background auto connection +** bd address +** +** Parameters client_if: server interface. +** remote_bda: remote device BD address. +** is_direct: direct connection or background auto connection +** +** Returns void +** +*******************************************************************************/ +void BTA_GATTC_CancelOpen(tBTA_GATTC_IF client_if, BD_ADDR remote_bda, BOOLEAN is_direct) +{ + tBTA_GATTC_API_CANCEL_OPEN *p_buf; + + if ((p_buf = (tBTA_GATTC_API_CANCEL_OPEN *) GKI_getbuf(sizeof(tBTA_GATTC_API_CANCEL_OPEN))) != NULL) + { + p_buf->hdr.event = BTA_GATTC_API_CANCEL_OPEN_EVT; + + p_buf->client_if = client_if; + p_buf->is_direct = is_direct; + memcpy(p_buf->remote_bda, remote_bda, BD_ADDR_LEN); + + bta_sys_sendmsg(p_buf); + } + return; +} + +/******************************************************************************* +** +** Function BTA_GATTC_Close +** +** Description Close a connection to a GATT server. +** +** Parameters conn_id: connectino ID to be closed. +** +** Returns void +** +*******************************************************************************/ +void BTA_GATTC_Close(UINT16 conn_id) +{ + BT_HDR *p_buf; + + if ((p_buf = (BT_HDR *) GKI_getbuf(sizeof(BT_HDR))) != NULL) + { + p_buf->event = BTA_GATTC_API_CLOSE_EVT; + + p_buf->layer_specific = conn_id; + + bta_sys_sendmsg(p_buf); + } + return; + +} +/******************************************************************************* +** +** Function BTA_GATTC_ConfigureMTU +** +** Description Configure the MTU size in the GATT channel. This can be done +** only once per connection. +** +** Parameters conn_id: connection ID. +** mtu: desired MTU size to use. +** +** Returns void +** +*******************************************************************************/ +void BTA_GATTC_ConfigureMTU (UINT16 conn_id, UINT16 mtu) +{ + tBTA_GATTC_API_CFG_MTU *p_buf; + + if ((p_buf = (tBTA_GATTC_API_CFG_MTU *) GKI_getbuf(sizeof(tBTA_GATTC_API_CFG_MTU))) != NULL) + { + p_buf->hdr.event = BTA_GATTC_API_CFG_MTU_EVT; + p_buf->hdr.layer_specific = conn_id; + + p_buf->mtu = mtu; + + bta_sys_sendmsg(p_buf); + } + return; +} +/******************************************************************************* +** +** Function BTA_GATTC_ServiceSearchRequest +** +** Description This function is called to request a GATT service discovery +** on a GATT server. This function report service search result +** by a callback event, and followed by a service search complete +** event. +** +** Parameters conn_id: connection ID. +** p_srvc_uuid: a UUID of the service application is interested in. +** If Null, discover for all services. +** +** Returns None +** +*******************************************************************************/ +void BTA_GATTC_ServiceSearchRequest (UINT16 conn_id, tBT_UUID *p_srvc_uuid) +{ + tBTA_GATTC_API_SEARCH *p_buf; + UINT16 len = sizeof(tBTA_GATTC_API_SEARCH) + sizeof(tBT_UUID); + + if ((p_buf = (tBTA_GATTC_API_SEARCH *) GKI_getbuf(len)) != NULL) + { + memset(p_buf, 0, len); + + p_buf->hdr.event = BTA_GATTC_API_SEARCH_EVT; + p_buf->hdr.layer_specific = conn_id; + + if (p_srvc_uuid) + { + p_buf->p_srvc_uuid = (tBT_UUID *)(p_buf + 1); + memcpy(p_buf->p_srvc_uuid, p_srvc_uuid, sizeof(tBT_UUID)); + } + else + p_buf->p_srvc_uuid = NULL; + + bta_sys_sendmsg(p_buf); + } + return; +} + + +/******************************************************************************* +** +** Function BTA_GATTC_GetFirstChar +** +** Description This function is called to find the first characteristic of the +** service on the given server. +** +** Parameters conn_id: connection ID which identify the server. +** p_srvc_id: the service ID of which the characteristic is belonged to. +** p_char_uuid_cond: Characteristic UUID, if NULL find the first available +** characteristic. +** p_char_result: output parameter which will store the GATT +** characteristic ID. +** p_property: output parameter to carry the characteristic property. +** +** Returns returns status. +** +*******************************************************************************/ +tBTA_GATT_STATUS BTA_GATTC_GetFirstChar (UINT16 conn_id, tBTA_GATT_SRVC_ID *p_srvc_id, + tBT_UUID *p_char_uuid_cond, + tBTA_GATTC_CHAR_ID *p_char_result, + tBTA_GATT_CHAR_PROP *p_property) +{ + tBTA_GATT_STATUS status; + + if (!p_srvc_id || !p_char_result) + return BTA_GATT_ILLEGAL_PARAMETER; + + if ((status = bta_gattc_query_cache(conn_id, BTA_GATTC_ATTR_TYPE_CHAR, p_srvc_id, NULL, + p_char_uuid_cond, &p_char_result->char_id, (void *)p_property)) + == BTA_GATT_OK) + { + memcpy(&p_char_result->srvc_id, p_srvc_id, sizeof(tBTA_GATT_SRVC_ID)); + } + + return status; + +} +/******************************************************************************* +** +** Function BTA_GATTC_GetNextChar +** +** Description This function is called to find the next characteristic of the +** service on the given server. +** +** Parameters conn_id: connection ID which identify the server. +** p_start_char_id: start the characteristic search from the next record +** after the one identified by char_id. +** p_char_uuid_cond: Characteristic UUID, if NULL find the first available +** characteristic. +** p_char_result: output parameter which will store the GATT +** characteristic ID. +** p_property: output parameter to carry the characteristic property. +** +** Returns returns status. +** +*******************************************************************************/ +tBTA_GATT_STATUS BTA_GATTC_GetNextChar (UINT16 conn_id, + tBTA_GATTC_CHAR_ID *p_start_char_id, + tBT_UUID *p_char_uuid_cond, + tBTA_GATTC_CHAR_ID *p_char_result, + tBTA_GATT_CHAR_PROP *p_property) +{ + tBTA_GATT_STATUS status; + + if (!p_start_char_id || !p_char_result) + return BTA_GATT_ILLEGAL_PARAMETER; + + if ((status = bta_gattc_query_cache(conn_id, BTA_GATTC_ATTR_TYPE_CHAR, + &p_start_char_id->srvc_id, + &p_start_char_id->char_id, + p_char_uuid_cond, + &p_char_result->char_id, + (void *) p_property)) + == BTA_GATT_OK) + { + memcpy(&p_char_result->srvc_id, &p_start_char_id->srvc_id, sizeof(tBTA_GATT_SRVC_ID)); + } + + return status; +} + +/******************************************************************************* +** +** Function BTA_GATTC_GetFirstCharDescr +** +** Description This function is called to find the first characteristic descriptor of the +** characteristic on the given server. +** +** Parameters conn_id: connection ID which identify the server. +** p_char_id: the characteristic ID of which the descriptor is belonged to. +** p_descr_uuid_cond: Characteristic Descr UUID, if NULL find the first available +** characteristic. +** p_descr_result: output parameter which will store the GATT +** characteristic descriptor ID. +** +** Returns returns status. +** +*******************************************************************************/ +tBTA_GATT_STATUS BTA_GATTC_GetFirstCharDescr (UINT16 conn_id, tBTA_GATTC_CHAR_ID *p_char_id, + tBT_UUID *p_descr_uuid_cond, + tBTA_GATTC_CHAR_DESCR_ID *p_descr_result) +{ + tBTA_GATT_STATUS status; + + if (!p_char_id || !p_descr_result) + return BTA_GATT_ILLEGAL_PARAMETER; + + memset(p_descr_result, 0, sizeof(tBTA_GATTC_CHAR_DESCR_ID)); + + if ((status = bta_gattc_query_cache(conn_id, + BTA_GATTC_ATTR_TYPE_CHAR_DESCR, + &p_char_id->srvc_id, + &p_char_id->char_id, + p_descr_uuid_cond, + &p_descr_result->char_id.char_id, + NULL)) + == BTA_GATT_OK) + { + memcpy(&p_descr_result->descr_id, &p_descr_result->char_id.char_id, sizeof(tBTA_GATT_ID)); + memcpy(&p_descr_result->char_id, p_char_id, sizeof(tBTA_GATTC_CHAR_ID)); + } + return status; + +} +/******************************************************************************* +** +** Function BTA_GATTC_GetNextCharDescr +** +** Description This function is called to find the next characteristic descriptor +** of the characterisctic. +** +** Parameters conn_id: connection ID which identify the server. +** p_start_descr_id: start the descriptor search from the next record +** after the one identified by p_start_descr_id. +** p_descr_uuid_cond: Characteristic descriptor UUID, if NULL find +** the first available characteristic descriptor. +** p_descr_result: output parameter which will store the GATT +** characteristic descriptor ID. +** +** Returns returns status. +** +*******************************************************************************/ +tBTA_GATT_STATUS BTA_GATTC_GetNextCharDescr (UINT16 conn_id, + tBTA_GATTC_CHAR_DESCR_ID *p_start_descr_id, + tBT_UUID *p_descr_uuid_cond, + tBTA_GATTC_CHAR_DESCR_ID *p_descr_result) +{ + tBTA_GATT_STATUS status; + + if (!p_start_descr_id || !p_descr_result) + return BTA_GATT_ILLEGAL_PARAMETER; + + memset(p_descr_result, 0, sizeof(tBTA_GATTC_CHAR_DESCR_ID)); + + if ((status = bta_gattc_query_cache(conn_id, BTA_GATTC_ATTR_TYPE_CHAR_DESCR, + &p_start_descr_id->char_id.srvc_id, + &p_start_descr_id->char_id.char_id, + p_descr_uuid_cond, + &p_descr_result->char_id.char_id, + (void *)&p_start_descr_id->descr_id)) + == BTA_GATT_OK) + { + memcpy(&p_descr_result->descr_id, &p_descr_result->char_id.char_id, sizeof(tBTA_GATT_ID)); + memcpy(&p_descr_result->char_id, p_start_descr_id, sizeof(tBTA_GATTC_CHAR_ID)); + } + + return status; +} + + +/******************************************************************************* +** +** Function BTA_GATTC_GetFirstIncludedService +** +** Description This function is called to find the first included service of the +** service on the given server. +** +** Parameters conn_id: connection ID which identify the server. +** p_srvc_id: the service ID of which the characteristic is belonged to. +** p_uuid_cond: Characteristic UUID, if NULL find the first available +** characteristic. +** p_result: output parameter which will store the GATT ID +** of the included service found. +** +** Returns returns status. +** +*******************************************************************************/ +tBTA_GATT_STATUS BTA_GATTC_GetFirstIncludedService(UINT16 conn_id, tBTA_GATT_SRVC_ID *p_srvc_id, + tBT_UUID *p_uuid_cond, tBTA_GATTC_INCL_SVC_ID *p_result) +{ + tBTA_GATT_STATUS status; + + if (!p_srvc_id || !p_result) + return BTA_GATT_ILLEGAL_PARAMETER; + + if ((status = bta_gattc_query_cache(conn_id, + BTA_GATTC_ATTR_TYPE_INCL_SRVC, + p_srvc_id, + NULL, + p_uuid_cond, + &p_result->incl_svc_id.id, + (void *)&p_result->incl_svc_id.is_primary)) + == BTA_GATT_OK) + { + memcpy(&p_result->srvc_id, p_srvc_id, sizeof(tBTA_GATT_SRVC_ID)); + } + + return status; +} +/******************************************************************************* +** +** Function BTA_GATTC_GetNextIncludedService +** +** Description This function is called to find the next included service of the +** service on the given server. +** +** Parameters conn_id: connection ID which identify the server. +** p_start_id: start the search from the next record +** after the one identified by p_start_id. +** p_uuid_cond: Included service UUID, if NULL find the first available +** included service. +** p_result: output parameter which will store the GATT ID +** of the included service found. +** +** Returns returns status. +** +*******************************************************************************/ +tBTA_GATT_STATUS BTA_GATTC_GetNextIncludedService(UINT16 conn_id, + tBTA_GATTC_INCL_SVC_ID *p_start_id, + tBT_UUID *p_uuid_cond, + tBTA_GATTC_INCL_SVC_ID *p_result) +{ + tBTA_GATT_STATUS status; + + if (!p_start_id || !p_result) + return BTA_GATT_ILLEGAL_PARAMETER; + + if ((status = bta_gattc_query_cache(conn_id, + BTA_GATTC_ATTR_TYPE_INCL_SRVC, + &p_start_id->srvc_id, + &p_start_id->incl_svc_id.id, + p_uuid_cond, + &p_result->incl_svc_id.id, + (void *)&p_result->incl_svc_id.is_primary)) + == BTA_GATT_OK) + { + memcpy(&p_result->srvc_id, &p_start_id->srvc_id, sizeof(tBTA_GATT_SRVC_ID)); + } + + return status; +} + +/******************************************************************************* +** +** Function BTA_GATTC_ReadCharacteristic +** +** Description This function is called to read a service's characteristics of +** the given characteritisc ID. +** +** Parameters conn_id - connectino ID. +** p_char_id - characteritic ID to read. +** +** Returns None +** +*******************************************************************************/ +void BTA_GATTC_ReadCharacteristic(UINT16 conn_id, tBTA_GATTC_CHAR_ID *p_char_id, + tBTA_GATT_AUTH_REQ auth_req) +{ + tBTA_GATTC_API_READ *p_buf; + + if ((p_buf = (tBTA_GATTC_API_READ *) GKI_getbuf(sizeof(tBTA_GATTC_API_READ))) != NULL) + { + memset(p_buf, 0, sizeof(tBTA_GATTC_API_READ)); + + p_buf->hdr.event = BTA_GATTC_API_READ_EVT; + p_buf->hdr.layer_specific = conn_id; + p_buf->auth_req = auth_req; + + memcpy(&p_buf->srvc_id, &p_char_id->srvc_id, sizeof(tBTA_GATT_SRVC_ID)); + memcpy(&p_buf->char_id, &p_char_id->char_id, sizeof(tBTA_GATT_ID)); + p_buf->p_descr_type = NULL; + + bta_sys_sendmsg(p_buf); + } + return; +} + +/******************************************************************************* +** +** Function BTA_GATTC_ReadCharDescr +** +** Description This function is called to read a characteristics descriptor. +** +** Parameters conn_id - connection ID. +** p_char_descr_id - characteritic descriptor ID to read. +** +** Returns None +** +*******************************************************************************/ +void BTA_GATTC_ReadCharDescr (UINT16 conn_id, + tBTA_GATTC_CHAR_DESCR_ID *p_descr_id, + tBTA_GATT_AUTH_REQ auth_req) +{ + tBTA_GATTC_API_READ *p_buf; + UINT16 len = (UINT16)(sizeof(tBTA_GATT_ID) + sizeof(tBTA_GATTC_API_READ)); + + if ((p_buf = (tBTA_GATTC_API_READ *) GKI_getbuf(len)) != NULL) + { + memset(p_buf, 0, sizeof(tBTA_GATTC_API_READ)); + + p_buf->hdr.event = BTA_GATTC_API_READ_EVT; + p_buf->hdr.layer_specific = conn_id; + p_buf->auth_req = auth_req; + + memcpy(&p_buf->srvc_id, &p_descr_id->char_id.srvc_id, sizeof(tBTA_GATT_SRVC_ID)); + memcpy(&p_buf->char_id, &p_descr_id->char_id.char_id, sizeof(tBTA_GATT_ID)); + p_buf->p_descr_type = (tBTA_GATT_ID *)(p_buf + 1); + + memcpy(p_buf->p_descr_type, &p_descr_id->descr_id, sizeof(tBTA_GATT_ID)); + + bta_sys_sendmsg(p_buf); + } + return; + +} +/******************************************************************************* +** +** Function BTA_GATTC_ReadMultiple +** +** Description This function is called to read multiple characteristic or +** characteristic descriptors. +** +** Parameters conn_id - connectino ID. +** p_read_multi - pointer to the read multiple parameter. +** +** Returns None +** +*******************************************************************************/ +void BTA_GATTC_ReadMultiple(UINT16 conn_id, tBTA_GATTC_MULTI *p_read_multi, + tBTA_GATT_AUTH_REQ auth_req) +{ + tBTA_GATTC_API_READ_MULTI *p_buf; + tBTA_GATTC_ATTR_ID *p_value; + UINT16 len = (UINT16)(sizeof(tBTA_GATTC_API_READ_MULTI) + + p_read_multi->num_attr * sizeof(tBTA_GATTC_ATTR_ID)); + UINT8 i; + + if ((p_buf = (tBTA_GATTC_API_READ_MULTI *) GKI_getbuf(len)) != NULL) + { + memset(p_buf, 0, len); + + p_buf->hdr.event = BTA_GATTC_API_READ_MULTI_EVT; + p_buf->hdr.layer_specific = conn_id; + p_buf->auth_req = auth_req; + + p_buf->num_attr = p_read_multi->num_attr; + + if (p_buf->num_attr > 0) + { + p_buf->p_id_list = p_value = (tBTA_GATTC_ATTR_ID *)(p_buf + 1); + + for (i = 0; i < p_buf->num_attr; i ++, p_value ++) + { + memcpy(p_value, &p_read_multi->id_list[i], sizeof(tBTA_GATTC_ATTR_ID)); + } + } + bta_sys_sendmsg(p_buf); + } + return; +} + + +/******************************************************************************* +** +** Function BTA_GATTC_WriteCharValue +** +** Description This function is called to write characteristic value. +** +** Parameters conn_id - connection ID. +** p_char_id - characteristic ID to write. +** write_type - type of write. +** len: length of the data to be written. +** p_value - the value to be written. +** +** Returns None +** +*******************************************************************************/ +void BTA_GATTC_WriteCharValue ( UINT16 conn_id, + tBTA_GATTC_CHAR_ID *p_char_id, + tBTA_GATTC_WRITE_TYPE write_type, + UINT16 len, + UINT8 *p_value, + tBTA_GATT_AUTH_REQ auth_req) +{ + tBTA_GATTC_API_WRITE *p_buf; + + if ((p_buf = (tBTA_GATTC_API_WRITE *) GKI_getbuf((UINT16)(sizeof(tBTA_GATTC_API_WRITE) + len))) != NULL) + { + memset(p_buf, 0, sizeof(tBTA_GATTC_API_WRITE) + len); + + p_buf->hdr.event = BTA_GATTC_API_WRITE_EVT; + p_buf->hdr.layer_specific = conn_id; + p_buf->auth_req = auth_req; + + memcpy(&p_buf->srvc_id, &p_char_id->srvc_id, sizeof(tBTA_GATT_SRVC_ID)); + memcpy(&p_buf->char_id, &p_char_id->char_id, sizeof(tBTA_GATT_ID)); + + p_buf->write_type = write_type; + p_buf->len = len; + + if (p_value && len > 0) + { + p_buf->p_value = (UINT8 *)(p_buf + 1); + memcpy(p_buf->p_value, p_value, len); + } + + bta_sys_sendmsg(p_buf); + } + return; +} +/******************************************************************************* +** +** Function BTA_GATTC_WriteCharDescr +** +** Description This function is called to write characteristic descriptor value. +** +** Parameters conn_id - connection ID +** p_char_descr_id - characteristic descriptor ID to write. +** write_type - write type. +** p_value - the value to be written. +** +** Returns None +** +*******************************************************************************/ +void BTA_GATTC_WriteCharDescr (UINT16 conn_id, + tBTA_GATTC_CHAR_DESCR_ID *p_char_descr_id, + tBTA_GATTC_WRITE_TYPE write_type, + tBTA_GATT_UNFMT *p_data, + tBTA_GATT_AUTH_REQ auth_req) +{ + tBTA_GATTC_API_WRITE *p_buf; + UINT16 len = sizeof(tBTA_GATTC_API_WRITE) + sizeof(tBTA_GATT_ID); + + if (p_data != NULL) + len += p_data->len; + + if ((p_buf = (tBTA_GATTC_API_WRITE *) GKI_getbuf(len)) != NULL) + { + memset(p_buf, 0, len); + + p_buf->hdr.event = BTA_GATTC_API_WRITE_EVT; + p_buf->hdr.layer_specific = conn_id; + p_buf->auth_req = auth_req; + + memcpy(&p_buf->srvc_id, &p_char_descr_id->char_id.srvc_id, sizeof(tBTA_GATT_SRVC_ID)); + memcpy(&p_buf->char_id, &p_char_descr_id->char_id.char_id, sizeof(tBTA_GATT_ID)); + p_buf->p_descr_type = (tBTA_GATT_ID *)(p_buf + 1); + memcpy(p_buf->p_descr_type, &p_char_descr_id->descr_id, sizeof(tBTA_GATT_ID)); + p_buf->write_type = write_type; + + if (p_data && p_data->len != 0) + { + p_buf->p_value = (UINT8 *)(p_buf->p_descr_type + 1); + p_buf->len = p_data->len; + /* pack the descr data */ + memcpy(p_buf->p_value, p_data->p_value, p_data->len); + } + + bta_sys_sendmsg(p_buf); + } + return; + +} +/******************************************************************************* +** +** Function BTA_GATTC_PrepareWrite +** +** Description This function is called to prepare write a characteristic value. +** +** Parameters conn_id - connection ID. +** p_char_id - GATT characteritic ID of the service. +** offset - offset of the write value. +** len: length of the data to be written. +** p_value - the value to be written. +** +** Returns None +** +*******************************************************************************/ +void BTA_GATTC_PrepareWrite (UINT16 conn_id, tBTA_GATTC_CHAR_ID *p_char_id, + UINT16 offset, UINT16 len, UINT8 *p_value, + tBTA_GATT_AUTH_REQ auth_req) +{ + tBTA_GATTC_API_WRITE *p_buf; + + if ((p_buf = (tBTA_GATTC_API_WRITE *) GKI_getbuf((UINT16)(sizeof(tBTA_GATTC_API_WRITE) + len))) != NULL) + { + memset(p_buf, 0, sizeof(tBTA_GATTC_API_WRITE) + len); + + p_buf->hdr.event = BTA_GATTC_API_WRITE_EVT; + p_buf->hdr.layer_specific = conn_id; + p_buf->auth_req = auth_req; + + memcpy(&p_buf->srvc_id, &p_char_id->srvc_id, sizeof(tBTA_GATT_SRVC_ID)); + memcpy(&p_buf->char_id, &p_char_id->char_id, sizeof(tBTA_GATT_ID)); + + p_buf->write_type = BTA_GATTC_WRITE_PREPARE; + p_buf->offset = offset; + p_buf->len = len; + + if (p_value && len > 0) + { + p_buf->p_value = (UINT8 *)(p_buf + 1); + memcpy(p_buf->p_value, p_value, len); + } + + bta_sys_sendmsg(p_buf); + } + return; + +} +/******************************************************************************* +** +** Function BTA_GATTC_ExecuteWrite +** +** Description This function is called to execute write a prepare write sequence. +** +** Parameters conn_id - connection ID. +** is_execute - execute or cancel. +** +** Returns None +** +*******************************************************************************/ +void BTA_GATTC_ExecuteWrite (UINT16 conn_id, BOOLEAN is_execute) +{ + tBTA_GATTC_API_EXEC *p_buf; + + if ((p_buf = (tBTA_GATTC_API_EXEC *) GKI_getbuf((UINT16)sizeof(tBTA_GATTC_API_EXEC))) != NULL) + { + memset(p_buf, 0, sizeof(tBTA_GATTC_API_EXEC)); + + p_buf->hdr.event = BTA_GATTC_API_EXEC_EVT; + p_buf->hdr.layer_specific = conn_id; + + p_buf->is_execute = is_execute; + + bta_sys_sendmsg(p_buf); + } + return; + +} +/******************************************************************************* +** +** Function BTA_GATTC_SendIndConfirm +** +** Description This function is called to send handle value confirmation. +** +** Parameters conn_id - connection ID. +** p_char_id - characteristic ID to confirm. +** +** Returns None +** +*******************************************************************************/ +void BTA_GATTC_SendIndConfirm (UINT16 conn_id, tBTA_GATTC_CHAR_ID *p_char_id) +{ + tBTA_GATTC_API_CONFIRM *p_buf; + + APPL_TRACE_API("BTA_GATTC_SendIndConfirm conn_id=%d service uuid1=0x%x char uuid=0x%x", + conn_id, p_char_id->srvc_id.id.uuid.uu.uuid16, p_char_id->char_id.uuid.uu.uuid16); + + if ((p_buf = (tBTA_GATTC_API_CONFIRM *) GKI_getbuf(sizeof(tBTA_GATTC_API_CONFIRM))) != NULL) + { + memset(p_buf, 0, sizeof(tBTA_GATTC_API_CONFIRM)); + + p_buf->hdr.event = BTA_GATTC_API_CONFIRM_EVT; + p_buf->hdr.layer_specific = conn_id; + + memcpy(&p_buf->srvc_id, &p_char_id->srvc_id, sizeof(tBTA_GATT_SRVC_ID)); + memcpy(&p_buf->char_id, &p_char_id->char_id, sizeof(tBTA_GATT_ID)); + + bta_sys_sendmsg(p_buf); + } + return; + +} + +/******************************************************************************* +** +** Function BTA_GATTC_RegisterForNotifications +** +** Description This function is called to register for notification of a service. +** +** Parameters client_if - client interface. +** bda - target GATT server. +** p_char_id - pointer to GATT characteristic ID. +** +** Returns OK if registration succeed, otherwise failed. +** +*******************************************************************************/ +tBTA_GATT_STATUS BTA_GATTC_RegisterForNotifications (tBTA_GATTC_IF client_if, + BD_ADDR bda, + tBTA_GATTC_CHAR_ID *p_char_id) +{ + tBTA_GATTC_RCB *p_clreg; + tBTA_GATT_STATUS status = BTA_GATT_ILLEGAL_PARAMETER; + UINT8 i; + + if (!p_char_id) + { + APPL_TRACE_ERROR("deregistration failed, unknow char id"); + return status; + } + + if ((p_clreg = bta_gattc_cl_get_regcb(client_if)) != NULL) + { + for (i = 0; i < BTA_GATTC_NOTIF_REG_MAX; i ++) + { + if ( p_clreg->notif_reg[i].in_use && + !memcmp(p_clreg->notif_reg[i].remote_bda, bda, BD_ADDR_LEN) && + bta_gattc_charid_compare(&p_clreg->notif_reg[i].char_id, p_char_id)) + { + APPL_TRACE_WARNING("notification already registered"); + status = BTA_GATT_OK; + break; + } + } + if (status != BTA_GATT_OK) + { + for (i = 0; i < BTA_GATTC_NOTIF_REG_MAX; i ++) + { + if (!p_clreg->notif_reg[i].in_use) + { + memset((void *)&p_clreg->notif_reg[i], 0, sizeof(tBTA_GATTC_NOTIF_REG)); + + p_clreg->notif_reg[i].in_use = TRUE; + memcpy(p_clreg->notif_reg[i].remote_bda, bda, BD_ADDR_LEN); + + p_clreg->notif_reg[i].char_id.srvc_id.is_primary = p_char_id->srvc_id.is_primary; + bta_gattc_cpygattid(&p_clreg->notif_reg[i].char_id.srvc_id.id, &p_char_id->srvc_id.id); + bta_gattc_cpygattid(&p_clreg->notif_reg[i].char_id.char_id, &p_char_id->char_id); + + status = BTA_GATT_OK; + break; + } + } + if (i == BTA_GATTC_NOTIF_REG_MAX) + { + status = BTA_GATT_NO_RESOURCES; + APPL_TRACE_ERROR("Max Notification Reached, registration failed."); + } + } + } + else + { + APPL_TRACE_ERROR("Client_if: %d Not Registered", client_if); + } + + return status; +} + +/******************************************************************************* +** +** Function BTA_GATTC_DeregisterForNotifications +** +** Description This function is called to de-register for notification of a service. +** +** Parameters client_if - client interface. +** bda - target GATT server. +** p_char_id - pointer to GATT characteristic ID. +** +** Returns OK if deregistration succeed, otherwise failed. +** +*******************************************************************************/ +tBTA_GATT_STATUS BTA_GATTC_DeregisterForNotifications (tBTA_GATTC_IF client_if, + BD_ADDR bda, + tBTA_GATTC_CHAR_ID *p_char_id) +{ + tBTA_GATTC_RCB *p_clreg; + tBTA_GATT_STATUS status = BTA_GATT_ILLEGAL_PARAMETER; + UINT8 i; + + if (!p_char_id) + { + APPL_TRACE_ERROR("%s deregistration failed, unknown char id", __func__); + return status; + } + + if ((p_clreg = bta_gattc_cl_get_regcb(client_if)) != NULL) + { + for (i = 0; i < BTA_GATTC_NOTIF_REG_MAX; i ++) + { + if (p_clreg->notif_reg[i].in_use && + !memcmp(p_clreg->notif_reg[i].remote_bda, bda, BD_ADDR_LEN) && + bta_gattc_charid_compare(&p_clreg->notif_reg[i].char_id, p_char_id)) + { + APPL_TRACE_DEBUG("%s deregistered bd_addr:%02x:%02x:%02x:%02x:%02x:%02x", + __func__, bda[0], bda[1], bda[2], bda[3], bda[4], bda[5]); + memset(&p_clreg->notif_reg[i], 0, sizeof(tBTA_GATTC_NOTIF_REG)); + status = BTA_GATT_OK; + break; + } + } + if (i == BTA_GATTC_NOTIF_REG_MAX) + { + status = BTA_GATT_ERROR; + APPL_TRACE_ERROR("%s registration not found bd_addr:%02x:%02x:%02x:%02x:%02x:%02x", + __func__, bda[0], bda[1], bda[2], bda[3], bda[4], bda[5]); + } + } + else + { + APPL_TRACE_ERROR("%s client_if: %d not registered bd_addr:%02x:%02x:%02x:%02x:%02x:%02x", + __func__, client_if, bda[0], bda[1], bda[2], bda[3], bda[4], bda[5]); + } + + return status; +} + +/******************************************************************************* +** +** Function BTA_GATTC_Refresh +** +** Description Refresh the server cache of the remote device +** +** Parameters remote_bda: remote device BD address. +** +** Returns void +** +*******************************************************************************/ +void BTA_GATTC_Refresh(BD_ADDR remote_bda) +{ + tBTA_GATTC_API_OPEN *p_buf; + + if ((p_buf = (tBTA_GATTC_API_OPEN *) GKI_getbuf(sizeof(tBTA_GATTC_API_OPEN))) != NULL) + { + p_buf->hdr.event = BTA_GATTC_API_REFRESH_EVT; + + memcpy(p_buf->remote_bda, remote_bda, BD_ADDR_LEN); + + + bta_sys_sendmsg(p_buf); + } + return; +} + +/******************************************************************************* +** +** Function BTA_GATTC_Listen +** +** Description Start advertisement to listen for connection request for a GATT +** client application. +** +** Parameters client_if: server interface. +** start: to start or stop listening for connection +** remote_bda: remote device BD address, if listen to all device +** use NULL. +** +** Returns void +** +*******************************************************************************/ +void BTA_GATTC_Listen(tBTA_GATTC_IF client_if, BOOLEAN start, BD_ADDR_PTR target_bda) +{ + tBTA_GATTC_API_LISTEN *p_buf; + + if ((p_buf = (tBTA_GATTC_API_LISTEN *) GKI_getbuf((UINT16)(sizeof(tBTA_GATTC_API_LISTEN) + BD_ADDR_LEN))) != NULL) + { + p_buf->hdr.event = BTA_GATTC_API_LISTEN_EVT; + + p_buf->client_if = client_if; + p_buf->start = start; + if (target_bda) + { + p_buf->remote_bda = (UINT8*)(p_buf + 1); + memcpy(p_buf->remote_bda, target_bda, BD_ADDR_LEN); + } + else + p_buf->remote_bda = NULL; + + bta_sys_sendmsg(p_buf); + } + return; +} + +/******************************************************************************* +** +** Function BTA_GATTC_Broadcast +** +** Description Start broadcasting (non-connectable advertisements) +** +** Parameters client_if: client interface. +** start: to start or stop listening for connection +** +** Returns void +** +*******************************************************************************/ +void BTA_GATTC_Broadcast(tBTA_GATTC_IF client_if, BOOLEAN start) +{ + tBTA_GATTC_API_LISTEN *p_buf; + + if ((p_buf = (tBTA_GATTC_API_LISTEN *) GKI_getbuf((UINT16)(sizeof(tBTA_GATTC_API_LISTEN) + BD_ADDR_LEN))) != NULL) + { + p_buf->hdr.event = BTA_GATTC_API_BROADCAST_EVT; + p_buf->client_if = client_if; + p_buf->start = start; + bta_sys_sendmsg(p_buf); + } + return; +} + +#endif /* BTA_GATT_INCLUDED */ + diff --git a/components/bt/bluedroid/bta/gatt/bta_gattc_cache.c b/components/bt/bluedroid/bta/gatt/bta_gattc_cache.c new file mode 100755 index 0000000000..ed5c531f97 --- /dev/null +++ b/components/bt/bluedroid/bta/gatt/bta_gattc_cache.c @@ -0,0 +1,1637 @@ +/****************************************************************************** + * + * Copyright (C) 2003-2012 Broadcom Corporation + * + * 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 GATT client discovery procedures and cache + * related functions. + * + ******************************************************************************/ + +#include "bt_target.h" + +#if defined(BTA_GATT_INCLUDED) && (BTA_GATT_INCLUDED == TRUE) + +#include +#include "utl.h" +#include "gki.h" +#include "bta_sys.h" +#include "sdp_api.h" +#include "sdpdefs.h" +#include "bta_gattc_int.h" +#include "btm_api.h" +#include "btm_ble_api.h" + +#define LOG_TAG "bt_bta_gattc" +// #include "osi/include/log.h" + +static void bta_gattc_char_dscpt_disc_cmpl(UINT16 conn_id, tBTA_GATTC_SERV *p_srvc_cb); +static tBTA_GATT_STATUS bta_gattc_sdp_service_disc(UINT16 conn_id, tBTA_GATTC_SERV *p_server_cb); + +#define BTA_GATT_SDP_DB_SIZE 4096 + +/***************************************************************************** +** Constants +*****************************************************************************/ + +#if (defined BTA_GATT_DEBUG && BTA_GATT_DEBUG == TRUE) +static char *bta_gattc_attr_type[] = +{ + "I", /* Included Service */ + "C", /* Characteristic */ + "D" /* Characteristic Descriptor */ +}; +/* utility functions */ + +/******************************************************************************* +** +** Function bta_gattc_display_cache_server +** +** Description debug function to display the server cache. +** +** Returns none. +** +*******************************************************************************/ +static void bta_gattc_display_cache_server(tBTA_GATTC_CACHE *p_cache) +{ + UINT8 i = 0, j; + tBTA_GATTC_CACHE *p_cur_srvc = p_cache; + tBTA_GATTC_CACHE_ATTR *p_attr; + + APPL_TRACE_ERROR("<================Start Server Cache =============>"); + + while (p_cur_srvc) + { + APPL_TRACE_ERROR("Service[%d]: handle[%d ~ %d] %s[0x%04x] inst[%d]", + i, p_cur_srvc->s_handle, p_cur_srvc->e_handle, + ((p_cur_srvc->service_uuid.id.uuid.len == 2) ? "uuid16" : "uuid128"), + p_cur_srvc->service_uuid.id.uuid.uu.uuid16, + p_cur_srvc->service_uuid.id.inst_id); + i ++; + + p_attr = p_cur_srvc->p_attr; + + for (j = 0; p_attr; j ++ ) + { + APPL_TRACE_ERROR("\t Attr[0x%04x] handle[%d] uuid[0x%04x] inst[%d] type[%s] prop[0x%1x]", + j + 1, p_attr->attr_handle, p_attr->p_uuid->uuid16, p_attr->inst_id, + bta_gattc_attr_type[p_attr->attr_type], p_attr->property); + + p_attr = p_attr->p_next; + } + p_cur_srvc = p_cur_srvc->p_next; + } + + APPL_TRACE_ERROR("<================End Server Cache =============>"); + APPL_TRACE_ERROR(" "); +} + +/******************************************************************************* +** +** Function bta_gattc_display_explore_record +** +** Description debug function to display the exploration list +** +** Returns none. +** +*******************************************************************************/ +static void bta_gattc_display_explore_record(tBTA_GATTC_ATTR_REC *p_rec, UINT8 num_rec) +{ + UINT8 i; + tBTA_GATTC_ATTR_REC *pp = p_rec; + + APPL_TRACE_ERROR("<================Start Explore Queue =============>"); + for (i = 0; i < num_rec; i ++, pp ++) + { + APPL_TRACE_ERROR("\t rec[%d] uuid[0x%04x] s_handle[%d] e_handle[%d] is_primary[%d]", + i + 1, pp->uuid.uu.uuid16, pp->s_handle, pp->e_handle, pp->is_primary); + } + APPL_TRACE_ERROR("<================ End Explore Queue =============>"); + APPL_TRACE_ERROR(" "); + +} +#endif /* BTA_GATT_DEBUG == TRUE */ + + +/******************************************************************************* +** +** Function bta_gattc_alloc_cache_buf +** +** Description Allocate a GKI buffer for database cache. +** +** Returns status +** +*******************************************************************************/ +BT_HDR *bta_gattc_alloc_cache_buf(tBTA_GATTC_SERV *p_srvc_cb) +{ + BT_HDR *p_buf; + + if ((p_buf = (BT_HDR *)GKI_getpoolbuf(GATT_DB_POOL_ID)) == NULL) + { + APPL_TRACE_DEBUG("No resources: GKI buffer allocation failed."); + utl_freebuf((void **)&p_srvc_cb->p_srvc_list); + p_srvc_cb->free_byte = 0; + } + else + { + memset(p_buf, 0, GKI_get_buf_size(p_buf)); + p_srvc_cb->p_free = (UINT8 *) p_buf; + p_srvc_cb->free_byte = GKI_get_buf_size(p_buf); + + /* link into buffer queue */ + GKI_enqueue(&p_srvc_cb->cache_buffer, p_buf); + } +#if BTA_GATT_DEBUG== TRUE + APPL_TRACE_DEBUG("allocating new buffer: free byte = %d", p_srvc_cb->free_byte); +#endif + return p_buf; +} +/******************************************************************************* +** +** Function bta_gattc_init_cache +** +** Description Initialize the database cache and discovery related resources. +** +** Returns status +** +*******************************************************************************/ +tBTA_GATT_STATUS bta_gattc_init_cache(tBTA_GATTC_SERV *p_srvc_cb) +{ + tBTA_GATT_STATUS status = BTA_GATT_OK; + + while (!GKI_queue_is_empty(&p_srvc_cb->cache_buffer)) + GKI_freebuf (GKI_dequeue (&p_srvc_cb->cache_buffer)); + + utl_freebuf((void **)&p_srvc_cb->p_srvc_list); + + if ((p_srvc_cb->p_srvc_list = (tBTA_GATTC_ATTR_REC*)GKI_getbuf(BTA_GATTC_ATTR_LIST_SIZE)) == NULL) + { + APPL_TRACE_DEBUG("No resources: GKI buffer allocation failed."); + status = GATT_NO_RESOURCES; + } + else + { + p_srvc_cb->total_srvc = 0; + p_srvc_cb->cur_srvc_idx = + p_srvc_cb->cur_char_idx = + p_srvc_cb->next_avail_idx = 0; + + if (bta_gattc_alloc_cache_buf(p_srvc_cb) == NULL) + { + status = GATT_NO_RESOURCES; + } + else + { + p_srvc_cb->p_cur_srvc = p_srvc_cb->p_srvc_cache = NULL; + } + } + + return status; +} +/******************************************************************************* +** +** Function bta_gattc_get_srvc_inst_id +** +** Description get service instance number +** +** Returns instance ID of the service. +** +*******************************************************************************/ +static UINT8 bta_gattc_get_srvc_inst_id(tBTA_GATTC_SERV *p_srvc_cb, tBT_UUID uuid) +{ + UINT8 i = 0, inst = 0; + tBTA_GATTC_ATTR_REC *p_srvc_rec; + + for (i = 0; i < p_srvc_cb->total_srvc; i ++) + /* + for (; i < p_srvc_cb->cur_srvc_idx; i ++)*/ + { + p_srvc_rec = p_srvc_cb->p_srvc_list + i; + + if (bta_gattc_uuid_compare(&p_srvc_rec->uuid, &uuid, TRUE)) + inst ++; + } + return inst ; +} +/******************************************************************************* +** +** Function bta_gattc_get_char_inst_id +** +** Description get characteristic instance number +** +** Returns characteristic instance ID. +** +*******************************************************************************/ +static UINT8 bta_gattc_get_char_inst_id(tBTA_GATTC_CACHE *p_service_cache, tBT_UUID *p_uuid) +{ + UINT8 inst = 0; + tBTA_GATTC_CACHE_ATTR *p_attr; + tBT_UUID attr_uuid; + + p_attr = p_service_cache->p_attr; + + while (p_attr) + { + bta_gattc_pack_attr_uuid(p_attr, &attr_uuid); + + if (bta_gattc_uuid_compare(&attr_uuid, p_uuid, TRUE)) + inst ++; + + p_attr = p_attr->p_next; + } + + return inst ; +} +/******************************************************************************* +** +** Function bta_gattc_get_char_descr_inst_id +** +** Description get characteristic descriptor instance number +** +** Returns characteristic instance ID. +** +*******************************************************************************/ +static UINT8 bta_gattc_get_char_descr_inst_id(tBTA_GATTC_CACHE_ATTR *p_char_attr, tBT_UUID *p_uuid) +{ + UINT8 inst = 0; + tBT_UUID attr_uuid; + + if (p_char_attr != NULL) + p_char_attr = p_char_attr->p_next; + + while (p_char_attr) + { + bta_gattc_pack_attr_uuid(p_char_attr, &attr_uuid); + + if (bta_gattc_uuid_compare(&attr_uuid, p_uuid, TRUE)) + inst ++; + + p_char_attr = p_char_attr->p_next; + } + return inst ; +} + +/******************************************************************************* +** +** Function bta_gattc_add_srvc_to_cache +** +** Description Add a service into database cache. +** +** Returns status +** +*******************************************************************************/ +static tBTA_GATT_STATUS bta_gattc_add_srvc_to_cache(tBTA_GATTC_SERV *p_srvc_cb, + UINT16 s_handle, UINT16 e_handle, + tBT_UUID *p_uuid, + BOOLEAN is_primary, UINT8 srvc_inst) +{ + tBTA_GATTC_CACHE *p_new_srvc = NULL; + tBTA_GATT_STATUS status = BTA_GATT_OK; + +#if (defined BTA_GATT_DEBUG && BTA_GATT_DEBUG == TRUE) + APPL_TRACE_DEBUG("Add a service into Service"); + APPL_TRACE_DEBUG("free byte = %d, req %d bytes.", p_srvc_cb->free_byte, sizeof(tBTA_GATTC_CACHE)) +#endif + + if (p_srvc_cb->free_byte < sizeof(tBTA_GATTC_CACHE)) + { + if (bta_gattc_alloc_cache_buf(p_srvc_cb) == NULL) + return GATT_NO_RESOURCES; + } + + p_new_srvc = (tBTA_GATTC_CACHE *)p_srvc_cb->p_free; + /* update service information */ + p_new_srvc->s_handle = s_handle; + p_new_srvc->e_handle = e_handle; + p_new_srvc->service_uuid.is_primary = is_primary; + memcpy(&p_new_srvc->service_uuid.id.uuid, p_uuid, sizeof(tBT_UUID)); + p_new_srvc->service_uuid.id.inst_id = srvc_inst; + p_new_srvc->p_next = NULL; + + if (p_srvc_cb->p_cur_srvc != NULL) + p_srvc_cb->p_cur_srvc->p_next = p_new_srvc; + p_srvc_cb->p_cur_srvc = p_new_srvc; + p_srvc_cb->p_cur_srvc->p_cur_char = NULL; + + /* first service */ + if (p_srvc_cb->p_srvc_cache == NULL) + p_srvc_cb->p_srvc_cache = p_new_srvc; + + /* update buffer managament info */ + p_srvc_cb->p_free += sizeof(tBTA_GATTC_CACHE); + p_srvc_cb->free_byte -= sizeof(tBTA_GATTC_CACHE); + + + return status; +} +/******************************************************************************* +** +** Function bta_gattc_add_attr_to_cache +** +** Description Add an attribute into database cache buffer. +** +** Returns status +** +*******************************************************************************/ +static tBTA_GATT_STATUS bta_gattc_add_attr_to_cache(tBTA_GATTC_SERV *p_srvc_cb, + UINT16 handle, + tBT_UUID *p_uuid, + UINT8 property, + tBTA_GATTC_ATTR_TYPE type) +{ + tBTA_GATTC_CACHE_ATTR *p_attr; + tBTA_GATT_STATUS status = BTA_GATT_OK; + UINT16 len = sizeof(tBTA_GATTC_CACHE_ATTR) + p_uuid->len; + UINT8 *pp; + +#if (defined BTA_GATT_DEBUG && BTA_GATT_DEBUG == TRUE) + APPL_TRACE_DEBUG("bta_gattc_add_attr_to_cache: Add a [%s] into Service", bta_gattc_attr_type[type]); + APPL_TRACE_DEBUG("handle=%d uuid16=0x%x property=0x%x type=%d", handle, p_uuid->uu.uuid16, property, type); + APPL_TRACE_DEBUG("free byte = %d, req %d bytes.", p_srvc_cb->free_byte, len); +#endif + + if (p_srvc_cb->p_cur_srvc == NULL) + { + APPL_TRACE_ERROR("Illegal action to add char/descr/incl srvc before adding a service!"); + return GATT_WRONG_STATE; + } + + if (p_srvc_cb->free_byte < len) + { + if (bta_gattc_alloc_cache_buf(p_srvc_cb) == NULL) + return GATT_NO_RESOURCES; + } + + p_attr = (tBTA_GATTC_CACHE_ATTR *)p_srvc_cb->p_free; + + p_attr->attr_handle = handle; + p_attr->attr_type = type; + p_attr->property = property; + p_attr->uuid_len = p_uuid->len; + p_attr->p_uuid = (tBTA_GATTC_UUID *)(p_attr + 1); + p_attr->p_next = NULL; + + pp = (UINT8 *)p_attr->p_uuid; + + if (p_uuid->len == LEN_UUID_16) + { + UINT16_TO_STREAM(pp, p_uuid->uu.uuid16); + } + else if (p_uuid->len == LEN_UUID_128) + { + memcpy(pp, p_uuid->uu.uuid128, LEN_UUID_128); + } + + if (type == BTA_GATTC_ATTR_TYPE_CHAR) + { + p_attr->inst_id = bta_gattc_get_char_inst_id(p_srvc_cb->p_cur_srvc, p_uuid); + p_srvc_cb->p_cur_srvc->p_cur_char = p_attr; + } + else if (type == BTA_GATTC_ATTR_TYPE_CHAR_DESCR) + p_attr->inst_id = bta_gattc_get_char_descr_inst_id(p_srvc_cb->p_cur_srvc->p_cur_char, p_uuid); + else /* TODO: --->> temp treat included service as single instance */ + p_attr->inst_id = 0; + + /* update service information */ + p_srvc_cb->p_free += len; + p_srvc_cb->free_byte -= len; + + /* first attribute within the service, update the attribute pointer */ + if (p_srvc_cb->p_cur_srvc->p_attr == NULL) + { + p_srvc_cb->p_cur_srvc->p_attr = p_attr; + } + if (p_srvc_cb->p_cur_srvc->p_last_attr != NULL) + p_srvc_cb->p_cur_srvc->p_last_attr->p_next = p_attr; + + p_srvc_cb->p_cur_srvc->p_last_attr = p_attr; + + return status; +} + +/******************************************************************************* +** +** Function bta_gattc_get_disc_range +** +** Description get discovery stating and ending handle range. +** +** Returns None. +** +*******************************************************************************/ +void bta_gattc_get_disc_range(tBTA_GATTC_SERV *p_srvc_cb, UINT16 *p_s_hdl, UINT16 *p_e_hdl, BOOLEAN is_srvc) +{ + tBTA_GATTC_ATTR_REC *p_rec = NULL; + + if (is_srvc) + { + p_rec = p_srvc_cb->p_srvc_list + p_srvc_cb->cur_srvc_idx; + *p_s_hdl = p_rec->s_handle; + } + else + { + p_rec = p_srvc_cb->p_srvc_list + p_srvc_cb->cur_char_idx; + *p_s_hdl = p_rec->s_handle + 1; + } + + *p_e_hdl = p_rec->e_handle; +#if (defined BTA_GATT_DEBUG && BTA_GATT_DEBUG == TRUE) + APPL_TRACE_DEBUG("discover range [%d ~ %d]",p_rec->s_handle, p_rec->e_handle); +#endif + return; +} +/******************************************************************************* +** +** Function bta_gattc_discover_pri_service +** +** Description Start primary service discovery +** +** Returns status of the operation. +** +*******************************************************************************/ +tBTA_GATT_STATUS bta_gattc_discover_pri_service(UINT16 conn_id, tBTA_GATTC_SERV *p_server_cb, + UINT8 disc_type) +{ + tBTA_GATTC_CLCB *p_clcb = bta_gattc_find_clcb_by_conn_id(conn_id); + tBTA_GATT_STATUS status = BTA_GATT_ERROR; + + if (p_clcb) + { + if (p_clcb->transport == BTA_TRANSPORT_LE) + status = bta_gattc_discover_procedure(conn_id, p_server_cb, disc_type); + else + status = bta_gattc_sdp_service_disc(conn_id, p_server_cb); + } + + return status; +} +/******************************************************************************* +** +** Function bta_gattc_discover_procedure +** +** Description Start a particular type of discovery procedure on server. +** +** Returns status of the operation. +** +*******************************************************************************/ +tBTA_GATT_STATUS bta_gattc_discover_procedure(UINT16 conn_id, tBTA_GATTC_SERV *p_server_cb, + UINT8 disc_type) +{ + tGATT_DISC_PARAM param; + BOOLEAN is_service = TRUE; + + memset(¶m, 0, sizeof(tGATT_DISC_PARAM)); + + if (disc_type == GATT_DISC_SRVC_ALL || disc_type == GATT_DISC_SRVC_BY_UUID) + { + param.s_handle = 1; + param.e_handle = 0xFFFF; + } + else + { + if (disc_type == GATT_DISC_CHAR_DSCPT) + is_service = FALSE; + + bta_gattc_get_disc_range(p_server_cb, ¶m.s_handle, ¶m.e_handle, is_service); + + if (param.s_handle > param.e_handle) + { + return GATT_ERROR; + } + } + return GATTC_Discover (conn_id, disc_type, ¶m); + +} +/******************************************************************************* +** +** Function bta_gattc_start_disc_include_srvc +** +** Description Start discovery for included service +** +** Returns status of the operation. +** +*******************************************************************************/ +tBTA_GATT_STATUS bta_gattc_start_disc_include_srvc(UINT16 conn_id, tBTA_GATTC_SERV *p_srvc_cb) +{ + return bta_gattc_discover_procedure(conn_id, p_srvc_cb, GATT_DISC_INC_SRVC); +} +/******************************************************************************* +** +** Function bta_gattc_start_disc_char +** +** Description Start discovery for characteristic +** +** Returns status of the operation. +** +*******************************************************************************/ +tBTA_GATT_STATUS bta_gattc_start_disc_char(UINT16 conn_id, tBTA_GATTC_SERV *p_srvc_cb) +{ + p_srvc_cb->total_char = 0; + + return bta_gattc_discover_procedure(conn_id, p_srvc_cb, GATT_DISC_CHAR); +} +/******************************************************************************* +** +** Function bta_gattc_start_disc_char_dscp +** +** Description Start discovery for characteristic descriptor +** +** Returns none. +** +*******************************************************************************/ +void bta_gattc_start_disc_char_dscp(UINT16 conn_id, tBTA_GATTC_SERV *p_srvc_cb) +{ + APPL_TRACE_DEBUG("starting discover characteristics descriptor"); + + if (bta_gattc_discover_procedure(conn_id, p_srvc_cb, GATT_DISC_CHAR_DSCPT) != 0) + bta_gattc_char_dscpt_disc_cmpl(conn_id, p_srvc_cb); + +} +/******************************************************************************* +** +** Function bta_gattc_explore_srvc +** +** Description process the service discovery complete event +** +** Returns status +** +*******************************************************************************/ +static void bta_gattc_explore_srvc(UINT16 conn_id, tBTA_GATTC_SERV *p_srvc_cb) +{ + tBTA_GATTC_ATTR_REC *p_rec = p_srvc_cb->p_srvc_list + p_srvc_cb->cur_srvc_idx; + tBTA_GATTC_CLCB *p_clcb = bta_gattc_find_clcb_by_conn_id(conn_id); + + APPL_TRACE_DEBUG("Start service discovery: srvc_idx = %d", p_srvc_cb->cur_srvc_idx); + + p_srvc_cb->cur_char_idx = p_srvc_cb->next_avail_idx = p_srvc_cb->total_srvc; + + if (p_clcb == NULL) + { + APPL_TRACE_ERROR("unknown connection ID"); + return; + } + /* start expore a service if there is service not been explored */ + if (p_srvc_cb->cur_srvc_idx < p_srvc_cb->total_srvc) + { + /* add the first service into cache */ + if (bta_gattc_add_srvc_to_cache (p_srvc_cb, + p_rec->s_handle, + p_rec->e_handle, + &p_rec->uuid, + p_rec->is_primary, + p_rec->srvc_inst_id) == 0) + { + /* start discovering included services */ + bta_gattc_start_disc_include_srvc(conn_id, p_srvc_cb); + return; + } + } + /* no service found at all, the end of server discovery*/ + LOG_WARN("%s no more services found", __func__); + +#if (defined BTA_GATT_DEBUG && BTA_GATT_DEBUG == TRUE) + bta_gattc_display_cache_server(p_srvc_cb->p_srvc_cache); +#endif + /* save cache to NV */ + p_clcb->p_srcb->state = BTA_GATTC_SERV_SAVE; + bta_gattc_co_cache_open(p_srvc_cb->server_bda, BTA_GATTC_CI_CACHE_OPEN_EVT, + conn_id, TRUE); +} +/******************************************************************************* +** +** Function bta_gattc_incl_srvc_disc_cmpl +** +** Description process the relationship discovery complete event +** +** Returns status +** +*******************************************************************************/ +static void bta_gattc_incl_srvc_disc_cmpl(UINT16 conn_id, tBTA_GATTC_SERV *p_srvc_cb) +{ + p_srvc_cb->cur_char_idx = p_srvc_cb->total_srvc; + + /* start discoverying characteristic */ + bta_gattc_start_disc_char(conn_id, p_srvc_cb); +} +/******************************************************************************* +** +** Function bta_gattc_char_disc_cmpl +** +** Description process the characteristic discovery complete event +** +** Returns status +** +*******************************************************************************/ +static void bta_gattc_char_disc_cmpl(UINT16 conn_id, tBTA_GATTC_SERV *p_srvc_cb) +{ + tBTA_GATTC_ATTR_REC *p_rec = p_srvc_cb->p_srvc_list + p_srvc_cb->cur_char_idx; + + /* if there are characteristic needs to be explored */ + if (p_srvc_cb->total_char > 0) + { + /* add the first characteristic into cache */ + bta_gattc_add_attr_to_cache (p_srvc_cb, + p_rec->s_handle, + &p_rec->uuid, + p_rec->property, + BTA_GATTC_ATTR_TYPE_CHAR); + + /* start discoverying characteristic descriptor , if failed, disc for next char*/ + bta_gattc_start_disc_char_dscp(conn_id, p_srvc_cb); + } + else /* otherwise start with next service */ + { + p_srvc_cb->cur_srvc_idx ++; + + bta_gattc_explore_srvc (conn_id, p_srvc_cb); + } +} +/******************************************************************************* +** +** Function bta_gattc_char_dscpt_disc_cmpl +** +** Description process the char descriptor discovery complete event +** +** Returns status +** +*******************************************************************************/ +static void bta_gattc_char_dscpt_disc_cmpl(UINT16 conn_id, tBTA_GATTC_SERV *p_srvc_cb) +{ + tBTA_GATTC_ATTR_REC *p_rec = NULL; + + if (-- p_srvc_cb->total_char > 0) + { + p_rec = p_srvc_cb->p_srvc_list + (++ p_srvc_cb->cur_char_idx); + /* add the next characteristic into cache */ + bta_gattc_add_attr_to_cache (p_srvc_cb, + p_rec->s_handle, + &p_rec->uuid, + p_rec->property, + BTA_GATTC_ATTR_TYPE_CHAR); + + /* start discoverying next characteristic for char descriptor */ + bta_gattc_start_disc_char_dscp(conn_id, p_srvc_cb); + } + else + /* all characteristic has been explored, start with next service if any */ + { +#if (defined BTA_GATT_DEBUG && BTA_GATT_DEBUG == TRUE) + APPL_TRACE_ERROR("all char has been explored"); +#endif + p_srvc_cb->cur_srvc_idx ++; + bta_gattc_explore_srvc (conn_id, p_srvc_cb); + } + +} +static BOOLEAN bta_gattc_srvc_in_list(tBTA_GATTC_SERV *p_srvc_cb, UINT16 s_handle, + UINT16 e_handle, tBT_UUID uuid) +{ + tBTA_GATTC_ATTR_REC *p_rec = NULL; + UINT8 i; + BOOLEAN exist_srvc = FALSE; + UNUSED(uuid); + + if (!GATT_HANDLE_IS_VALID(s_handle) || !GATT_HANDLE_IS_VALID(e_handle)) + { + APPL_TRACE_ERROR("invalid included service handle: [0x%04x ~ 0x%04x]", s_handle, e_handle); + exist_srvc = TRUE; + } + else + { + for (i = 0; i < p_srvc_cb->next_avail_idx; i ++) + { + p_rec = p_srvc_cb->p_srvc_list + i; + + /* a new service should not have any overlap with other service handle range */ + if (p_rec->s_handle == s_handle || p_rec->e_handle == e_handle) + { + exist_srvc = TRUE; + break; + } + } + } + return exist_srvc; +} +/******************************************************************************* +** +** Function bta_gattc_add_srvc_to_list +** +** Description Add a service into explore pending list +** +** Returns status +** +*******************************************************************************/ +static tBTA_GATT_STATUS bta_gattc_add_srvc_to_list(tBTA_GATTC_SERV *p_srvc_cb, + UINT16 s_handle, UINT16 e_handle, + tBT_UUID uuid, BOOLEAN is_primary) +{ + tBTA_GATTC_ATTR_REC *p_rec = NULL; + tBTA_GATT_STATUS status = BTA_GATT_OK; + + if (p_srvc_cb->p_srvc_list && p_srvc_cb->next_avail_idx < BTA_GATTC_MAX_CACHE_CHAR) + { + p_rec = p_srvc_cb->p_srvc_list + p_srvc_cb->next_avail_idx; + + APPL_TRACE_DEBUG("%s handle=%d, service type=0x%04x", + __func__, s_handle, uuid.uu.uuid16); + + p_rec->s_handle = s_handle; + p_rec->e_handle = e_handle; + p_rec->is_primary = is_primary; + p_rec->srvc_inst_id = bta_gattc_get_srvc_inst_id(p_srvc_cb, uuid); + memcpy(&p_rec->uuid, &uuid, sizeof(tBT_UUID)); + + p_srvc_cb->total_srvc ++; + p_srvc_cb->next_avail_idx ++; + } + else + { /* allocate bigger buffer ?? */ + status = GATT_DB_FULL; + + APPL_TRACE_ERROR("service not added, no resources or wrong state"); + } + return status; +} +/******************************************************************************* +** +** Function bta_gattc_add_char_to_list +** +** Description Add a characteristic into explore pending list +** +** Returns status +** +*******************************************************************************/ +static tBTA_GATT_STATUS bta_gattc_add_char_to_list(tBTA_GATTC_SERV *p_srvc_cb, + UINT16 decl_handle, UINT16 value_handle, + tBT_UUID uuid, UINT8 property) +{ + tBTA_GATTC_ATTR_REC *p_rec = NULL; + tBTA_GATT_STATUS status = BTA_GATT_OK; + + if (p_srvc_cb->p_srvc_list == NULL) + { + APPL_TRACE_ERROR("No service available, unexpected char discovery result"); + status = BTA_GATT_INTERNAL_ERROR; + } + else if (p_srvc_cb->next_avail_idx < BTA_GATTC_MAX_CACHE_CHAR) + { + + p_rec = p_srvc_cb->p_srvc_list + p_srvc_cb->next_avail_idx; + + p_srvc_cb->total_char ++; + + p_rec->s_handle = value_handle; + p_rec->property = property; + p_rec->e_handle = (p_srvc_cb->p_srvc_list + p_srvc_cb->cur_srvc_idx)->e_handle; + memcpy(&p_rec->uuid, &uuid, sizeof(tBT_UUID)); + + /* update the endind handle of pervious characteristic if available */ + if (p_srvc_cb->total_char > 1) + { + p_rec -= 1; + p_rec->e_handle = decl_handle - 1; + } + p_srvc_cb->next_avail_idx ++; + } + else + { + APPL_TRACE_ERROR("char not added, no resources"); + /* allocate bigger buffer ?? */ + status = BTA_GATT_DB_FULL; + } + return status; + +} +/******************************************************************************* +** +** Function bta_gattc_sdp_callback +** +** Description Process the discovery result from sdp +** +** Returns void +** +*******************************************************************************/ +void bta_gattc_sdp_callback (UINT16 sdp_status) +{ + tSDP_DISC_REC *p_sdp_rec = NULL; + tBT_UUID service_uuid; + tSDP_PROTOCOL_ELEM pe; + UINT16 start_handle = 0, end_handle = 0; + tBTA_GATTC_SERV *p_srvc_cb = bta_gattc_find_scb_by_cid(bta_gattc_cb.sdp_conn_id); + + if(((sdp_status == SDP_SUCCESS) || (sdp_status == SDP_DB_FULL)) && p_srvc_cb != NULL) + { + do + { + /* find a service record, report it */ + p_sdp_rec = SDP_FindServiceInDb(bta_gattc_cb.p_sdp_db, + 0, p_sdp_rec); + if (p_sdp_rec) + { + if (SDP_FindServiceUUIDInRec(p_sdp_rec, &service_uuid)) + { + + if (SDP_FindProtocolListElemInRec(p_sdp_rec, UUID_PROTOCOL_ATT, &pe)) + { + start_handle = (UINT16) pe.params[0]; + end_handle = (UINT16) pe.params[1]; + +#if (defined BTA_GATT_DEBUG && BTA_GATT_DEBUG == TRUE) + APPL_TRACE_EVENT("Found ATT service [0x%04x] handle[0x%04x ~ 0x%04x]", + service_uuid.uu.uuid16, start_handle, end_handle); +#endif + + if (GATT_HANDLE_IS_VALID(start_handle) && GATT_HANDLE_IS_VALID(end_handle)&& + p_srvc_cb != NULL) + { + /* discover services result, add services into a service list */ + bta_gattc_add_srvc_to_list(p_srvc_cb, + start_handle, + end_handle, + service_uuid, + TRUE); + } + else + { + APPL_TRACE_ERROR("invalid start_handle = %d end_handle = %d", + start_handle, end_handle); + } + } + + + } + } + } while (p_sdp_rec); + } + + if ( p_srvc_cb != NULL) + /* start discover primary service */ + bta_gattc_explore_srvc(bta_gattc_cb.sdp_conn_id, p_srvc_cb); + else + { + APPL_TRACE_ERROR("GATT service discovery is done on unknown connection"); + } + + GKI_freebuf(bta_gattc_cb.p_sdp_db); + bta_gattc_cb.p_sdp_db = NULL; + bta_gattc_cb.sdp_conn_id = 0; +} +/******************************************************************************* +** +** Function bta_gattc_sdp_service_disc +** +** Description Start DSP Service Discovert +** +** Returns void +** +*******************************************************************************/ +static tBTA_GATT_STATUS bta_gattc_sdp_service_disc(UINT16 conn_id, tBTA_GATTC_SERV *p_server_cb) +{ + tSDP_UUID uuid; + UINT16 num_attrs = 2; + UINT16 attr_list[2]; + tBTA_GATT_STATUS status = BTA_GATT_ERROR; + + memset (&uuid, 0, sizeof(tSDP_UUID)); + + uuid.len = LEN_UUID_16; + uuid.uu.uuid16 = UUID_PROTOCOL_ATT; + + if((bta_gattc_cb.p_sdp_db = (tSDP_DISCOVERY_DB *)GKI_getbuf(BTA_GATT_SDP_DB_SIZE)) != NULL) + { + attr_list[0] = ATTR_ID_SERVICE_CLASS_ID_LIST; + attr_list[1] = ATTR_ID_PROTOCOL_DESC_LIST; + + SDP_InitDiscoveryDb (bta_gattc_cb.p_sdp_db, BTA_GATT_SDP_DB_SIZE, 1, + &uuid, num_attrs, attr_list); + + if(!SDP_ServiceSearchAttributeRequest (p_server_cb->server_bda, + bta_gattc_cb.p_sdp_db, &bta_gattc_sdp_callback)) + { + GKI_freebuf(bta_gattc_cb.p_sdp_db); + bta_gattc_cb.p_sdp_db = NULL; + } + else + { + bta_gattc_cb.sdp_conn_id = conn_id; + status = BTA_GATT_OK; + } + } + return status; +} +/******************************************************************************* +** +** Function bta_gattc_disc_res_cback +** bta_gattc_disc_cmpl_cback +** +** Description callback functions to GATT client stack. +** +** Returns void +** +*******************************************************************************/ +void bta_gattc_disc_res_cback (UINT16 conn_id, tGATT_DISC_TYPE disc_type, tGATT_DISC_RES *p_data) +{ + tBTA_GATTC_SERV * p_srvc_cb = NULL; + BOOLEAN pri_srvc; + tBTA_GATTC_CLCB *p_clcb = bta_gattc_find_clcb_by_conn_id(conn_id); + + p_srvc_cb = bta_gattc_find_scb_by_cid(conn_id); + + if (p_srvc_cb != NULL && p_clcb != NULL && p_clcb->state == BTA_GATTC_DISCOVER_ST) + { + switch (disc_type) + { + case GATT_DISC_SRVC_ALL: + /* discover services result, add services into a service list */ + bta_gattc_add_srvc_to_list(p_srvc_cb, + p_data->handle, + p_data->value.group_value.e_handle, + p_data->value.group_value.service_type, + TRUE); + + break; + case GATT_DISC_SRVC_BY_UUID: + bta_gattc_add_srvc_to_list(p_srvc_cb, + p_data->handle, + p_data->value.group_value.e_handle, + p_data->value.group_value.service_type, + TRUE); + break; + + case GATT_DISC_INC_SRVC: + /* add included service into service list if it's secondary or it never showed up + in the primary service search */ + pri_srvc = bta_gattc_srvc_in_list(p_srvc_cb, + p_data->value.incl_service.s_handle, + p_data->value.incl_service.e_handle, + p_data->value.incl_service.service_type); + + if (!pri_srvc) + bta_gattc_add_srvc_to_list(p_srvc_cb, + p_data->value.incl_service.s_handle, + p_data->value.incl_service.e_handle, + p_data->value.incl_service.service_type, + FALSE); + /* add into database */ + bta_gattc_add_attr_to_cache(p_srvc_cb, + p_data->handle, + &p_data->value.incl_service.service_type, + pri_srvc, + BTA_GATTC_ATTR_TYPE_INCL_SRVC); + break; + + case GATT_DISC_CHAR: + /* add char value into database */ + bta_gattc_add_char_to_list(p_srvc_cb, + p_data->handle, + p_data->value.dclr_value.val_handle, + p_data->value.dclr_value.char_uuid, + p_data->value.dclr_value.char_prop); + break; + + case GATT_DISC_CHAR_DSCPT: + bta_gattc_add_attr_to_cache(p_srvc_cb, p_data->handle, &p_data->type, 0, + BTA_GATTC_ATTR_TYPE_CHAR_DESCR); + break; + } + } +} +void bta_gattc_disc_cmpl_cback (UINT16 conn_id, tGATT_DISC_TYPE disc_type, tGATT_STATUS status) +{ + tBTA_GATTC_SERV * p_srvc_cb; + tBTA_GATTC_CLCB *p_clcb = bta_gattc_find_clcb_by_conn_id(conn_id); + + if ( p_clcb && (status != GATT_SUCCESS || p_clcb->status != GATT_SUCCESS) ) + { + if (p_clcb->status == GATT_SUCCESS) + p_clcb->status = status; + bta_gattc_sm_execute(p_clcb, BTA_GATTC_DISCOVER_CMPL_EVT, NULL); + return; + } + p_srvc_cb = bta_gattc_find_scb_by_cid(conn_id); + + if (p_srvc_cb != NULL) + { + switch (disc_type) + { + case GATT_DISC_SRVC_ALL: + case GATT_DISC_SRVC_BY_UUID: +#if (defined BTA_GATT_DEBUG && BTA_GATT_DEBUG == TRUE) + bta_gattc_display_explore_record(p_srvc_cb->p_srvc_list, p_srvc_cb->next_avail_idx); +#endif + bta_gattc_explore_srvc(conn_id, p_srvc_cb); + break; + + case GATT_DISC_INC_SRVC: + bta_gattc_incl_srvc_disc_cmpl(conn_id, p_srvc_cb); + + break; + + case GATT_DISC_CHAR: +#if (defined BTA_GATT_DEBUG && BTA_GATT_DEBUG == TRUE) + bta_gattc_display_explore_record(p_srvc_cb->p_srvc_list, p_srvc_cb->next_avail_idx); +#endif + bta_gattc_char_disc_cmpl(conn_id, p_srvc_cb); + break; + + case GATT_DISC_CHAR_DSCPT: + bta_gattc_char_dscpt_disc_cmpl(conn_id, p_srvc_cb); + break; + } + } +} +/******************************************************************************* +** +** Function bta_gattc_id2handle +** +** Description map GATT ID to handle in a given cache. +** +** Returns the handle mapped. 0 if not found. +** +*******************************************************************************/ +UINT16 bta_gattc_id2handle(tBTA_GATTC_SERV *p_srcb, tBTA_GATT_SRVC_ID *p_service_id, + tBTA_GATT_ID *p_char_id, tBTA_GATT_ID *p_descr_uuid) +{ + tBTA_GATTC_CACHE *p_cache = p_srcb->p_srvc_cache; + tBTA_GATTC_CACHE_ATTR *p_attr; + UINT8 j; + UINT16 handle = 0; + tBT_UUID attr_uuid; + BOOLEAN char_map = FALSE, done = FALSE; + + while (p_service_id && p_cache && !done) + { +#if (defined BTA_GATT_DEBUG && BTA_GATT_DEBUG == TRUE) + APPL_TRACE_DEBUG("Service: handle[%d] uuid[0x%04x] inst[%d]", + p_cache->s_handle, p_cache->service_uuid.id.uuid.uu.uuid16, + p_cache->service_uuid.id.inst_id); +#endif + p_attr = p_cache->p_attr; + + if (bta_gattc_srvcid_compare(p_service_id, &p_cache->service_uuid)) + { + for (j = 0; p_attr; j ++) + { +#if (defined BTA_GATT_DEBUG && BTA_GATT_DEBUG == TRUE) + APPL_TRACE_DEBUG("\t Attr[0x%04x] handle[0x%04x] uuid[0x%04x] inst[%d] type[%d]", + j + 1, p_attr->attr_handle, p_attr->p_uuid->uuid16, + p_attr->inst_id, p_attr->attr_type); +#endif + bta_gattc_pack_attr_uuid(p_attr, &attr_uuid); + + if (bta_gattc_uuid_compare(&p_char_id->uuid, &attr_uuid, TRUE) && + p_char_id->inst_id == p_attr->inst_id) + { + if (p_descr_uuid == NULL) + { + handle = p_attr->attr_handle; + done = TRUE; + break; + } + else + { +#if (defined BTA_GATT_DEBUG && BTA_GATT_DEBUG == TRUE) + APPL_TRACE_DEBUG("found matching characteristic for the descriptor"); +#endif + char_map = TRUE; + } + } + else if (char_map == TRUE) + { + if (p_attr->attr_type == BTA_GATTC_ATTR_TYPE_CHAR_DESCR) + { + + if (p_descr_uuid != NULL && + bta_gattc_uuid_compare(&p_descr_uuid->uuid, &attr_uuid, TRUE) && + p_descr_uuid->inst_id == p_attr->inst_id) + { +#if (defined BTA_GATT_DEBUG && BTA_GATT_DEBUG == TRUE) + APPL_TRACE_DEBUG("found descriptor!!"); +#endif + handle = p_attr->attr_handle; + done = TRUE; + break; + } + else + { +#if (defined BTA_GATT_DEBUG && BTA_GATT_DEBUG == TRUE) + APPL_TRACE_DEBUG("descriptor UUID not matching"); +#endif + } + } + else /* another char */ + { +#if (defined BTA_GATT_DEBUG && BTA_GATT_DEBUG == TRUE) + APPL_TRACE_DEBUG("no matching descptr found!!start of next characteristic"); +#endif + char_map = FALSE; + done = TRUE; + break; + } + } + p_attr = p_attr->p_next; + } + } + p_cache = p_cache->p_next; + } + + return handle; +} +/******************************************************************************* +** +** Function bta_gattc_handle2id +** +** Description map a handle to GATT ID in a given cache. +** +** Returns FALSE if map can not be found. +** +*******************************************************************************/ + +BOOLEAN bta_gattc_handle2id(tBTA_GATTC_SERV *p_srcb, UINT16 handle, tBTA_GATT_SRVC_ID *p_service_id, + tBTA_GATT_ID *p_char_id, tBTA_GATT_ID *p_descr_type) +{ + tBTA_GATTC_CACHE *p_cache = p_srcb->p_srvc_cache; + tBTA_GATTC_CACHE_ATTR *p_attr, *p_char = NULL; + UINT8 j; + + memset(p_service_id, 0, sizeof(tBTA_GATT_SRVC_ID)); + memset(p_char_id, 0, sizeof(tBTA_GATT_ID)); + memset(p_descr_type, 0, sizeof(tBTA_GATT_ID)); + + while (p_cache) + { +#if (defined BTA_GATT_DEBUG && BTA_GATT_DEBUG == TRUE) + APPL_TRACE_DEBUG("Service: handle[%d] uuid[0x%04x] inst[%d]", + p_cache->s_handle, p_cache->service_uuid.id.uuid.uu.uuid16, + p_cache->service_uuid.id.inst_id); +#endif + /* a service found */ + if (p_cache->s_handle == handle) + { + memcpy(p_service_id, &p_cache->service_uuid, sizeof(tBTA_GATT_SRVC_ID)); + + return TRUE; + } + else /* start looking for attributes within the service */ + { + p_attr = p_cache->p_attr; + + for (j = 0; p_attr; j ++) + { +#if (defined BTA_GATT_DEBUG && BTA_GATT_DEBUG == TRUE) + APPL_TRACE_DEBUG("\t Attr[0x%04x] handle[0x%04x] uuid[0x%04x] inst[%d] type[%d]", + j + 1, p_attr->attr_handle, p_attr->p_uuid->uuid16, + p_attr->inst_id, p_attr->attr_type); +#endif + if (p_attr->attr_type == BTA_GATTC_ATTR_TYPE_CHAR) + p_char = p_attr; + + if (handle == p_attr->attr_handle) + { + memcpy(p_service_id, &p_cache->service_uuid, sizeof(tBTA_GATT_SRVC_ID)); + + if (p_attr->attr_type == BTA_GATTC_ATTR_TYPE_CHAR_DESCR) + { + bta_gattc_pack_attr_uuid(p_attr, &p_descr_type->uuid); + p_descr_type->inst_id = p_attr->inst_id; + + if (p_char != NULL) + { + bta_gattc_pack_attr_uuid(p_char, &p_char_id->uuid); + p_char_id->inst_id = p_char->inst_id; + } + else + { + APPL_TRACE_ERROR("descptr does not belong to any chracteristic"); + } + } + else + /* is a characterisitc value or included service */ + { + bta_gattc_pack_attr_uuid(p_attr, &p_char_id->uuid); + p_char_id->inst_id =p_attr->inst_id; + } + return TRUE; + } + p_attr = p_attr->p_next; + } + } + p_cache = p_cache->p_next; + } + + return FALSE; +} + +/******************************************************************************* +** +** Function bta_gattc_search_service +** +** Description search local cache for matching service record. +** +** Returns FALSE if map can not be found. +** +*******************************************************************************/ +void bta_gattc_search_service(tBTA_GATTC_CLCB *p_clcb, tBT_UUID *p_uuid) +{ + tBTA_GATTC_SERV *p_srcb = p_clcb->p_srcb; + tBTA_GATTC_CACHE *p_cache = p_srcb->p_srvc_cache; + tBTA_GATTC cb_data; + + while (p_cache) + { + if (bta_gattc_uuid_compare(p_uuid, &p_cache->service_uuid.id.uuid, FALSE)) + { +#if (defined BTA_GATT_DEBUG && BTA_GATT_DEBUG == TRUE) + APPL_TRACE_DEBUG("found service [0x%04x], inst[%d] handle [%d]", + p_cache->service_uuid.id.uuid.uu.uuid16, + p_cache->service_uuid.id.inst_id, + p_cache->s_handle); +#endif + if (p_clcb->p_rcb->p_cback) + { + memset(&cb_data, 0, sizeof(tBTA_GATTC)); + + cb_data.srvc_res.conn_id = p_clcb->bta_conn_id; + memcpy(&cb_data.srvc_res.service_uuid, &p_cache->service_uuid, + sizeof(tBTA_GATT_SRVC_ID)); + + (* p_clcb->p_rcb->p_cback)(BTA_GATTC_SEARCH_RES_EVT, &cb_data); + } + } + p_cache = p_cache->p_next; + } +} +/******************************************************************************* +** +** Function bta_gattc_find_record +** +** Description search local cache for matching attribute record. +** +** Parameter p_result: output parameter to store the characteristic/ +** included service GATT ID. +** +** Returns GATT_ERROR is no recording found. BTA_GATT_OK if record found. +** +*******************************************************************************/ +static tBTA_GATT_STATUS bta_gattc_find_record(tBTA_GATTC_SERV *p_srcb, + tBTA_GATTC_ATTR_TYPE attr_type, + tBTA_GATT_SRVC_ID *p_service_id, + tBTA_GATT_ID *p_start_rec, + tBT_UUID * p_uuid_cond, + tBTA_GATT_ID *p_result, + void *p_param) +{ + tBTA_GATTC_CACHE *p_cache = p_srcb->p_srvc_cache; + tBTA_GATT_STATUS status = BTA_GATT_ERROR; + UINT8 i, j; + tBTA_GATTC_CACHE_ATTR *p_attr; + BOOLEAN char_found = FALSE, descr_found = FALSE; + tBTA_GATT_ID *p_descr_id = (tBTA_GATT_ID *)p_param;; + + for (i = 0; p_cache && status != BTA_GATT_OK; i ++) + { + if (bta_gattc_srvcid_compare(p_service_id, &p_cache->service_uuid)) + { +#if (defined BTA_GATT_DEBUG && BTA_GATT_DEBUG == TRUE) + APPL_TRACE_DEBUG("found matching service [0x%04x], inst[%d]", + p_cache->service_uuid.id.uuid.uu.uuid16, + p_cache->service_uuid.id.inst_id); +#endif + p_attr = p_cache->p_attr; + + for (j = 0; p_attr; j ++) + { +#if (defined BTA_GATT_DEBUG && BTA_GATT_DEBUG == TRUE) + APPL_TRACE_DEBUG("\t Attr[%d] handle[0x%04x] uuid[0x%04x] inst[%d] type[%d]", + j + 1, p_attr->attr_handle, + p_attr->p_uuid->uuid16, + p_attr->inst_id, + p_attr->attr_type); +#endif + bta_gattc_pack_attr_uuid(p_attr, &p_result->uuid); + + if (p_start_rec != NULL && char_found == FALSE) + { + /* find the starting record first */ + if (bta_gattc_uuid_compare(&p_start_rec->uuid, &p_result->uuid, FALSE) && + p_start_rec->inst_id == p_attr->inst_id && + (attr_type == p_attr->attr_type || + /* find descriptor would look for characteristic first */ + (attr_type == BTA_GATTC_ATTR_TYPE_CHAR_DESCR && + p_attr->attr_type == BTA_GATTC_ATTR_TYPE_CHAR))) + { + char_found = TRUE; + } + } + else + { + /* if looking for descriptor, here is the where the descrptor to be found */ + if (attr_type == BTA_GATTC_ATTR_TYPE_CHAR_DESCR) + { + /* next characeteristic already, return error */ + if (p_attr->attr_type != BTA_GATTC_ATTR_TYPE_CHAR_DESCR) + { + break; + } + else + { + /* find starting descriptor */ + if (p_descr_id != NULL && !descr_found) + { + if (bta_gattc_uuid_compare(&p_descr_id->uuid, &p_result->uuid, TRUE) + && p_descr_id->inst_id == p_attr->inst_id) + { + descr_found = TRUE; + } + } + else + { + /* with matching descriptor */ + if (bta_gattc_uuid_compare(p_uuid_cond, &p_result->uuid, FALSE)) + { + p_result->inst_id = p_attr->inst_id; + status = BTA_GATT_OK; + break; + } + } + } + } + else + { + if (bta_gattc_uuid_compare(p_uuid_cond, &p_result->uuid, FALSE) && + attr_type == p_attr->attr_type) + { + +#if (defined BTA_GATT_DEBUG && BTA_GATT_DEBUG == TRUE) + APPL_TRACE_DEBUG("found char handle mapping characteristic"); +#endif + p_result->inst_id = p_attr->inst_id; + + if (p_param != NULL) + { + if (attr_type == BTA_GATTC_ATTR_TYPE_CHAR || + attr_type == BTA_GATTC_ATTR_TYPE_INCL_SRVC) + { + *(tBTA_GATT_CHAR_PROP *)p_param = p_attr->property; + } + } + + status = BTA_GATT_OK; + break; + } + } + } + p_attr = p_attr->p_next; + } +#if (defined BTA_GATT_DEBUG && BTA_GATT_DEBUG == TRUE) + if (status) + { + APPL_TRACE_ERROR("In the given service, can not find matching record"); + } +#endif + break; + } + + p_cache = p_cache->p_next; + } + return status; + +} + +/******************************************************************************* +** +** Function bta_gattc_query_cache +** +** Description search local cache for matching attribute record. +** +** Parameters conn_id: connection ID which identify the server. +** p_srvc_id: the service ID of which the characteristic is belonged to. +** *p_start_rec: start the search from the next record +** after the one identified by *p_start_rec. +** p_uuid_cond: UUID, if NULL find the first available +** characteristic/included service. +** p_output: output parameter which will store the GATT ID +** of the characteristic /included service found. +** +** Returns BTA_GATT_ERROR is no recording found. BTA_GATT_OK if record found. +** +*******************************************************************************/ +tBTA_GATT_STATUS bta_gattc_query_cache(UINT16 conn_id, + tBTA_GATTC_ATTR_TYPE query_type, + tBTA_GATT_SRVC_ID *p_srvc_id, + tBTA_GATT_ID *p_start_rec, + tBT_UUID *p_uuid_cond, + tBTA_GATT_ID *p_output, + void *p_param) +{ + tBTA_GATTC_CLCB *p_clcb = bta_gattc_find_clcb_by_conn_id(conn_id); + tBTA_GATT_STATUS status = BTA_GATT_ILLEGAL_PARAMETER; + + if (p_clcb != NULL ) + { + if (p_clcb->state == BTA_GATTC_CONN_ST) + { + if (p_clcb->p_srcb && + !p_clcb->p_srcb->p_srvc_list && /* no active discovery */ + p_clcb->p_srcb->p_srvc_cache) + { + status = bta_gattc_find_record(p_clcb->p_srcb, + query_type, + p_srvc_id, + p_start_rec, + p_uuid_cond, + p_output, + p_param); + } + else + { + status = BTA_GATT_ERROR; + APPL_TRACE_ERROR("No server cache available"); + } + } + else + { + APPL_TRACE_ERROR("server cache not available, CLCB state = %d", p_clcb->state); + + status = (p_clcb->state == BTA_GATTC_DISCOVER_ST) ? BTA_GATT_BUSY : BTA_GATT_ERROR; + } + } + else + { + APPL_TRACE_ERROR("Unknown conn ID: %d", conn_id); + } + + return status; +} + +/******************************************************************************* +** +** Function bta_gattc_rebuild_cache +** +** Description rebuild server cache from NV cache. +** +** Parameters +** +** Returns None. +** +*******************************************************************************/ +void bta_gattc_rebuild_cache(tBTA_GATTC_SERV *p_srvc_cb, UINT16 num_attr, + tBTA_GATTC_NV_ATTR *p_attr, UINT16 attr_index) +{ + /* first attribute loading, initialize buffer */ + APPL_TRACE_ERROR("bta_gattc_rebuild_cache"); + if (attr_index == 0) + { + while (!GKI_queue_is_empty(&p_srvc_cb->cache_buffer)) + GKI_freebuf (GKI_dequeue (&p_srvc_cb->cache_buffer)); + + if (bta_gattc_alloc_cache_buf(p_srvc_cb) == NULL) + { + APPL_TRACE_ERROR("allocate cache buffer failed, no resources"); + } + else + { + p_srvc_cb->p_cur_srvc = p_srvc_cb->p_srvc_cache = NULL; + } + } + + while (num_attr > 0 && p_attr != NULL) + { + switch (p_attr->attr_type) + { + case BTA_GATTC_ATTR_TYPE_SRVC: + bta_gattc_add_srvc_to_cache(p_srvc_cb, + p_attr->s_handle, + p_attr->e_handle, + &p_attr->uuid, + p_attr->is_primary, + p_attr->id); + break; + + case BTA_GATTC_ATTR_TYPE_CHAR: + case BTA_GATTC_ATTR_TYPE_CHAR_DESCR: + case BTA_GATTC_ATTR_TYPE_INCL_SRVC: + bta_gattc_add_attr_to_cache(p_srvc_cb, + p_attr->s_handle, + &p_attr->uuid, + p_attr->prop, + p_attr->attr_type); + break; + } + p_attr ++; + num_attr --; + } +} + +/******************************************************************************* +** +** Function bta_gattc_fill_nv_attr +** +** Description fill a NV attribute entry value +** +** Returns None. +** +*******************************************************************************/ +void bta_gattc_fill_nv_attr(tBTA_GATTC_NV_ATTR *p_attr, UINT8 type, UINT16 s_handle, + UINT16 e_handle, UINT8 id, tBT_UUID uuid, UINT8 prop, + BOOLEAN is_primary) +{ + p_attr->s_handle = s_handle; + p_attr->e_handle = e_handle; + p_attr->attr_type = type; + p_attr->is_primary = is_primary; + p_attr->id = id; + p_attr->prop = prop; + + memcpy(&p_attr->uuid, &uuid, sizeof(tBT_UUID)); +} +/******************************************************************************* +** +** Function bta_gattc_cache_save +** +** Description save the server cache into NV +** +** Returns None. +** +*******************************************************************************/ +BOOLEAN bta_gattc_cache_save(tBTA_GATTC_SERV *p_srvc_cb, UINT16 conn_id) +{ + tBTA_GATTC_CACHE *p_cur_srvc = p_srvc_cb->p_srvc_cache; + UINT8 i = 0; + UINT16 offset = 0; + tBTA_GATTC_NV_ATTR nv_attr[BTA_GATTC_NV_LOAD_MAX]; + tBTA_GATTC_CACHE_ATTR *p_attr; + tBT_UUID uuid; + + while (p_cur_srvc && i < BTA_GATTC_NV_LOAD_MAX) + { + if (offset ++ >= p_srvc_cb->attr_index) + { + bta_gattc_fill_nv_attr(&nv_attr[i++], + BTA_GATTC_ATTR_TYPE_SRVC, + p_cur_srvc->s_handle, + p_cur_srvc->e_handle, + p_cur_srvc->service_uuid.id.inst_id, + p_cur_srvc->service_uuid.id.uuid, + 0, + p_cur_srvc->service_uuid.is_primary); + } + + p_attr = p_cur_srvc->p_attr; + + for (; p_attr && i < BTA_GATTC_NV_LOAD_MAX ; offset ++, p_attr = p_attr->p_next) + { + if (offset >= p_srvc_cb->attr_index) + { + if ((uuid.len = p_attr->uuid_len) == LEN_UUID_16) + { + uuid.uu.uuid16 = p_attr->p_uuid->uuid16; + } + else + { + memcpy(uuid.uu.uuid128, p_attr->p_uuid->uuid128, LEN_UUID_128); + } + + bta_gattc_fill_nv_attr(&nv_attr[i++], + p_attr->attr_type, + p_attr->attr_handle, + 0, + p_attr->inst_id, + uuid, + p_attr->property, + FALSE); + } + } + p_cur_srvc = p_cur_srvc->p_next; + } + + if (i > 0) + { + bta_gattc_co_cache_save(p_srvc_cb->server_bda, BTA_GATTC_CI_CACHE_SAVE_EVT, i, + nv_attr, p_srvc_cb->attr_index, conn_id); + + p_srvc_cb->attr_index += i; + + return TRUE; + } + else + { + return FALSE; + } +} +#endif /* BTA_GATT_INCLUDED */ + diff --git a/components/bt/bluedroid/bta/gatt/bta_gattc_ci.c b/components/bt/bluedroid/bta/gatt/bta_gattc_ci.c new file mode 100755 index 0000000000..f6d9347a70 --- /dev/null +++ b/components/bt/bluedroid/bta/gatt/bta_gattc_ci.c @@ -0,0 +1,140 @@ +/****************************************************************************** + * + * Copyright (C) 2010-2012 Broadcom Corporation + * + * 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 is the implementation file for the GATT call-in functions. + * + ******************************************************************************/ + +#include "bt_target.h" + +#if defined(BTA_GATT_INCLUDED) && (BTA_GATT_INCLUDED == TRUE) + +#include + +#include "bta_api.h" +#include "bta_sys.h" +#include "bta_gattc_ci.h" +#include "gki.h" +#include "utl.h" + +/******************************************************************************* +** +** Function bta_gattc_ci_cache_open +** +** Description This function sends an event to indicate server cache open +** completed. +** +** Parameters server_bda - server BDA of this cache. +** status - BTA_GATT_OK if full buffer of data, +** BTA_GATT_FAIL if an error has occurred. +** +** Returns void +** +*******************************************************************************/ +void bta_gattc_ci_cache_open(BD_ADDR server_bda, UINT16 evt, tBTA_GATT_STATUS status, + UINT16 conn_id) +{ + tBTA_GATTC_CI_EVT *p_evt; + UNUSED(server_bda); + + if ((p_evt = (tBTA_GATTC_CI_EVT *) GKI_getbuf(sizeof(tBTA_GATTC_CI_EVT))) != NULL) + { + p_evt->hdr.event = evt; + p_evt->hdr.layer_specific = conn_id; + + p_evt->status = status; + bta_sys_sendmsg(p_evt); + } +} + +/******************************************************************************* +** +** Function bta_gattc_ci_cache_load +** +** Description This function sends an event to BTA indicating the phone has +** load the servere cache and ready to send it to the stack. +** +** Parameters server_bda - server BDA of this cache. +** num_bytes_read - number of bytes read into the buffer +** specified in the read callout-function. +** status - BTA_GATT_OK if full buffer of data, +** BTA_GATT_FAIL if an error has occurred. +** +** Returns void +** +*******************************************************************************/ +void bta_gattc_ci_cache_load(BD_ADDR server_bda, UINT16 evt, UINT16 num_attr, + tBTA_GATTC_NV_ATTR *p_attr, tBTA_GATT_STATUS status, + UINT16 conn_id) +{ + tBTA_GATTC_CI_LOAD *p_evt; + UNUSED(server_bda); + + if ((p_evt = (tBTA_GATTC_CI_LOAD *) GKI_getbuf(sizeof(tBTA_GATTC_CI_LOAD))) != NULL) + { + memset(p_evt, 0, sizeof(tBTA_GATTC_CI_LOAD)); + + p_evt->hdr.event = evt; + p_evt->hdr.layer_specific = conn_id; + + p_evt->status = status; + p_evt->num_attr = (num_attr > BTA_GATTC_NV_LOAD_MAX) ? BTA_GATTC_NV_LOAD_MAX : num_attr; + + if (p_evt->num_attr > 0 && p_attr != NULL) + { + memcpy(p_evt->attr, p_attr, p_evt->num_attr * sizeof(tBTA_GATTC_NV_ATTR)); + } + + bta_sys_sendmsg(p_evt); + } +} + +/******************************************************************************* +** +** Function bta_gattc_ci_cache_save +** +** Description This function sends an event to BTA indicating the phone has +** save the servere cache. +** +** Parameters server_bda - server BDA of this cache. +** evt - callin event code. +** status - BTA_GATT_OK if full buffer of data, +** BTA_GATT_ERROR if an error has occurred. +*8 conn_id - for this NV operation for. +** +** Returns void +** +*******************************************************************************/ +void bta_gattc_ci_cache_save(BD_ADDR server_bda, UINT16 evt, tBTA_GATT_STATUS status, + UINT16 conn_id) +{ + tBTA_GATTC_CI_EVT *p_evt; + UNUSED(server_bda); + + if ((p_evt = (tBTA_GATTC_CI_EVT *) GKI_getbuf(sizeof(tBTA_GATTC_CI_EVT))) != NULL) + { + p_evt->hdr.event = evt; + p_evt->hdr.layer_specific = conn_id; + + p_evt->status = status; + bta_sys_sendmsg(p_evt); + } +} +#endif /* BTA_GATT_INCLUDED */ diff --git a/components/bt/bluedroid/bta/gatt/bta_gattc_main.c b/components/bt/bluedroid/bta/gatt/bta_gattc_main.c new file mode 100755 index 0000000000..7885fa6858 --- /dev/null +++ b/components/bt/bluedroid/bta/gatt/bta_gattc_main.c @@ -0,0 +1,542 @@ +/****************************************************************************** + * + * Copyright (C) 2003-2012 Broadcom Corporation + * + * 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 GATT client main functions and state machine. + * + ******************************************************************************/ + +#include "bt_target.h" + +#if defined(BTA_GATT_INCLUDED) && (BTA_GATT_INCLUDED == TRUE) + +#include + +#include "bta_gattc_int.h" +#include "gki.h" + + +/***************************************************************************** +** Constants and types +*****************************************************************************/ + + +/* state machine action enumeration list */ +enum +{ + BTA_GATTC_OPEN, + BTA_GATTC_OPEN_FAIL, + BTA_GATTC_OPEN_ERROR, + BTA_GATTC_CANCEL_OPEN, + BTA_GATTC_CANCEL_OPEN_OK, + BTA_GATTC_CANCEL_OPEN_ERROR, + BTA_GATTC_CONN, + BTA_GATTC_START_DISCOVER, + BTA_GATTC_DISC_CMPL, + + BTA_GATTC_Q_CMD, + BTA_GATTC_CLOSE, + BTA_GATTC_CLOSE_FAIL, + BTA_GATTC_READ, + BTA_GATTC_WRITE, + + BTA_GATTC_OP_CMPL, + BTA_GATTC_SEARCH, + BTA_GATTC_FAIL, + BTA_GATTC_CONFIRM, + BTA_GATTC_EXEC, + BTA_GATTC_READ_MULTI, + BTA_GATTC_CI_OPEN, + BTA_GATTC_CI_LOAD, + BTA_GATTC_CI_SAVE, + BTA_GATTC_CACHE_OPEN, + BTA_GATTC_IGNORE_OP_CMPL, + BTA_GATTC_DISC_CLOSE, + BTA_GATTC_RESTART_DISCOVER, + BTA_GATTC_CFG_MTU, + + BTA_GATTC_IGNORE +}; +/* type for action functions */ +typedef void (*tBTA_GATTC_ACTION)(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data); + +/* action function list */ +const tBTA_GATTC_ACTION bta_gattc_action[] = +{ + bta_gattc_open, + bta_gattc_open_fail, + bta_gattc_open_error, + bta_gattc_cancel_open, + bta_gattc_cancel_open_ok, + bta_gattc_cancel_open_error, + bta_gattc_conn, + bta_gattc_start_discover, + bta_gattc_disc_cmpl, + + bta_gattc_q_cmd, + bta_gattc_close, + bta_gattc_close_fail, + bta_gattc_read, + bta_gattc_write, + + bta_gattc_op_cmpl, + bta_gattc_search, + bta_gattc_fail, + bta_gattc_confirm, + bta_gattc_execute, + bta_gattc_read_multi, + bta_gattc_ci_open, + bta_gattc_ci_load, + bta_gattc_ci_save, + bta_gattc_cache_open, + bta_gattc_ignore_op_cmpl, + bta_gattc_disc_close, + bta_gattc_restart_discover, + bta_gattc_cfg_mtu +}; + + +/* state table information */ +#define BTA_GATTC_ACTIONS 1 /* number of actions */ +#define BTA_GATTC_NEXT_STATE 1 /* position of next state */ +#define BTA_GATTC_NUM_COLS 2 /* number of columns in state tables */ + +/* state table for idle state */ +static const UINT8 bta_gattc_st_idle[][BTA_GATTC_NUM_COLS] = +{ +/* Event Action 1 Next state */ +/* BTA_GATTC_API_OPEN_EVT */ {BTA_GATTC_OPEN, BTA_GATTC_W4_CONN_ST}, +/* BTA_GATTC_INT_OPEN_FAIL_EVT */ {BTA_GATTC_IGNORE, BTA_GATTC_IDLE_ST}, +/* BTA_GATTC_API_CANCEL_OPEN_EVT */ {BTA_GATTC_IGNORE, BTA_GATTC_IDLE_ST}, +/* BTA_GATTC_INT_CANCEL_OPEN_OK_EVT */ {BTA_GATTC_IGNORE, BTA_GATTC_IDLE_ST}, + +/* BTA_GATTC_API_READ_EVT */ {BTA_GATTC_FAIL, BTA_GATTC_IDLE_ST}, +/* BTA_GATTC_API_WRITE_EVT */ {BTA_GATTC_FAIL, BTA_GATTC_IDLE_ST}, +/* BTA_GATTC_API_EXEC_EVT */ {BTA_GATTC_FAIL, BTA_GATTC_IDLE_ST}, +/* BTA_GATTC_API_CFG_MTU_EVT */ {BTA_GATTC_IGNORE, BTA_GATTC_IDLE_ST}, + +/* BTA_GATTC_API_CLOSE_EVT */ {BTA_GATTC_CLOSE_FAIL, BTA_GATTC_IDLE_ST}, + +/* BTA_GATTC_API_SEARCH_EVT */ {BTA_GATTC_FAIL, BTA_GATTC_IDLE_ST}, +/* BTA_GATTC_API_CONFIRM_EVT */ {BTA_GATTC_FAIL, BTA_GATTC_IDLE_ST}, +/* BTA_GATTC_API_READ_MULTI_EVT */ {BTA_GATTC_FAIL, BTA_GATTC_IDLE_ST}, +/* BTA_GATTC_API_REFRESH_EVT */ {BTA_GATTC_IGNORE, BTA_GATTC_IDLE_ST}, + +/* BTA_GATTC_INT_CONN_EVT */ {BTA_GATTC_CONN, BTA_GATTC_CONN_ST}, +/* BTA_GATTC_INT_DISCOVER_EVT */ {BTA_GATTC_IGNORE, BTA_GATTC_IDLE_ST}, +/* BTA_GATTC_DISCOVER_CMPL_EVT */ {BTA_GATTC_IGNORE, BTA_GATTC_IDLE_ST}, +/* BTA_GATTC_OP_CMPL_EVT */ {BTA_GATTC_IGNORE, BTA_GATTC_IDLE_ST}, +/* BTA_GATTC_INT_DISCONN_EVT */ {BTA_GATTC_IGNORE, BTA_GATTC_IDLE_ST}, + + +/* ===> for cache loading, saving */ +/* BTA_GATTC_START_CACHE_EVT */ {BTA_GATTC_IGNORE, BTA_GATTC_IDLE_ST}, +/* BTA_GATTC_CI_CACHE_OPEN_EVT */ {BTA_GATTC_IGNORE, BTA_GATTC_IDLE_ST}, +/* BTA_GATTC_CI_CACHE_LOAD_EVT */ {BTA_GATTC_IGNORE, BTA_GATTC_IDLE_ST}, +/* BTA_GATTC_CI_CACHE_SAVE_EVT */ {BTA_GATTC_IGNORE, BTA_GATTC_IDLE_ST} +}; + +/* state table for wait for open state */ +static const UINT8 bta_gattc_st_w4_conn[][BTA_GATTC_NUM_COLS] = +{ +/* Event Action 1 Next state */ +/* BTA_GATTC_API_OPEN_EVT */ {BTA_GATTC_OPEN, BTA_GATTC_W4_CONN_ST}, +/* BTA_GATTC_INT_OPEN_FAIL_EVT */ {BTA_GATTC_OPEN_FAIL, BTA_GATTC_IDLE_ST}, +/* BTA_GATTC_API_CANCEL_OPEN_EVT */ {BTA_GATTC_CANCEL_OPEN, BTA_GATTC_W4_CONN_ST}, +/* BTA_GATTC_INT_CANCEL_OPEN_OK_EVT */ {BTA_GATTC_CANCEL_OPEN_OK, BTA_GATTC_IDLE_ST}, + +/* BTA_GATTC_API_READ_EVT */ {BTA_GATTC_FAIL, BTA_GATTC_W4_CONN_ST}, +/* BTA_GATTC_API_WRITE_EVT */ {BTA_GATTC_FAIL, BTA_GATTC_W4_CONN_ST}, +/* BTA_GATTC_API_EXEC_EVT */ {BTA_GATTC_FAIL, BTA_GATTC_W4_CONN_ST}, +/* BTA_GATTC_API_CFG_MTU_EVT */ {BTA_GATTC_IGNORE, BTA_GATTC_W4_CONN_ST}, + +/* BTA_GATTC_API_CLOSE_EVT */ {BTA_GATTC_CANCEL_OPEN, BTA_GATTC_W4_CONN_ST}, + +/* BTA_GATTC_API_SEARCH_EVT */ {BTA_GATTC_FAIL, BTA_GATTC_W4_CONN_ST}, +/* BTA_GATTC_API_CONFIRM_EVT */ {BTA_GATTC_FAIL, BTA_GATTC_W4_CONN_ST}, +/* BTA_GATTC_API_READ_MULTI_EVT */ {BTA_GATTC_FAIL, BTA_GATTC_W4_CONN_ST}, +/* BTA_GATTC_API_REFRESH_EVT */ {BTA_GATTC_IGNORE, BTA_GATTC_W4_CONN_ST}, + +/* BTA_GATTC_INT_CONN_EVT */ {BTA_GATTC_CONN, BTA_GATTC_CONN_ST}, +/* BTA_GATTC_INT_DISCOVER_EVT */ {BTA_GATTC_IGNORE, BTA_GATTC_W4_CONN_ST}, +/* BTA_GATTC_DISCOVER_CMPL_EVT */ {BTA_GATTC_IGNORE, BTA_GATTC_W4_CONN_ST}, +/* BTA_GATTC_OP_CMPL_EVT */ {BTA_GATTC_IGNORE, BTA_GATTC_W4_CONN_ST}, +/* BTA_GATTC_INT_DISCONN_EVT */ {BTA_GATTC_OPEN_FAIL, BTA_GATTC_IDLE_ST}, + +/* ===> for cache loading, saving */ +/* BTA_GATTC_START_CACHE_EVT */ {BTA_GATTC_IGNORE, BTA_GATTC_W4_CONN_ST}, +/* BTA_GATTC_CI_CACHE_OPEN_EVT */ {BTA_GATTC_IGNORE, BTA_GATTC_W4_CONN_ST}, +/* BTA_GATTC_CI_CACHE_LOAD_EVT */ {BTA_GATTC_IGNORE, BTA_GATTC_W4_CONN_ST}, +/* BTA_GATTC_CI_CACHE_SAVE_EVT */ {BTA_GATTC_IGNORE, BTA_GATTC_W4_CONN_ST} +}; + +/* state table for open state */ +static const UINT8 bta_gattc_st_connected[][BTA_GATTC_NUM_COLS] = +{ +/* Event Action 1 Next state */ +/* BTA_GATTC_API_OPEN_EVT */ {BTA_GATTC_OPEN, BTA_GATTC_CONN_ST}, +/* BTA_GATTC_INT_OPEN_FAIL_EVT */ {BTA_GATTC_IGNORE, BTA_GATTC_CONN_ST}, +/* BTA_GATTC_API_CANCEL_OPEN_EVT */ {BTA_GATTC_CANCEL_OPEN_ERROR, BTA_GATTC_CONN_ST}, +/* BTA_GATTC_INT_CANCEL_OPEN_OK_EVT */ {BTA_GATTC_IGNORE, BTA_GATTC_CONN_ST}, + +/* BTA_GATTC_API_READ_EVT */ {BTA_GATTC_READ, BTA_GATTC_CONN_ST}, +/* BTA_GATTC_API_WRITE_EVT */ {BTA_GATTC_WRITE, BTA_GATTC_CONN_ST}, +/* BTA_GATTC_API_EXEC_EVT */ {BTA_GATTC_EXEC, BTA_GATTC_CONN_ST}, +/* BTA_GATTC_API_CFG_MTU_EVT */ {BTA_GATTC_CFG_MTU, BTA_GATTC_CONN_ST}, + +/* BTA_GATTC_API_CLOSE_EVT */ {BTA_GATTC_CLOSE, BTA_GATTC_IDLE_ST}, + +/* BTA_GATTC_API_SEARCH_EVT */ {BTA_GATTC_SEARCH, BTA_GATTC_CONN_ST}, +/* BTA_GATTC_API_CONFIRM_EVT */ {BTA_GATTC_CONFIRM, BTA_GATTC_CONN_ST}, +/* BTA_GATTC_API_READ_MULTI_EVT */ {BTA_GATTC_READ_MULTI, BTA_GATTC_CONN_ST}, +/* BTA_GATTC_API_REFRESH_EVT */ {BTA_GATTC_IGNORE, BTA_GATTC_CONN_ST}, + +/* BTA_GATTC_INT_CONN_EVT */ {BTA_GATTC_IGNORE, BTA_GATTC_CONN_ST}, +/* BTA_GATTC_INT_DISCOVER_EVT */ {BTA_GATTC_START_DISCOVER, BTA_GATTC_DISCOVER_ST}, +/* BTA_GATTC_DISCOVER_CMPL_EVT */ {BTA_GATTC_IGNORE, BTA_GATTC_CONN_ST}, +/* BTA_GATTC_OP_CMPL_EVT */ {BTA_GATTC_OP_CMPL, BTA_GATTC_CONN_ST}, + +/* BTA_GATTC_INT_DISCONN_EVT */ {BTA_GATTC_CLOSE, BTA_GATTC_IDLE_ST}, + +/* ===> for cache loading, saving */ +/* BTA_GATTC_START_CACHE_EVT */ {BTA_GATTC_CACHE_OPEN, BTA_GATTC_DISCOVER_ST}, +/* BTA_GATTC_CI_CACHE_OPEN_EVT */ {BTA_GATTC_IGNORE, BTA_GATTC_CONN_ST}, +/* BTA_GATTC_CI_CACHE_LOAD_EVT */ {BTA_GATTC_IGNORE, BTA_GATTC_CONN_ST}, +/* BTA_GATTC_CI_CACHE_SAVE_EVT */ {BTA_GATTC_IGNORE, BTA_GATTC_CONN_ST} +}; + +/* state table for discover state */ +static const UINT8 bta_gattc_st_discover[][BTA_GATTC_NUM_COLS] = +{ +/* Event Action 1 Next state */ +/* BTA_GATTC_API_OPEN_EVT */ {BTA_GATTC_OPEN, BTA_GATTC_DISCOVER_ST}, +/* BTA_GATTC_INT_OPEN_FAIL_EVT */ {BTA_GATTC_IGNORE, BTA_GATTC_DISCOVER_ST}, +/* BTA_GATTC_API_CANCEL_OPEN_EVT */ {BTA_GATTC_CANCEL_OPEN_ERROR, BTA_GATTC_DISCOVER_ST}, +/* BTA_GATTC_INT_CANCEL_OPEN_OK_EVT */ {BTA_GATTC_FAIL, BTA_GATTC_DISCOVER_ST}, + +/* BTA_GATTC_API_READ_EVT */ {BTA_GATTC_Q_CMD, BTA_GATTC_DISCOVER_ST}, +/* BTA_GATTC_API_WRITE_EVT */ {BTA_GATTC_Q_CMD, BTA_GATTC_DISCOVER_ST}, +/* BTA_GATTC_API_EXEC_EVT */ {BTA_GATTC_Q_CMD, BTA_GATTC_DISCOVER_ST}, +/* BTA_GATTC_API_CFG_MTU_EVT */ {BTA_GATTC_Q_CMD, BTA_GATTC_DISCOVER_ST}, + +/* BTA_GATTC_API_CLOSE_EVT */ {BTA_GATTC_DISC_CLOSE, BTA_GATTC_DISCOVER_ST}, + +/* BTA_GATTC_API_SEARCH_EVT */ {BTA_GATTC_Q_CMD, BTA_GATTC_DISCOVER_ST}, +/* BTA_GATTC_API_CONFIRM_EVT */ {BTA_GATTC_CONFIRM, BTA_GATTC_DISCOVER_ST}, +/* BTA_GATTC_API_READ_MULTI_EVT */ {BTA_GATTC_Q_CMD, BTA_GATTC_DISCOVER_ST}, +/* BTA_GATTC_API_REFRESH_EVT */ {BTA_GATTC_IGNORE, BTA_GATTC_DISCOVER_ST}, + +/* BTA_GATTC_INT_CONN_EVT */ {BTA_GATTC_CONN, BTA_GATTC_DISCOVER_ST}, +/* BTA_GATTC_INT_DISCOVER_EVT */ {BTA_GATTC_RESTART_DISCOVER, BTA_GATTC_DISCOVER_ST}, +/* BTA_GATTC_DISCOVER_CMPL_EVT */ {BTA_GATTC_DISC_CMPL, BTA_GATTC_CONN_ST}, +/* BTA_GATTC_OP_CMPL_EVT */ {BTA_GATTC_IGNORE_OP_CMPL, BTA_GATTC_DISCOVER_ST}, +/* BTA_GATTC_INT_DISCONN_EVT */ {BTA_GATTC_CLOSE, BTA_GATTC_IDLE_ST}, + +/* ===> for cache loading, saving */ +/* BTA_GATTC_START_CACHE_EVT */ {BTA_GATTC_IGNORE, BTA_GATTC_DISCOVER_ST}, +/* BTA_GATTC_CI_CACHE_OPEN_EVT */ {BTA_GATTC_CI_OPEN, BTA_GATTC_DISCOVER_ST}, +/* BTA_GATTC_CI_CACHE_LOAD_EVT */ {BTA_GATTC_CI_LOAD, BTA_GATTC_DISCOVER_ST}, +/* BTA_GATTC_CI_CACHE_SAVE_EVT */ {BTA_GATTC_CI_SAVE, BTA_GATTC_DISCOVER_ST} +}; + +/* type for state table */ +typedef const UINT8 (*tBTA_GATTC_ST_TBL)[BTA_GATTC_NUM_COLS]; + +/* state table */ +const tBTA_GATTC_ST_TBL bta_gattc_st_tbl[] = +{ + bta_gattc_st_idle, + bta_gattc_st_w4_conn, + bta_gattc_st_connected, + bta_gattc_st_discover +}; + +/***************************************************************************** +** Global data +*****************************************************************************/ + +/* GATTC control block */ +#if BTA_DYNAMIC_MEMORY == FALSE +tBTA_GATTC_CB bta_gattc_cb; +#endif + +#if BTA_GATT_DEBUG == TRUE +static char *gattc_evt_code(tBTA_GATTC_INT_EVT evt_code); +static char *gattc_state_code(tBTA_GATTC_STATE state_code); +#endif + +/******************************************************************************* +** +** Function bta_gattc_sm_execute +** +** Description State machine event handling function for GATTC +** +** +** Returns BOOLEAN : TRUE if queued client request buffer can be immediately released +** else FALSE +** +*******************************************************************************/ +BOOLEAN bta_gattc_sm_execute(tBTA_GATTC_CLCB *p_clcb, UINT16 event, tBTA_GATTC_DATA *p_data) +{ + tBTA_GATTC_ST_TBL state_table; + UINT8 action; + int i; + BOOLEAN rt = TRUE; +#if BTA_GATT_DEBUG == TRUE + tBTA_GATTC_STATE in_state = p_clcb->state; + UINT16 in_event = event; + APPL_TRACE_DEBUG("bta_gattc_sm_execute: State 0x%02x [%s], Event 0x%x[%s]", in_state, + gattc_state_code(in_state), + in_event, + gattc_evt_code(in_event)); +#endif + + + /* look up the state table for the current state */ + state_table = bta_gattc_st_tbl[p_clcb->state]; + + event &= 0x00FF; + + /* set next state */ + p_clcb->state = state_table[event][BTA_GATTC_NEXT_STATE]; + + /* execute action functions */ + for (i = 0; i < BTA_GATTC_ACTIONS; i++) + { + if ((action = state_table[event][i]) != BTA_GATTC_IGNORE) + { + (*bta_gattc_action[action])(p_clcb, p_data); + if (p_clcb->p_q_cmd == p_data) { + /* buffer is queued, don't free in the bta dispatcher. + * we free it ourselves when a completion event is received. + */ + rt = FALSE; + } + } + else + { + break; + } + } + +#if BTA_GATT_DEBUG == TRUE + if (in_state != p_clcb->state) + { + APPL_TRACE_DEBUG("GATTC State Change: [%s] -> [%s] after Event [%s]", + gattc_state_code(in_state), + gattc_state_code(p_clcb->state), + gattc_evt_code(in_event)); + } +#endif + return rt; +} + +/******************************************************************************* +** +** Function bta_gattc_hdl_event +** +** Description GATT client main event handling function. +** +** +** Returns BOOLEAN +** +*******************************************************************************/ +BOOLEAN bta_gattc_hdl_event(BT_HDR *p_msg) +{ + tBTA_GATTC_CB *p_cb = &bta_gattc_cb; + tBTA_GATTC_CLCB *p_clcb = NULL; + tBTA_GATTC_RCB *p_clreg; + BOOLEAN rt = TRUE; +#if BTA_GATT_DEBUG == TRUE + APPL_TRACE_DEBUG("bta_gattc_hdl_event: Event [%s]", gattc_evt_code(p_msg->event)); +#endif + switch (p_msg->event) + { + case BTA_GATTC_API_DISABLE_EVT: + bta_gattc_disable(p_cb); + break; + + case BTA_GATTC_API_REG_EVT: + bta_gattc_register(p_cb, (tBTA_GATTC_DATA *) p_msg); + break; + + case BTA_GATTC_INT_START_IF_EVT: + bta_gattc_start_if(p_cb, (tBTA_GATTC_DATA *) p_msg); + break; + + case BTA_GATTC_API_DEREG_EVT: + p_clreg = bta_gattc_cl_get_regcb(((tBTA_GATTC_DATA *)p_msg)->api_dereg.client_if); + bta_gattc_deregister(p_cb, p_clreg); + break; + + case BTA_GATTC_API_OPEN_EVT: + bta_gattc_process_api_open(p_cb, (tBTA_GATTC_DATA *) p_msg); + break; + + case BTA_GATTC_API_CANCEL_OPEN_EVT: + bta_gattc_process_api_open_cancel(p_cb, (tBTA_GATTC_DATA *) p_msg); + break; + + case BTA_GATTC_API_REFRESH_EVT: + bta_gattc_process_api_refresh(p_cb, (tBTA_GATTC_DATA *) p_msg); + break; + +#if BLE_INCLUDED == TRUE + case BTA_GATTC_API_LISTEN_EVT: + bta_gattc_listen(p_cb, (tBTA_GATTC_DATA *) p_msg); + break; + case BTA_GATTC_API_BROADCAST_EVT: + bta_gattc_broadcast(p_cb, (tBTA_GATTC_DATA *) p_msg); + break; +#endif + + case BTA_GATTC_ENC_CMPL_EVT: + bta_gattc_process_enc_cmpl(p_cb, (tBTA_GATTC_DATA *) p_msg); + break; + + default: + if (p_msg->event == BTA_GATTC_INT_CONN_EVT) + p_clcb = bta_gattc_find_int_conn_clcb((tBTA_GATTC_DATA *) p_msg); + else if (p_msg->event == BTA_GATTC_INT_DISCONN_EVT) + p_clcb = bta_gattc_find_int_disconn_clcb((tBTA_GATTC_DATA *) p_msg); + else + p_clcb = bta_gattc_find_clcb_by_conn_id(p_msg->layer_specific); + + if (p_clcb != NULL) + { + rt = bta_gattc_sm_execute(p_clcb, p_msg->event, (tBTA_GATTC_DATA *) p_msg); + } + else + { + APPL_TRACE_DEBUG("Ignore unknown conn ID: %d", p_msg->layer_specific); + } + + break; + } + + + return rt; +} + + +/***************************************************************************** +** Debug Functions +*****************************************************************************/ +#if BTA_GATT_DEBUG == TRUE + +/******************************************************************************* +** +** Function gattc_evt_code +** +** Description +** +** Returns void +** +*******************************************************************************/ +static char *gattc_evt_code(tBTA_GATTC_INT_EVT evt_code) +{ + switch (evt_code) + { + case BTA_GATTC_API_OPEN_EVT: + return "BTA_GATTC_API_OPEN_EVT"; + case BTA_GATTC_INT_OPEN_FAIL_EVT: + return "BTA_GATTC_INT_OPEN_FAIL_EVT"; + case BTA_GATTC_API_CANCEL_OPEN_EVT: + return "BTA_GATTC_API_CANCEL_OPEN_EVT"; + case BTA_GATTC_INT_CANCEL_OPEN_OK_EVT: + return "BTA_GATTC_INT_CANCEL_OPEN_OK_EVT"; + case BTA_GATTC_API_READ_EVT: + return "BTA_GATTC_API_READ_EVT"; + case BTA_GATTC_API_WRITE_EVT: + return "BTA_GATTC_API_WRITE_EVT"; + case BTA_GATTC_API_EXEC_EVT: + return "BTA_GATTC_API_EXEC_EVT"; + case BTA_GATTC_API_CLOSE_EVT: + return "BTA_GATTC_API_CLOSE_EVT"; + case BTA_GATTC_API_SEARCH_EVT: + return "BTA_GATTC_API_SEARCH_EVT"; + case BTA_GATTC_API_CONFIRM_EVT: + return "BTA_GATTC_API_CONFIRM_EVT"; + case BTA_GATTC_API_READ_MULTI_EVT: + return "BTA_GATTC_API_READ_MULTI_EVT"; + case BTA_GATTC_INT_CONN_EVT: + return "BTA_GATTC_INT_CONN_EVT"; + case BTA_GATTC_INT_DISCOVER_EVT: + return "BTA_GATTC_INT_DISCOVER_EVT"; + case BTA_GATTC_DISCOVER_CMPL_EVT: + return "BTA_GATTC_DISCOVER_CMPL_EVT"; + case BTA_GATTC_OP_CMPL_EVT: + return "BTA_GATTC_OP_CMPL_EVT"; + case BTA_GATTC_INT_DISCONN_EVT: + return "BTA_GATTC_INT_DISCONN_EVT"; + case BTA_GATTC_START_CACHE_EVT: + return "BTA_GATTC_START_CACHE_EVT"; + case BTA_GATTC_CI_CACHE_OPEN_EVT: + return "BTA_GATTC_CI_CACHE_OPEN_EVT"; + case BTA_GATTC_CI_CACHE_LOAD_EVT: + return "BTA_GATTC_CI_CACHE_LOAD_EVT"; + case BTA_GATTC_CI_CACHE_SAVE_EVT: + return "BTA_GATTC_CI_CACHE_SAVE_EVT"; + case BTA_GATTC_INT_START_IF_EVT: + return "BTA_GATTC_INT_START_IF_EVT"; + case BTA_GATTC_API_REG_EVT: + return "BTA_GATTC_API_REG_EVT"; + case BTA_GATTC_API_DEREG_EVT: + return "BTA_GATTC_API_DEREG_EVT"; + case BTA_GATTC_API_REFRESH_EVT: + return "BTA_GATTC_API_REFRESH_EVT"; + case BTA_GATTC_API_LISTEN_EVT: + return "BTA_GATTC_API_LISTEN_EVT"; + case BTA_GATTC_API_DISABLE_EVT: + return "BTA_GATTC_API_DISABLE_EVT"; + case BTA_GATTC_API_CFG_MTU_EVT: + return "BTA_GATTC_API_CFG_MTU_EVT"; + default: + return "unknown GATTC event code"; + } +} + +/******************************************************************************* +** +** Function gattc_state_code +** +** Description +** +** Returns void +** +*******************************************************************************/ +static char *gattc_state_code(tBTA_GATTC_STATE state_code) +{ + switch (state_code) + { + case BTA_GATTC_IDLE_ST: + return "GATTC_IDLE_ST"; + case BTA_GATTC_W4_CONN_ST: + return "GATTC_W4_CONN_ST"; + case BTA_GATTC_CONN_ST: + return "GATTC_CONN_ST"; + case BTA_GATTC_DISCOVER_ST: + return "GATTC_DISCOVER_ST"; + default: + return "unknown GATTC state code"; + } +} + +#endif /* Debug Functions */ +#endif /* BTA_GATT_INCLUDED */ diff --git a/components/bt/bluedroid/bta/gatt/bta_gattc_utils.c b/components/bt/bluedroid/bta/gatt/bta_gattc_utils.c new file mode 100755 index 0000000000..3d99f6e671 --- /dev/null +++ b/components/bt/bluedroid/bta/gatt/bta_gattc_utils.c @@ -0,0 +1,973 @@ +/****************************************************************************** + * + * Copyright (C) 2003-2012 Broadcom Corporation + * + * 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 GATT client utility function. + * + ******************************************************************************/ + +#include "bt_target.h" + +#if defined(BTA_GATT_INCLUDED) && (BTA_GATT_INCLUDED == TRUE) + +#include + +#include "bdaddr.h" +// #include "btif/include/btif_util.h" +#include "gki.h" +#include "utl.h" +#include "bta_sys.h" +#include "bta_gattc_int.h" +#include "l2c_api.h" + +#define LOG_TAG "bt_bta_gattc" +/***************************************************************************** +** Constants +*****************************************************************************/ + + +static const UINT8 base_uuid[LEN_UUID_128] = {0xFB, 0x34, 0x9B, 0x5F, 0x80, 0x00, 0x00, 0x80, + 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + +static const BD_ADDR dummy_bda = {0,0,0,0,0,0}; + +/******************************************************************************* +** +** Function bta_gatt_convert_uuid16_to_uuid128 +** +** Description Convert a 16 bits UUID to be an standard 128 bits one. +** +** Returns TRUE if two uuid match; FALSE otherwise. +** +*******************************************************************************/ +void bta_gatt_convert_uuid16_to_uuid128(UINT8 uuid_128[LEN_UUID_128], UINT16 uuid_16) +{ + UINT8 *p = &uuid_128[LEN_UUID_128 - 4]; + + memcpy (uuid_128, base_uuid, LEN_UUID_128); + + UINT16_TO_STREAM(p, uuid_16); +} +/******************************************************************************* +** +** Function bta_gattc_uuid_compare +** +** Description Compare two UUID to see if they are the same. +** +** Returns TRUE if two uuid match; FALSE otherwise. +** +*******************************************************************************/ +BOOLEAN bta_gattc_uuid_compare (tBT_UUID *p_src, tBT_UUID *p_tar, BOOLEAN is_precise) +{ + UINT8 su[LEN_UUID_128], tu[LEN_UUID_128]; + UINT8 *ps, *pt; + + /* any of the UUID is unspecified */ + if (p_src == 0 || p_tar == 0) + { + if (is_precise) + return FALSE; + else + return TRUE; + } + + /* If both are 16-bit, we can do a simple compare */ + if (p_src->len == 2 && p_tar->len == 2) + { + return p_src->uu.uuid16 == p_tar->uu.uuid16; + } + + /* One or both of the UUIDs is 128-bit */ + if (p_src->len == LEN_UUID_16) + { + /* convert a 16 bits UUID to 128 bits value */ + bta_gatt_convert_uuid16_to_uuid128(su, p_src->uu.uuid16); + ps = su; + } + else + ps = p_src->uu.uuid128; + + if (p_tar->len == LEN_UUID_16) + { + /* convert a 16 bits UUID to 128 bits value */ + bta_gatt_convert_uuid16_to_uuid128(tu, p_tar->uu.uuid16); + pt = tu; + } + else + pt = p_tar->uu.uuid128; + + return(memcmp(ps, pt, LEN_UUID_128) == 0); +} + +/******************************************************************************* +** +** Function bta_gattc_cl_get_regcb +** +** Description get registration control block by client interface. +** +** Returns pointer to the regcb +** +*******************************************************************************/ +tBTA_GATTC_RCB * bta_gattc_cl_get_regcb(UINT8 client_if) +{ + UINT8 i = 0; + tBTA_GATTC_RCB *p_clrcb = &bta_gattc_cb.cl_rcb[0]; + + for (i = 0; i < BTA_GATTC_CL_MAX; i ++, p_clrcb ++) + { + if (p_clrcb->in_use && + p_clrcb->client_if == client_if) + return p_clrcb; + } + return NULL; +} +/******************************************************************************* +** +** Function bta_gattc_num_reg_app +** +** Description find the number of registered application. +** +** Returns pointer to the regcb +** +*******************************************************************************/ +UINT8 bta_gattc_num_reg_app(void) +{ + UINT8 i = 0, j = 0; + + for (i = 0; i < BTA_GATTC_CL_MAX; i ++) + { + if (bta_gattc_cb.cl_rcb[i].in_use) + j ++; + } + return j; +} +/******************************************************************************* +** +** Function bta_gattc_find_clcb_by_cif +** +** Description get clcb by client interface and remote bd adddress +** +** Returns pointer to the clcb +** +*******************************************************************************/ +tBTA_GATTC_CLCB * bta_gattc_find_clcb_by_cif (UINT8 client_if, BD_ADDR remote_bda, + tBTA_TRANSPORT transport) +{ + tBTA_GATTC_CLCB *p_clcb = &bta_gattc_cb.clcb[0]; + UINT8 i; + + for (i = 0; i < BTA_GATTC_CLCB_MAX; i ++, p_clcb ++) + { + if (p_clcb->in_use && + p_clcb->p_rcb->client_if == client_if && + p_clcb->transport == transport && + bdcmp(p_clcb->bda, remote_bda) == 0) + return p_clcb; + } + return NULL; +} +/******************************************************************************* +** +** Function bta_gattc_find_clcb_by_conn_id +** +** Description get clcb by connection ID +** +** Returns pointer to the clcb +** +*******************************************************************************/ +tBTA_GATTC_CLCB * bta_gattc_find_clcb_by_conn_id (UINT16 conn_id) +{ + tBTA_GATTC_CLCB *p_clcb = &bta_gattc_cb.clcb[0]; + UINT8 i; + + for (i = 0; i < BTA_GATTC_CLCB_MAX; i ++, p_clcb ++) + { + if (p_clcb->in_use && + p_clcb->bta_conn_id == conn_id) + return p_clcb; + } + return NULL; +} + +/******************************************************************************* +** +** Function bta_gattc_clcb_alloc +** +** Description allocate CLCB +** +** Returns pointer to the clcb +** +*******************************************************************************/ +tBTA_GATTC_CLCB * bta_gattc_clcb_alloc(tBTA_GATTC_IF client_if, BD_ADDR remote_bda, + tBTA_TRANSPORT transport) +{ + UINT8 i_clcb = 0; + tBTA_GATTC_CLCB *p_clcb = NULL; + + for (i_clcb = 0; i_clcb < BTA_GATTC_CLCB_MAX; i_clcb++) + { + if (!bta_gattc_cb.clcb[i_clcb].in_use) + { +#if BTA_GATT_DEBUG == TRUE + APPL_TRACE_DEBUG("bta_gattc_clcb_alloc: found clcb[%d] available",i_clcb); +#endif + p_clcb = &bta_gattc_cb.clcb[i_clcb]; + p_clcb->in_use = TRUE; + p_clcb->status = BTA_GATT_OK; + p_clcb->transport = transport; + bdcpy(p_clcb->bda, remote_bda); + + p_clcb->p_rcb = bta_gattc_cl_get_regcb(client_if); + + if ((p_clcb->p_srcb = bta_gattc_find_srcb(remote_bda)) == NULL) + p_clcb->p_srcb = bta_gattc_srcb_alloc(remote_bda); + + if (p_clcb->p_rcb != NULL && p_clcb->p_srcb != NULL) + { + p_clcb->p_srcb->num_clcb ++; + p_clcb->p_rcb->num_clcb ++; + } + else + { + /* release this clcb if clcb or srcb allocation failed */ + p_clcb->in_use = FALSE; + p_clcb = NULL; + } + break; + } + } + return p_clcb; +} +/******************************************************************************* +** +** Function bta_gattc_find_alloc_clcb +** +** Description find or allocate CLCB if not found. +** +** Returns pointer to the clcb +** +*******************************************************************************/ +tBTA_GATTC_CLCB *bta_gattc_find_alloc_clcb(tBTA_GATTC_IF client_if, BD_ADDR remote_bda, + tBTA_TRANSPORT transport) +{ + tBTA_GATTC_CLCB *p_clcb ; + + if ((p_clcb = bta_gattc_find_clcb_by_cif(client_if, remote_bda, transport)) == NULL) + { + p_clcb = bta_gattc_clcb_alloc(client_if, remote_bda, transport); + } + return p_clcb; +} + +/******************************************************************************* +** +** Function bta_gattc_clcb_dealloc +** +** Description Deallocte a clcb +** +** Returns pointer to the clcb +** +*******************************************************************************/ +void bta_gattc_clcb_dealloc(tBTA_GATTC_CLCB *p_clcb) +{ + tBTA_GATTC_SERV *p_srcb = NULL; + + if (p_clcb) + { + p_srcb = p_clcb->p_srcb; + if (p_srcb->num_clcb) + p_srcb->num_clcb --; + + if (p_clcb->p_rcb->num_clcb) + p_clcb->p_rcb->num_clcb --; + + /* if the srcb is no longer needed, reset the state */ + if ( p_srcb->num_clcb == 0) + { + p_srcb->connected = FALSE; + p_srcb->state = BTA_GATTC_SERV_IDLE; + p_srcb->mtu = 0; + } + + utl_freebuf((void **)&p_clcb->p_q_cmd); + + memset(p_clcb, 0, sizeof(tBTA_GATTC_CLCB)); + } + else + { + APPL_TRACE_ERROR("bta_gattc_clcb_dealloc p_clcb=NULL"); + } +} + +/******************************************************************************* +** +** Function bta_gattc_find_srcb +** +** Description find server cache by remote bd address currently in use +** +** Returns pointer to the server cache. +** +*******************************************************************************/ +tBTA_GATTC_SERV * bta_gattc_find_srcb(BD_ADDR bda) +{ + tBTA_GATTC_SERV *p_srcb = &bta_gattc_cb.known_server[0]; + UINT8 i; + + for (i = 0; i < BTA_GATTC_KNOWN_SR_MAX; i ++, p_srcb ++) + { + if (p_srcb->in_use && bdcmp(p_srcb->server_bda, bda) == 0) + return p_srcb; + } + return NULL; +} + +/******************************************************************************* +** +** Function bta_gattc_find_srvr_cache +** +** Description find server cache by remote bd address +** +** Returns pointer to the server cache. +** +*******************************************************************************/ +tBTA_GATTC_SERV * bta_gattc_find_srvr_cache(BD_ADDR bda) +{ + tBTA_GATTC_SERV *p_srcb = &bta_gattc_cb.known_server[0]; + UINT8 i; + + for (i = 0; i < BTA_GATTC_KNOWN_SR_MAX; i ++, p_srcb ++) + { + if (bdcmp(p_srcb->server_bda, bda) == 0) + return p_srcb; + } + return NULL; +} +/******************************************************************************* +** +** Function bta_gattc_find_scb_by_cid +** +** Description find server control block by connection ID +** +** Returns pointer to the server cache. +** +*******************************************************************************/ +tBTA_GATTC_SERV * bta_gattc_find_scb_by_cid (UINT16 conn_id) +{ + tBTA_GATTC_CLCB *p_clcb = bta_gattc_find_clcb_by_conn_id(conn_id); + + if (p_clcb) + return p_clcb->p_srcb; + else + return NULL; +} +/******************************************************************************* +** +** Function bta_gattc_srcb_alloc +** +** Description allocate server cache control block +** +** Returns pointer to the server cache. +** +*******************************************************************************/ +tBTA_GATTC_SERV * bta_gattc_srcb_alloc(BD_ADDR bda) +{ + tBTA_GATTC_SERV *p_tcb = &bta_gattc_cb.known_server[0], + *p_recycle = NULL; + BOOLEAN found = FALSE; + UINT8 i; + + for (i = 0; i < BTA_GATTC_KNOWN_SR_MAX; i ++, p_tcb ++) + { + if (!p_tcb->in_use) + { + found = TRUE; + break; + } + else if (!p_tcb->connected) + { + p_recycle = p_tcb; + } + } + + /* if not found, try to recycle one known device */ + if (!found && !p_recycle) + p_tcb = NULL; + else if (!found && p_recycle) + p_tcb = p_recycle; + + if (p_tcb != NULL) + { + while (!GKI_queue_is_empty(&p_tcb->cache_buffer)) + GKI_freebuf (GKI_dequeue (&p_tcb->cache_buffer)); + + utl_freebuf((void **)&p_tcb->p_srvc_list); + memset(p_tcb, 0 , sizeof(tBTA_GATTC_SERV)); + + p_tcb->in_use = TRUE; + bdcpy(p_tcb->server_bda, bda); + } + return p_tcb; +} +/******************************************************************************* +** +** Function bta_gattc_enqueue +** +** Description enqueue a client request in clcb. +** +** Returns success or failure. +** +*******************************************************************************/ +BOOLEAN bta_gattc_enqueue(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data) +{ + + if (p_clcb->p_q_cmd == NULL) + { + p_clcb->p_q_cmd = p_data; + } + else + { + APPL_TRACE_ERROR("already has a pending command!!"); + /* skip the callback now. ----- need to send callback ? */ + } + return (p_clcb->p_q_cmd != NULL) ? TRUE : FALSE; + +} + +/******************************************************************************* +** +** Function bta_gattc_pack_attr_uuid +** +** Description pack UUID into a stream. +** +** Returns +** +*******************************************************************************/ +void bta_gattc_pack_attr_uuid(tBTA_GATTC_CACHE_ATTR *p_attr, tBT_UUID *p_uuid) +{ + UINT8 *pp = (UINT8 *)p_attr->p_uuid; + + memset(p_uuid, 0, sizeof(tBT_UUID)); + + p_uuid->len = p_attr->uuid_len; + + if (p_attr->uuid_len == LEN_UUID_16) + { + STREAM_TO_UINT16(p_uuid->uu.uuid16, pp); + } + else + { + memcpy(p_uuid->uu.uuid128, pp, LEN_UUID_128); + } + + return; +} +/******************************************************************************* +** +** Function bta_gattc_cpygattid +** +** Description copy two tBTA_GATT_ID value +** +** Returns +** +*******************************************************************************/ +void bta_gattc_cpygattid(tBTA_GATT_ID *p_des, tBTA_GATT_ID *p_src) +{ + memset ((void *)p_des, 0, sizeof(tBTA_GATT_ID)); + + p_des->inst_id = p_src->inst_id; + + p_des->uuid.len = p_src->uuid.len; + + if (p_des->uuid.len == LEN_UUID_16) + { + p_des->uuid.uu.uuid16 = p_src->uuid.uu.uuid16; + } + else if (p_des->uuid.len == LEN_UUID_128) + { + memcpy(p_des->uuid.uu.uuid128, p_src->uuid.uu.uuid128, LEN_UUID_128); + } +} +/******************************************************************************* +** +** Function bta_gattc_gattid_compare +** +** Description compare two tBTA_GATT_ID type of pointer +** +** Returns +** +*******************************************************************************/ +BOOLEAN bta_gattc_gattid_compare(tBTA_GATT_ID *p_src, tBTA_GATT_ID *p_tar) +{ + if (p_src->inst_id == p_tar->inst_id && + bta_gattc_uuid_compare (&p_src->uuid, &p_tar->uuid, TRUE )) + return TRUE; + else + return FALSE; + +} +/******************************************************************************* +** +** Function bta_gattc_srvcid_compare +** +** Description compare two tBTA_GATT_SRVC_ID type of pointer +** +** Returns +** +*******************************************************************************/ +BOOLEAN bta_gattc_srvcid_compare(tBTA_GATT_SRVC_ID *p_src, tBTA_GATT_SRVC_ID *p_tar) +{ + if (p_src->is_primary == p_tar->is_primary && + bta_gattc_gattid_compare (&p_src->id, &p_tar->id)) + return TRUE; + else + return FALSE; +} +/******************************************************************************* +** +** Function bta_gattc_charid_compare +** +** Description compare two tBTA_GATTC_CHAR_ID type of pointer +** +** Returns +** +*******************************************************************************/ +BOOLEAN bta_gattc_charid_compare(tBTA_GATTC_CHAR_ID *p_src, tBTA_GATTC_CHAR_ID *p_tar) +{ + if (bta_gattc_gattid_compare (&p_src->char_id, &p_tar->char_id) && + bta_gattc_srvcid_compare (&p_src->srvc_id, &p_tar->srvc_id)) + return TRUE; + else + return FALSE; +} + +/******************************************************************************* +** +** Function bta_gattc_check_notif_registry +** +** Description check if the service notificaition has been registered. +** +** Returns +** +*******************************************************************************/ +BOOLEAN bta_gattc_check_notif_registry(tBTA_GATTC_RCB *p_clreg, tBTA_GATTC_SERV *p_srcb, + tBTA_GATTC_NOTIFY *p_notify) +{ + UINT8 i; + + for (i = 0 ; i < BTA_GATTC_NOTIF_REG_MAX; i ++) + { + if (p_clreg->notif_reg[i].in_use && + bdcmp(p_clreg->notif_reg[i].remote_bda, p_srcb->server_bda) == 0 && + bta_gattc_charid_compare (&p_clreg->notif_reg[i].char_id, &p_notify->char_id)) + { + APPL_TRACE_DEBUG("Notification registered!"); + return TRUE; + } + } + return FALSE; + +} +/******************************************************************************* +** +** Function bta_gattc_clear_notif_registration +** +** Description clear up the notification registration information by BD_ADDR. +** +** Returns None. +** +*******************************************************************************/ +void bta_gattc_clear_notif_registration(UINT16 conn_id) +{ + BD_ADDR remote_bda; + tBTA_GATTC_IF gatt_if; + tBTA_GATTC_RCB *p_clrcb ; + UINT8 i; + tGATT_TRANSPORT transport; + + if (GATT_GetConnectionInfor(conn_id, &gatt_if, remote_bda, &transport)) + { + if ((p_clrcb = bta_gattc_cl_get_regcb(gatt_if)) != NULL) + { + for (i = 0 ; i < BTA_GATTC_NOTIF_REG_MAX; i ++) + { + if (p_clrcb->notif_reg[i].in_use && + !bdcmp(p_clrcb->notif_reg[i].remote_bda, remote_bda)) + memset(&p_clrcb->notif_reg[i], 0, sizeof(tBTA_GATTC_NOTIF_REG)); + } + } + } + else + { + APPL_TRACE_ERROR("can not clear indication/notif registration for unknown app"); + } + return; +} + +/******************************************************************************* +** +** Function bta_gattc_pack_cb_data +** +** Description pack the data from read response into callback data structure. +** +** Returns +** +*******************************************************************************/ +tBTA_GATT_STATUS bta_gattc_pack_read_cb_data(tBTA_GATTC_SERV *p_srcb, + tBT_UUID *p_descr_uuid, + tGATT_VALUE *p_attr, + tBTA_GATT_READ_VAL *p_value) +{ + UINT8 i = 0, *pp = p_attr->value; + tBT_UUID uuid = {LEN_UUID_16, {GATT_UUID_CHAR_AGG_FORMAT}}; + UINT16 handle; + tBTA_GATT_STATUS status = BTA_GATT_OK; + + /* GATT_UUID_CHAR_AGG_FORMAT */ + if (bta_gattc_uuid_compare (&uuid, p_descr_uuid, TRUE)) + { + while (p_attr->len >= 2 && i < BTA_GATTC_MULTI_MAX) + { + STREAM_TO_UINT16(handle, pp); + + if (bta_gattc_handle2id(p_srcb, + handle, + &p_value->aggre_value.pre_format[i].char_id.srvc_id, + &p_value->aggre_value.pre_format[i].char_id.char_id, + &p_value->aggre_value.pre_format[i].descr_id) == FALSE) + { + status = BTA_GATT_INTERNAL_ERROR; + APPL_TRACE_ERROR("can not map to GATT ID. handle = 0x%04x", handle); + break; + } + i ++; + p_attr->len -= 2; + } + p_value->aggre_value.num_pres_fmt = i; + } + else + { + /* all others, take as raw format */ + p_value->unformat.len = p_attr->len; + p_value->unformat.p_value = p_attr->value; + } + return status; +} +/******************************************************************************* +** +** Function bta_gattc_mark_bg_conn +** +** Description mark background connection status when a bg connection is initiated +** or terminated. +** +** Returns TRUE if success; FALSE otherwise. +** +*******************************************************************************/ +BOOLEAN bta_gattc_mark_bg_conn (tBTA_GATTC_IF client_if, BD_ADDR_PTR remote_bda_ptr, + BOOLEAN add, BOOLEAN is_listen) +{ + tBTA_GATTC_BG_TCK *p_bg_tck = &bta_gattc_cb.bg_track[0]; + UINT8 i = 0; + tBTA_GATTC_CIF_MASK *p_cif_mask; + + for (i = 0; i < BTA_GATTC_KNOWN_SR_MAX; i ++, p_bg_tck ++) + { + if (p_bg_tck->in_use && + ((remote_bda_ptr != NULL && bdcmp(p_bg_tck->remote_bda, remote_bda_ptr) == 0) || + (remote_bda_ptr == NULL && bdcmp(p_bg_tck->remote_bda, dummy_bda) == 0))) + { + p_cif_mask = is_listen ? &p_bg_tck->cif_adv_mask : &p_bg_tck->cif_mask; + + if (add) + /* mask on the cif bit */ + *p_cif_mask |= (1 <<(client_if - 1)); + else + { + if (client_if != 0) + *p_cif_mask &= (~(1 <<(client_if - 1))); + else + *p_cif_mask = 0; + } + /* no BG connection for this device, make it available */ + if (p_bg_tck->cif_mask == 0 && p_bg_tck->cif_adv_mask == 0) + { + memset(p_bg_tck, 0, sizeof(tBTA_GATTC_BG_TCK)); + } + return TRUE; + } + } + if (!add) + { + if (remote_bda_ptr) + { + // bdstr_t bdstr = {0}; + char bdstr[18] = {0}; + APPL_TRACE_ERROR("%s unable to find the bg connection mask for: %s", __func__, + bdaddr_to_string((bt_bdaddr_t *)remote_bda_ptr, bdstr, sizeof(bdstr))); + } + return FALSE; + } + else /* adding a new device mask */ + { + for (i = 0, p_bg_tck = &bta_gattc_cb.bg_track[0]; + i < BTA_GATTC_KNOWN_SR_MAX; i ++, p_bg_tck ++) + { + if (!p_bg_tck->in_use) + { + p_bg_tck->in_use = TRUE; + if (remote_bda_ptr) + bdcpy(p_bg_tck->remote_bda, remote_bda_ptr); + else + bdcpy(p_bg_tck->remote_bda, dummy_bda); + + p_cif_mask = is_listen ? &p_bg_tck->cif_adv_mask : &p_bg_tck->cif_mask; + + *p_cif_mask = (1 <<(client_if - 1)); + return TRUE; + } + } + APPL_TRACE_ERROR("no available space to mark the bg connection status"); + return FALSE; + } +} +/******************************************************************************* +** +** Function bta_gattc_check_bg_conn +** +** Description check if this is a background connection background connection. +** +** Returns TRUE if success; FALSE otherwise. +** +*******************************************************************************/ +BOOLEAN bta_gattc_check_bg_conn (tBTA_GATTC_IF client_if, BD_ADDR remote_bda, UINT8 role) +{ + tBTA_GATTC_BG_TCK *p_bg_tck = &bta_gattc_cb.bg_track[0]; + UINT8 i = 0; + BOOLEAN is_bg_conn = FALSE; + + for (i = 0; i < BTA_GATTC_KNOWN_SR_MAX && !is_bg_conn; i ++, p_bg_tck ++) + { + if (p_bg_tck->in_use && + (bdcmp(p_bg_tck->remote_bda, remote_bda) == 0 || + bdcmp(p_bg_tck->remote_bda, dummy_bda) == 0)) + { + if (((p_bg_tck->cif_mask &(1 <<(client_if - 1))) != 0) && + role == HCI_ROLE_MASTER) + is_bg_conn = TRUE; + + if (((p_bg_tck->cif_adv_mask &(1 <<(client_if - 1))) != 0) && + role == HCI_ROLE_SLAVE) + is_bg_conn = TRUE; + } + } + return is_bg_conn; +} +/******************************************************************************* +** +** Function bta_gattc_send_open_cback +** +** Description send open callback +** +** Returns +** +*******************************************************************************/ +void bta_gattc_send_open_cback( tBTA_GATTC_RCB *p_clreg, tBTA_GATT_STATUS status, + BD_ADDR remote_bda, UINT16 conn_id, + tBTA_TRANSPORT transport, UINT16 mtu) +{ + tBTA_GATTC cb_data; + + if (p_clreg->p_cback) + { + memset(&cb_data, 0, sizeof(tBTA_GATTC)); + + cb_data.open.status = status; + cb_data.open.client_if = p_clreg->client_if; + cb_data.open.conn_id = conn_id; + cb_data.open.mtu = mtu; + cb_data.open.transport = transport; + bdcpy(cb_data.open.remote_bda, remote_bda); + + (*p_clreg->p_cback)(BTA_GATTC_OPEN_EVT, &cb_data); + } +} +/******************************************************************************* +** +** Function bta_gattc_conn_alloc +** +** Description allocate connection tracking spot +** +** Returns pointer to the clcb +** +*******************************************************************************/ +tBTA_GATTC_CONN * bta_gattc_conn_alloc(BD_ADDR remote_bda) +{ + UINT8 i_conn = 0; + tBTA_GATTC_CONN *p_conn = &bta_gattc_cb.conn_track[0]; + + for (i_conn = 0; i_conn < BTA_GATTC_CONN_MAX; i_conn++, p_conn ++) + { + if (!p_conn->in_use) + { +#if BTA_GATT_DEBUG == TRUE + APPL_TRACE_DEBUG("bta_gattc_conn_alloc: found conn_track[%d] available",i_conn); +#endif + p_conn->in_use = TRUE; + bdcpy(p_conn->remote_bda, remote_bda); + return p_conn; + } + } + return NULL; +} + +/******************************************************************************* +** +** Function bta_gattc_conn_find +** +** Description allocate connection tracking spot +** +** Returns pointer to the clcb +** +*******************************************************************************/ +tBTA_GATTC_CONN * bta_gattc_conn_find(BD_ADDR remote_bda) +{ + UINT8 i_conn = 0; + tBTA_GATTC_CONN *p_conn = &bta_gattc_cb.conn_track[0]; + + for (i_conn = 0; i_conn < BTA_GATTC_CONN_MAX; i_conn++, p_conn ++) + { + if (p_conn->in_use && bdcmp(remote_bda, p_conn->remote_bda) == 0) + { +#if BTA_GATT_DEBUG == TRUE + APPL_TRACE_DEBUG("bta_gattc_conn_find: found conn_track[%d] matched",i_conn); +#endif + return p_conn; + } + } + return NULL; +} + + +/******************************************************************************* +** +** Function bta_gattc_conn_find_alloc +** +** Description find or allocate connection tracking spot +** +** Returns pointer to the clcb +** +*******************************************************************************/ +tBTA_GATTC_CONN * bta_gattc_conn_find_alloc(BD_ADDR remote_bda) +{ + tBTA_GATTC_CONN *p_conn = bta_gattc_conn_find (remote_bda); + + if (p_conn == NULL) + { + p_conn = bta_gattc_conn_alloc(remote_bda); + } + return p_conn; +} + +/******************************************************************************* +** +** Function bta_gattc_conn_dealloc +** +** Description de-allocate connection tracking spot +** +** Returns pointer to the clcb +** +*******************************************************************************/ +BOOLEAN bta_gattc_conn_dealloc(BD_ADDR remote_bda) +{ + tBTA_GATTC_CONN *p_conn = bta_gattc_conn_find (remote_bda); + + if (p_conn != NULL) + { + p_conn->in_use = FALSE; + memset(p_conn->remote_bda, 0, BD_ADDR_LEN); + return TRUE; + } + return FALSE; +} + +/******************************************************************************* +** +** Function bta_gattc_find_int_conn_clcb +** +** Description try to locate a clcb when an internal connecion event arrives. +** +** Returns pointer to the clcb +** +*******************************************************************************/ +tBTA_GATTC_CLCB * bta_gattc_find_int_conn_clcb(tBTA_GATTC_DATA *p_msg) +{ + tBTA_GATTC_CLCB *p_clcb = NULL; + + if (p_msg->int_conn.role == HCI_ROLE_SLAVE) + bta_gattc_conn_find_alloc(p_msg->int_conn.remote_bda); + + /* try to locate a logic channel */ + if ((p_clcb = bta_gattc_find_clcb_by_cif(p_msg->int_conn.client_if, + p_msg->int_conn.remote_bda, + p_msg->int_conn.transport)) == NULL) + { + /* for a background connection or listening connection */ + if (/*p_msg->int_conn.role == HCI_ROLE_SLAVE || */ + bta_gattc_check_bg_conn(p_msg->int_conn.client_if, + p_msg->int_conn.remote_bda, + p_msg->int_conn.role)) + { + /* allocate a new channel */ + p_clcb = bta_gattc_clcb_alloc(p_msg->int_conn.client_if, + p_msg->int_conn.remote_bda, + p_msg->int_conn.transport); + } + } + return p_clcb; +} + +/******************************************************************************* +** +** Function bta_gattc_find_int_disconn_clcb +** +** Description try to locate a clcb when an internal disconnect callback arrives. +** +** Returns pointer to the clcb +** +*******************************************************************************/ +tBTA_GATTC_CLCB * bta_gattc_find_int_disconn_clcb(tBTA_GATTC_DATA *p_msg) +{ + tBTA_GATTC_CLCB *p_clcb = NULL; + + bta_gattc_conn_dealloc(p_msg->int_conn.remote_bda); + if ((p_clcb = bta_gattc_find_clcb_by_conn_id(p_msg->int_conn.hdr.layer_specific)) == NULL) + { + /* connection attempt failed, send connection callback event */ + p_clcb = bta_gattc_find_clcb_by_cif(p_msg->int_conn.client_if, + p_msg->int_conn.remote_bda, + p_msg->int_conn.transport); + } + if (p_clcb == NULL) + { + APPL_TRACE_DEBUG(" disconnection ID: [%d] not used by BTA", + p_msg->int_conn.hdr.layer_specific); + } + return p_clcb; +} + +#endif /* BTA_GATT_INCLUDED */ diff --git a/components/bt/bluedroid/bta/gatt/bta_gatts_act.c b/components/bt/bluedroid/bta/gatt/bta_gatts_act.c new file mode 100755 index 0000000000..1c0edfd770 --- /dev/null +++ b/components/bt/bluedroid/bta/gatt/bta_gatts_act.c @@ -0,0 +1,992 @@ +/****************************************************************************** + * + * Copyright (C) 2003-2012 Broadcom Corporation + * + * 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 GATT Server action functions for the state + * machine. + * + ******************************************************************************/ + + +#include "bt_target.h" + +#if defined(BTA_GATT_INCLUDED) && (BTA_GATT_INCLUDED == TRUE) + +#include "utl.h" +#include "gki.h" +#include "bta_sys.h" +#include "bta_gatts_int.h" +#include "bta_gatts_co.h" +#include "btm_ble_api.h" +// #include "btif/include/btif_debug_conn.h" +#include + +static void bta_gatts_nv_save_cback(BOOLEAN is_saved, tGATTS_HNDL_RANGE *p_hndl_range); +static BOOLEAN bta_gatts_nv_srv_chg_cback(tGATTS_SRV_CHG_CMD cmd, tGATTS_SRV_CHG_REQ *p_req, + tGATTS_SRV_CHG_RSP *p_rsp); + +static void bta_gatts_conn_cback (tGATT_IF gatt_if, BD_ADDR bda, UINT16 conn_id, + BOOLEAN connected, tGATT_DISCONN_REASON reason, + tGATT_TRANSPORT transport); +static void bta_gatts_send_request_cback (UINT16 conn_id, + UINT32 trans_id, + tGATTS_REQ_TYPE req_type, tGATTS_DATA *p_data); +static void bta_gatts_cong_cback (UINT16 conn_id, BOOLEAN congested); + +static tGATT_CBACK bta_gatts_cback = +{ + bta_gatts_conn_cback, + NULL, + NULL, + NULL, + bta_gatts_send_request_cback, + NULL, + bta_gatts_cong_cback +}; + +tGATT_APPL_INFO bta_gatts_nv_cback = +{ + bta_gatts_nv_save_cback, + bta_gatts_nv_srv_chg_cback +}; + +/******************************************************************************* +** +** Function bta_gatts_nv_save_cback +** +** Description NV save callback function. +** +** Parameter is_add: true is to add a handle range; otherwise is to delete. +** Returns none. +** +*******************************************************************************/ +static void bta_gatts_nv_save_cback(BOOLEAN is_add, tGATTS_HNDL_RANGE *p_hndl_range) +{ + bta_gatts_co_update_handle_range(is_add, (tBTA_GATTS_HNDL_RANGE *)p_hndl_range); +} + + +/******************************************************************************* +** +** Function bta_gatts_nv_srv_chg_cback +** +** Description NV save callback function. +** +** Parameter is_add: true is to add a handle range; otherwise is to delete. +** Returns none. +** +*******************************************************************************/ +static BOOLEAN bta_gatts_nv_srv_chg_cback(tGATTS_SRV_CHG_CMD cmd, + tGATTS_SRV_CHG_REQ *p_req, tGATTS_SRV_CHG_RSP *p_rsp) +{ + return bta_gatts_co_srv_chg((tBTA_GATTS_SRV_CHG_CMD) cmd, + (tBTA_GATTS_SRV_CHG_REQ *) p_req, + (tBTA_GATTS_SRV_CHG_RSP *) p_rsp); +} + + +/******************************************************************************* +** +** Function bta_gatts_enable +** +** Description enable BTA GATTS module. +** +** Returns none. +** +*******************************************************************************/ +void bta_gatts_enable(tBTA_GATTS_CB *p_cb) +{ + UINT8 index=0; + tBTA_GATTS_HNDL_RANGE handle_range; + + if (p_cb->enabled) + { + APPL_TRACE_DEBUG("GATTS already enabled."); + } + else + { + memset(p_cb, 0, sizeof(tBTA_GATTS_CB)); + + p_cb->enabled = TRUE; + + while ( bta_gatts_co_load_handle_range(index, &handle_range)) + { + GATTS_AddHandleRange((tGATTS_HNDL_RANGE *)&handle_range); + memset(&handle_range, 0, sizeof(tGATTS_HNDL_RANGE)); + index++; + } + + APPL_TRACE_DEBUG("bta_gatts_enable: num of handle range added=%d", index); + + if (!GATTS_NVRegister(&bta_gatts_nv_cback)) + { + APPL_TRACE_ERROR("BTA GATTS NV register failed."); + } + } +} + +/******************************************************************************* +** +** Function bta_gatts_api_disable +** +** Description disable BTA GATTS module. +** +** Returns none. +** +*******************************************************************************/ +void bta_gatts_api_disable(tBTA_GATTS_CB *p_cb) +{ + UINT8 i; + + if (p_cb->enabled) + { + for (i = 0; i < BTA_GATTS_MAX_APP_NUM; i ++) + { + if (p_cb->rcb[i].in_use) + { + GATT_Deregister(p_cb->rcb[i].gatt_if); + } + } + memset(p_cb, 0, sizeof(tBTA_GATTS_CB)); + } + else + { + APPL_TRACE_ERROR("GATTS not enabled"); + } +} + +/******************************************************************************* +** +** Function bta_gatts_register +** +** Description register an application. +** +** Returns none. +** +*******************************************************************************/ +void bta_gatts_register(tBTA_GATTS_CB *p_cb, tBTA_GATTS_DATA *p_msg) +{ + tBTA_GATTS_INT_START_IF *p_buf; + tBTA_GATTS cb_data; + tBTA_GATT_STATUS status = BTA_GATT_OK; + UINT8 i, first_unuse = 0xff; + + if (p_cb->enabled == FALSE) + { + bta_gatts_enable(p_cb); + } + + for (i = 0; i < BTA_GATTS_MAX_APP_NUM; i ++) + { + if (p_cb->rcb[i].in_use) + { + if (bta_gatts_uuid_compare(p_cb->rcb[i].app_uuid, p_msg->api_reg.app_uuid)) + { + APPL_TRACE_ERROR("application already registered.\n"); + status = BTA_GATT_DUP_REG; + break; + } + } + } + + if (status == BTA_GATT_OK) + { + for (i = 0; i < BTA_GATTS_MAX_APP_NUM; i ++) + { + if (first_unuse == 0xff && !p_cb->rcb[i].in_use) + { + first_unuse = i; + break; + } + } + + cb_data.reg_oper.server_if = BTA_GATTS_INVALID_IF; +// btla-specific ++ + memcpy(&cb_data.reg_oper.uuid, &p_msg->api_reg.app_uuid, sizeof(tBT_UUID)); +// btla-specific -- + if (first_unuse != 0xff) + { + APPL_TRACE_ERROR("register application first_unuse rcb_idx = %d", first_unuse); + + p_cb->rcb[first_unuse].in_use = TRUE; + p_cb->rcb[first_unuse].p_cback = p_msg->api_reg.p_cback; + memcpy(&p_cb->rcb[first_unuse].app_uuid, &p_msg->api_reg.app_uuid, sizeof(tBT_UUID)); + cb_data.reg_oper.server_if = + p_cb->rcb[first_unuse].gatt_if = + GATT_Register(&p_msg->api_reg.app_uuid, &bta_gatts_cback); + if ( !p_cb->rcb[first_unuse].gatt_if) + { + status = BTA_GATT_NO_RESOURCES; + } + else + { + if ((p_buf = + (tBTA_GATTS_INT_START_IF *) GKI_getbuf(sizeof(tBTA_GATTS_INT_START_IF))) != NULL) + { + p_buf->hdr.event = BTA_GATTS_INT_START_IF_EVT; + p_buf->server_if = p_cb->rcb[first_unuse].gatt_if; + + bta_sys_sendmsg(p_buf); + } + else + { + status = BTA_GATT_NO_RESOURCES; + memset( &p_cb->rcb[first_unuse], 0 , sizeof(tBTA_GATTS_RCB)); + } + } + } + else + { + status = BTA_GATT_NO_RESOURCES; + } + + } + cb_data.reg_oper.status = status; + if (p_msg->api_reg.p_cback) + (*p_msg->api_reg.p_cback)(BTA_GATTS_REG_EVT, &cb_data); + + LOG_ERROR("status=%x\n",status); +} + + +/******************************************************************************* +** +** Function bta_gatts_start_if +** +** Description start an application interface. +** +** Returns none. +** +*******************************************************************************/ +void bta_gatts_start_if(tBTA_GATTS_CB *p_cb, tBTA_GATTS_DATA *p_msg) +{ + UNUSED(p_cb); + + if (bta_gatts_find_app_rcb_by_app_if(p_msg->int_start_if.server_if)) + { + GATT_StartIf(p_msg->int_start_if.server_if); + } + else + { + APPL_TRACE_ERROR("Unable to start app.: Unknown interface =%d", + p_msg->int_start_if.server_if ); + } +} +/******************************************************************************* +** +** Function bta_gatts_deregister +** +** Description deregister an application. +** +** Returns none. +** +*******************************************************************************/ +void bta_gatts_deregister(tBTA_GATTS_CB *p_cb, tBTA_GATTS_DATA *p_msg) +{ + tBTA_GATT_STATUS status = BTA_GATT_ERROR; + tBTA_GATTS_CBACK *p_cback = NULL; + UINT8 i; + tBTA_GATTS cb_data; + + cb_data.reg_oper.server_if = p_msg->api_dereg.server_if; + cb_data.reg_oper.status = status; + + for (i = 0; i < BTA_GATTS_MAX_APP_NUM; i ++) + { + if (p_cb->rcb[i].in_use && p_cb->rcb[i].gatt_if == p_msg->api_dereg.server_if) + { + p_cback = p_cb->rcb[i].p_cback; + status = BTA_GATT_OK; + + /* deregister the app */ + GATT_Deregister(p_cb->rcb[i].gatt_if); + + /* reset cb */ + memset(&p_cb->rcb[i], 0, sizeof(tBTA_GATTS_RCB)); + cb_data.reg_oper.status = status; + break; + } + } + + if (p_cback) + { + (*p_cback)(BTA_GATTS_DEREG_EVT, &cb_data); + } + else + { + APPL_TRACE_ERROR("application not registered."); + } +} +/******************************************************************************* +** +** Function bta_gatts_create_srvc +** +** Description action function to create a service. +** +** Returns none. +** +*******************************************************************************/ +void bta_gatts_create_srvc(tBTA_GATTS_CB *p_cb, tBTA_GATTS_DATA * p_msg) +{ + UINT8 rcb_idx; + tBTA_GATTS cb_data; + UINT8 srvc_idx; + UINT16 service_id = 0; + + cb_data.create.status = BTA_GATT_ERROR; + + rcb_idx = bta_gatts_find_app_rcb_idx_by_app_if(p_cb, p_msg->api_create_svc.server_if); + + APPL_TRACE_ERROR("create service rcb_idx = %d", rcb_idx); + + if (rcb_idx != BTA_GATTS_INVALID_APP) + { + if ((srvc_idx = bta_gatts_alloc_srvc_cb(p_cb, rcb_idx)) != BTA_GATTS_INVALID_APP) + { + /* create the service now */ + service_id = GATTS_CreateService (p_cb->rcb[rcb_idx].gatt_if, + &p_msg->api_create_svc.service_uuid, + p_msg->api_create_svc.inst, + p_msg->api_create_svc.num_handle, + p_msg->api_create_svc.is_pri); + + if (service_id != 0) + { + memcpy(&p_cb->srvc_cb[srvc_idx].service_uuid, + &p_msg->api_create_svc.service_uuid, sizeof(tBT_UUID)); + p_cb->srvc_cb[srvc_idx].service_id = service_id; + p_cb->srvc_cb[srvc_idx].inst_num = p_msg->api_create_svc.inst; + p_cb->srvc_cb[srvc_idx].idx = srvc_idx; + + cb_data.create.status = BTA_GATT_OK; + cb_data.create.service_id = service_id; +// btla-specific ++ + cb_data.create.is_primary = p_msg->api_create_svc.is_pri; +// btla-specific -- + cb_data.create.server_if = p_cb->rcb[rcb_idx].gatt_if; + } + else + { + cb_data.status = BTA_GATT_ERROR; + memset(&p_cb->srvc_cb[srvc_idx], 0, sizeof(tBTA_GATTS_SRVC_CB)); + APPL_TRACE_ERROR("service creation failed."); + } +// btla-specific ++ + memcpy(&cb_data.create.uuid, &p_msg->api_create_svc.service_uuid, sizeof(tBT_UUID)); + cb_data.create.svc_instance= p_msg->api_create_svc.inst; +// btla-specific -- + } + if (p_cb->rcb[rcb_idx].p_cback) + (* p_cb->rcb[rcb_idx].p_cback)(BTA_GATTS_CREATE_EVT, &cb_data); + } + else /* application not registered */ + { + APPL_TRACE_ERROR("Application not registered"); + } +} +/******************************************************************************* +** +** Function bta_gatts_add_include_srvc +** +** Description action function to add an included service. +** +** Returns none. +** +*******************************************************************************/ +void bta_gatts_add_include_srvc(tBTA_GATTS_SRVC_CB *p_srvc_cb,tBTA_GATTS_DATA * p_msg) +{ + tBTA_GATTS_RCB *p_rcb = &bta_gatts_cb.rcb[p_srvc_cb->rcb_idx]; + UINT16 attr_id = 0; + tBTA_GATTS cb_data; + + attr_id = GATTS_AddIncludeService(p_msg->api_add_incl_srvc.hdr.layer_specific, + p_msg->api_add_incl_srvc.included_service_id); + + cb_data.add_result.server_if = p_rcb->gatt_if; + cb_data.add_result.service_id = p_msg->api_add_incl_srvc.hdr.layer_specific; + cb_data.add_result.attr_id = attr_id; + + if (attr_id) + { + cb_data.add_result.status = BTA_GATT_OK; + } + else + { + cb_data.add_result.status = BTA_GATT_ERROR; + } + + if (p_rcb->p_cback) + (*p_rcb->p_cback)(BTA_GATTS_ADD_INCL_SRVC_EVT, &cb_data); +} +/******************************************************************************* +** +** Function bta_gatts_add_char +** +** Description action function to add characteristic. +** +** Returns none. +** +*******************************************************************************/ +void bta_gatts_add_char(tBTA_GATTS_SRVC_CB *p_srvc_cb, tBTA_GATTS_DATA * p_msg) +{ + tBTA_GATTS_RCB *p_rcb = &bta_gatts_cb.rcb[p_srvc_cb->rcb_idx]; + UINT16 attr_id = 0; + tBTA_GATTS cb_data; + + attr_id = GATTS_AddCharacteristic(p_msg->api_add_char.hdr.layer_specific, + &p_msg->api_add_char.char_uuid, + p_msg->api_add_char.perm, + p_msg->api_add_char.property); + cb_data.add_result.server_if = p_rcb->gatt_if; + cb_data.add_result.service_id = p_msg->api_add_incl_srvc.hdr.layer_specific; + cb_data.add_result.attr_id = attr_id; +// btla-specific ++ + memcpy(&cb_data.add_result.char_uuid, &p_msg->api_add_char.char_uuid, sizeof(tBT_UUID)); +// btla-specific -- + + if (attr_id) + { + cb_data.add_result.status = BTA_GATT_OK; + } + else + { + cb_data.add_result.status = BTA_GATT_ERROR; + } + + if (p_rcb->p_cback) + (*p_rcb->p_cback)(BTA_GATTS_ADD_CHAR_EVT, &cb_data); +} +/******************************************************************************* +** +** Function bta_gatts_add_char_descr +** +** Description action function to add characteristic descriptor. +** +** Returns none. +** +*******************************************************************************/ +void bta_gatts_add_char_descr(tBTA_GATTS_SRVC_CB *p_srvc_cb, tBTA_GATTS_DATA * p_msg) +{ + tBTA_GATTS_RCB *p_rcb = &bta_gatts_cb.rcb[p_srvc_cb->rcb_idx]; + UINT16 attr_id = 0; + tBTA_GATTS cb_data; + + attr_id = GATTS_AddCharDescriptor(p_msg->api_add_char_descr.hdr.layer_specific, + p_msg->api_add_char_descr.perm, + &p_msg->api_add_char_descr.descr_uuid); + + cb_data.add_result.server_if = p_rcb->gatt_if; + cb_data.add_result.service_id = p_msg->api_add_incl_srvc.hdr.layer_specific; + cb_data.add_result.attr_id = attr_id; +// btla-specific ++ + memcpy(&cb_data.add_result.char_uuid, &p_msg->api_add_char_descr.descr_uuid, sizeof(tBT_UUID)); +// btla-specific -- + + if (attr_id) + { + cb_data.add_result.status = BTA_GATT_OK; + } + else + { + cb_data.add_result.status = BTA_GATT_ERROR; + } + + if (p_rcb->p_cback) + (*p_rcb->p_cback)(BTA_GATTS_ADD_CHAR_DESCR_EVT, &cb_data); + +} +/******************************************************************************* +** +** Function bta_gatts_delete_service +** +** Description action function to delete a service. +** +** Returns none. +** +*******************************************************************************/ +void bta_gatts_delete_service(tBTA_GATTS_SRVC_CB *p_srvc_cb, tBTA_GATTS_DATA * p_msg) +{ + tBTA_GATTS_RCB *p_rcb = &bta_gatts_cb.rcb[p_srvc_cb->rcb_idx]; + tBTA_GATTS cb_data; + + cb_data.srvc_oper.server_if = p_rcb->gatt_if; + cb_data.srvc_oper.service_id = p_msg->api_add_incl_srvc.hdr.layer_specific; + + if (GATTS_DeleteService(p_rcb->gatt_if, + &p_srvc_cb->service_uuid, + p_srvc_cb->inst_num)) + { + cb_data.srvc_oper.status = BTA_GATT_OK; + memset(p_srvc_cb, 0, sizeof(tBTA_GATTS_SRVC_CB)); + } + else + { + cb_data.srvc_oper.status = BTA_GATT_ERROR; + } + + if (p_rcb->p_cback) + (*p_rcb->p_cback)(BTA_GATTS_DELELTE_EVT, &cb_data); + +} +/******************************************************************************* +** +** Function bta_gatts_start_service +** +** Description action function to start a service. +** +** Returns none. +** +*******************************************************************************/ +void bta_gatts_start_service(tBTA_GATTS_SRVC_CB *p_srvc_cb, tBTA_GATTS_DATA * p_msg) +{ + tBTA_GATTS_RCB *p_rcb = &bta_gatts_cb.rcb[p_srvc_cb->rcb_idx]; + tBTA_GATTS cb_data; + + cb_data.srvc_oper.server_if = p_rcb->gatt_if; + cb_data.srvc_oper.service_id = p_msg->api_add_incl_srvc.hdr.layer_specific; + + if (GATTS_StartService(p_rcb->gatt_if, + p_srvc_cb->service_id, + p_msg->api_start.transport) == GATT_SUCCESS) + { + APPL_TRACE_DEBUG("bta_gatts_start_service service_id= %d", p_srvc_cb->service_id); + cb_data.srvc_oper.status = BTA_GATT_OK; + } + else + { + cb_data.srvc_oper.status = BTA_GATT_ERROR; + } + + if (p_rcb->p_cback) + (*p_rcb->p_cback)(BTA_GATTS_START_EVT, &cb_data); + +} +/******************************************************************************* +** +** Function bta_gatts_stop_service +** +** Description action function to stop a service. +** +** Returns none. +** +*******************************************************************************/ +void bta_gatts_stop_service(tBTA_GATTS_SRVC_CB *p_srvc_cb, tBTA_GATTS_DATA * p_msg) +{ + tBTA_GATTS_RCB *p_rcb = &bta_gatts_cb.rcb[p_srvc_cb->rcb_idx]; + tBTA_GATTS cb_data; + UNUSED(p_msg); + + GATTS_StopService(p_srvc_cb->service_id); + cb_data.srvc_oper.server_if = p_rcb->gatt_if; + cb_data.srvc_oper.service_id = p_srvc_cb->service_id; + cb_data.srvc_oper.status = BTA_GATT_OK; + APPL_TRACE_ERROR("bta_gatts_stop_service service_id= %d", p_srvc_cb->service_id); + + if (p_rcb->p_cback) + (*p_rcb->p_cback)(BTA_GATTS_STOP_EVT, &cb_data); + +} +/******************************************************************************* +** +** Function bta_gatts_send_rsp +** +** Description GATTS send response. +** +** Returns none. +** +*******************************************************************************/ +void bta_gatts_send_rsp (tBTA_GATTS_CB *p_cb, tBTA_GATTS_DATA * p_msg) +{ + UNUSED(p_cb); + + if (GATTS_SendRsp (p_msg->api_rsp.hdr.layer_specific, + p_msg->api_rsp.trans_id, + p_msg->api_rsp.status, + (tGATTS_RSP *)p_msg->api_rsp.p_rsp) != GATT_SUCCESS) + { + APPL_TRACE_ERROR("Sending response failed"); + } + +} +/******************************************************************************* +** +** Function bta_gatts_indicate_handle +** +** Description GATTS send handle value indication or notification. +** +** Returns none. +** +*******************************************************************************/ +void bta_gatts_indicate_handle (tBTA_GATTS_CB *p_cb, tBTA_GATTS_DATA * p_msg) +{ + tBTA_GATTS_SRVC_CB *p_srvc_cb; + tBTA_GATTS_RCB *p_rcb = NULL; + tBTA_GATT_STATUS status = BTA_GATT_ILLEGAL_PARAMETER; + tGATT_IF gatt_if; + BD_ADDR remote_bda; + tBTA_TRANSPORT transport; + tBTA_GATTS cb_data; + + p_srvc_cb = bta_gatts_find_srvc_cb_by_attr_id (p_cb, p_msg->api_indicate.attr_id); + + if (p_srvc_cb ) + { + if (GATT_GetConnectionInfor(p_msg->api_indicate.hdr.layer_specific, + &gatt_if, remote_bda, &transport)) + { + p_rcb = bta_gatts_find_app_rcb_by_app_if(gatt_if); + + if (p_msg->api_indicate.need_confirm) + + status = GATTS_HandleValueIndication (p_msg->api_indicate.hdr.layer_specific, + p_msg->api_indicate.attr_id, + p_msg->api_indicate.len, + p_msg->api_indicate.value); + else + status = GATTS_HandleValueNotification (p_msg->api_indicate.hdr.layer_specific, + p_msg->api_indicate.attr_id, + p_msg->api_indicate.len, + p_msg->api_indicate.value); + + /* if over BR_EDR, inform PM for mode change */ + if (transport == BTA_TRANSPORT_BR_EDR) + { + bta_sys_busy(BTA_ID_GATTS, BTA_ALL_APP_ID, remote_bda); + bta_sys_idle(BTA_ID_GATTS, BTA_ALL_APP_ID, remote_bda); + } + } + else + { + APPL_TRACE_ERROR("Unknown connection ID: %d fail sending notification", + p_msg->api_indicate.hdr.layer_specific); + } + + if ((status != GATT_SUCCESS || !p_msg->api_indicate.need_confirm) && + p_rcb && p_cb->rcb[p_srvc_cb->rcb_idx].p_cback) + { + cb_data.req_data.status = status; + cb_data.req_data.conn_id = p_msg->api_indicate.hdr.layer_specific; + + (*p_rcb->p_cback)(BTA_GATTS_CONF_EVT, &cb_data); + } + } + else + { + APPL_TRACE_ERROR("Not an registered servce attribute ID: 0x%04x", + p_msg->api_indicate.attr_id); + } +} + + +/******************************************************************************* +** +** Function bta_gatts_open +** +** Description +** +** Returns none. +** +*******************************************************************************/ +void bta_gatts_open (tBTA_GATTS_CB *p_cb, tBTA_GATTS_DATA * p_msg) +{ + tBTA_GATTS_RCB *p_rcb=NULL; + tBTA_GATT_STATUS status= BTA_GATT_ERROR; + UINT16 conn_id; + UNUSED(p_cb); + + if ((p_rcb = bta_gatts_find_app_rcb_by_app_if(p_msg->api_open.server_if)) != NULL) + { + /* should always get the connection ID */ + if (GATT_Connect(p_rcb->gatt_if, p_msg->api_open.remote_bda, + p_msg->api_open.is_direct, p_msg->api_open.transport)) + { + status = BTA_GATT_OK; + + if (GATT_GetConnIdIfConnected(p_rcb->gatt_if, p_msg->api_open.remote_bda, + &conn_id, p_msg->api_open.transport)) + { + status = BTA_GATT_ALREADY_OPEN; + } + } + } + else + { + APPL_TRACE_ERROR("Inavlide server_if=%d", p_msg->api_open.server_if); + } + + if (p_rcb && p_rcb->p_cback) + (*p_rcb->p_cback)(BTA_GATTS_OPEN_EVT, (tBTA_GATTS *)&status); + +} +/******************************************************************************* +** +** Function bta_gatts_cancel_open +** +** Description +** +** Returns none. +** +*******************************************************************************/ +void bta_gatts_cancel_open (tBTA_GATTS_CB *p_cb, tBTA_GATTS_DATA * p_msg) +{ + tBTA_GATTS_RCB *p_rcb; + tBTA_GATT_STATUS status= BTA_GATT_ERROR; + UNUSED(p_cb); + + if ((p_rcb = bta_gatts_find_app_rcb_by_app_if(p_msg->api_cancel_open.server_if)) != NULL) + { + if (!GATT_CancelConnect(p_rcb->gatt_if, p_msg->api_cancel_open.remote_bda, + p_msg->api_cancel_open.is_direct)) + { + APPL_TRACE_ERROR("bta_gatts_cancel_open failed for open request"); + } + else + { + status= BTA_GATT_OK; + } + } + else + { + APPL_TRACE_ERROR("Inavlide server_if=%d", p_msg->api_cancel_open.server_if); + } + + if (p_rcb && p_rcb->p_cback) + (*p_rcb->p_cback)(BTA_GATTS_CANCEL_OPEN_EVT, (tBTA_GATTS *)&status); +} +/******************************************************************************* +** +** Function bta_gatts_close +** +** Description +** +** Returns none. +** +*******************************************************************************/ +void bta_gatts_close (tBTA_GATTS_CB *p_cb, tBTA_GATTS_DATA * p_msg) +{ + tBTA_GATTS_RCB *p_rcb; + tBTA_GATT_STATUS status= BTA_GATT_ERROR; + tGATT_IF gatt_if; + BD_ADDR remote_bda; + tBTA_GATT_TRANSPORT transport; + + UNUSED(p_cb); + + if (GATT_GetConnectionInfor(p_msg->hdr.layer_specific, &gatt_if, remote_bda, &transport)) + { + if (GATT_Disconnect(p_msg->hdr.layer_specific) != GATT_SUCCESS) + { + APPL_TRACE_ERROR("bta_gatts_close fail conn_id=%d", p_msg->hdr.layer_specific); + } + else + { + status= BTA_GATT_OK; + } + + p_rcb = bta_gatts_find_app_rcb_by_app_if(gatt_if); + + if (p_rcb && p_rcb->p_cback) + { + if (transport == BTA_TRANSPORT_BR_EDR) + bta_sys_conn_close( BTA_ID_GATTS ,BTA_ALL_APP_ID, remote_bda); + + (*p_rcb->p_cback)(BTA_GATTS_CLOSE_EVT, (tBTA_GATTS *)&status); + } + } + else + { + APPL_TRACE_ERROR("Unknown connection ID: %d", p_msg->hdr.layer_specific); + } + +} +/******************************************************************************* +** +** Function bta_gatts_listen +** +** Description Start or stop listening for LE connection on a GATT server +** +** Returns none. +** +*******************************************************************************/ +void bta_gatts_listen(tBTA_GATTS_CB *p_cb, tBTA_GATTS_DATA * p_msg) +{ + tBTA_GATTS_RCB *p_rcb = bta_gatts_find_app_rcb_by_app_if(p_msg->api_listen.server_if); + tBTA_GATTS cb_data; + UNUSED(p_cb); + + cb_data.reg_oper.status = BTA_GATT_OK; + cb_data.reg_oper.server_if = p_msg->api_listen.server_if; + + if (p_rcb == NULL) + { + APPL_TRACE_ERROR("Unknown GATTS application"); + return; + } + + if (!GATT_Listen(p_msg->api_listen.server_if, + p_msg->api_listen.start, + p_msg->api_listen.remote_bda)) + { + cb_data.status = BTA_GATT_ERROR; + APPL_TRACE_ERROR("bta_gatts_listen Listen failed"); + } + + if (p_rcb->p_cback) + (*p_rcb->p_cback)(BTA_GATTS_LISTEN_EVT, &cb_data); +} + +/******************************************************************************* +** +** Function bta_gatts_request_cback +** +** Description GATTS attribute request callback. +** +** Returns none. +** +*******************************************************************************/ +static void bta_gatts_send_request_cback (UINT16 conn_id, + UINT32 trans_id, + tGATTS_REQ_TYPE req_type, tGATTS_DATA *p_data) +{ + tBTA_GATTS cb_data; + tBTA_GATTS_RCB *p_rcb; + tGATT_IF gatt_if; + tBTA_GATT_TRANSPORT transport; + + memset(&cb_data, 0 , sizeof(tBTA_GATTS)); + + if (GATT_GetConnectionInfor(conn_id, &gatt_if, cb_data.req_data.remote_bda, &transport)) + { + p_rcb = bta_gatts_find_app_rcb_by_app_if(gatt_if); + + APPL_TRACE_DEBUG ("bta_gatts_send_request_cback conn_id=%d trans_id=%d req_type=%d", + conn_id, trans_id, req_type); + + if (p_rcb && p_rcb->p_cback) + { + /* if over BR_EDR, inform PM for mode change */ + if (transport == BTA_TRANSPORT_BR_EDR) + { + bta_sys_busy(BTA_ID_GATTS, BTA_ALL_APP_ID, cb_data.req_data.remote_bda); + bta_sys_idle(BTA_ID_GATTS, BTA_ALL_APP_ID, cb_data.req_data.remote_bda); + } + + cb_data.req_data.conn_id = conn_id; + cb_data.req_data.trans_id = trans_id; + cb_data.req_data.p_data = (tBTA_GATTS_REQ_DATA *)p_data; + + (*p_rcb->p_cback)(req_type, &cb_data); + } + else + { + APPL_TRACE_ERROR("connection request on gatt_if[%d] is not interested", gatt_if); + } + } + else + { + APPL_TRACE_ERROR("request received on unknown connectino ID: %d", conn_id); + } +} + +/******************************************************************************* +** +** Function bta_gatts_conn_cback +** +** Description connection callback. +** +** Returns none. +** +*******************************************************************************/ +static void bta_gatts_conn_cback (tGATT_IF gatt_if, BD_ADDR bda, UINT16 conn_id, + BOOLEAN connected, tGATT_DISCONN_REASON reason, + tGATT_TRANSPORT transport) +{ + tBTA_GATTS cb_data; + UINT8 evt = connected ? BTA_GATTS_CONNECT_EVT: BTA_GATTS_DISCONNECT_EVT; + tBTA_GATTS_RCB *p_reg; + + APPL_TRACE_DEBUG ("bta_gatts_conn_cback gatt_if=%d conn_id=%d connected=%d reason = 0x%04d", + gatt_if, conn_id, connected, reason); + APPL_TRACE_DEBUG("bta_gatts_conn_cback bda :%02x-%02x-%02x-%02x-%02x-%02x ", + bda[0], bda[1], bda[2], bda[3], bda[4], bda[5]); + + bt_bdaddr_t bdaddr; + bdcpy(bdaddr.address, bda); + /* + if (connected) + btif_debug_conn_state(bdaddr, BTIF_DEBUG_CONNECTED, GATT_CONN_UNKNOWN); + else + btif_debug_conn_state(bdaddr, BTIF_DEBUG_DISCONNECTED, reason); + */ + p_reg = bta_gatts_find_app_rcb_by_app_if(gatt_if); + + if (p_reg && p_reg->p_cback) + { + /* there is no RM for GATT */ + if (transport == BTA_TRANSPORT_BR_EDR) + { + if (connected) + bta_sys_conn_open(BTA_ID_GATTS, BTA_ALL_APP_ID, bda); + else + bta_sys_conn_close( BTA_ID_GATTS ,BTA_ALL_APP_ID, bda); + } + + cb_data.conn.conn_id = conn_id; + cb_data.conn.server_if = gatt_if; + cb_data.conn.reason = reason; + cb_data.conn.transport = transport; + memcpy(cb_data.conn.remote_bda, bda, BD_ADDR_LEN); + (*p_reg->p_cback)(evt, &cb_data); + } + else + { + APPL_TRACE_ERROR("bta_gatts_conn_cback server_if=%d not found",gatt_if); + } +} + +/******************************************************************************* +** +** Function bta_gatts_cong_cback +** +** Description congestion callback. +** +** Returns none. +** +*******************************************************************************/ +static void bta_gatts_cong_cback (UINT16 conn_id, BOOLEAN congested) +{ + tBTA_GATTS_RCB *p_rcb; + tGATT_IF gatt_if; + tBTA_GATT_TRANSPORT transport; + tBTA_GATTS cb_data; + + if (GATT_GetConnectionInfor(conn_id, &gatt_if, cb_data.req_data.remote_bda, &transport)) + { + p_rcb = bta_gatts_find_app_rcb_by_app_if(gatt_if); + + if (p_rcb && p_rcb->p_cback) + { + cb_data.congest.conn_id = conn_id; + cb_data.congest.congested = congested; + + (*p_rcb->p_cback)(BTA_GATTS_CONGEST_EVT, &cb_data); + } + } +} +#endif /* BTA_GATT_INCLUDED */ diff --git a/components/bt/bluedroid/bta/gatt/bta_gatts_api.c b/components/bt/bluedroid/bta/gatt/bta_gatts_api.c new file mode 100755 index 0000000000..7f0954e4fa --- /dev/null +++ b/components/bt/bluedroid/bta/gatt/bta_gatts_api.c @@ -0,0 +1,581 @@ +/****************************************************************************** + * + * Copyright (C) 2010-2012 Broadcom Corporation + * + * 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 is the implementation of the API for GATT server of BTA. + * + ******************************************************************************/ + +#include "bt_target.h" + +#if defined(BTA_GATT_INCLUDED) && (BTA_GATT_INCLUDED == TRUE) + +#include +#include "gki.h" +#include "bta_sys.h" +#include "bta_gatt_api.h" +#include "bta_gatts_int.h" + +/***************************************************************************** +** Constants +*****************************************************************************/ + +static const tBTA_SYS_REG bta_gatts_reg = +{ + bta_gatts_hdl_event, + BTA_GATTS_Disable +}; + +/******************************************************************************* +** +** Function BTA_GATTS_Disable +** +** Description This function is called to disable GATTS module +** +** Parameters None. +** +** Returns None +** +*******************************************************************************/ +void BTA_GATTS_Disable(void) +{ + BT_HDR *p_buf; + + if (bta_sys_is_register(BTA_ID_GATTS) == FALSE) + { + APPL_TRACE_WARNING("GATTS Module not enabled/already disabled"); + return; + } + + if ((p_buf = (BT_HDR *) GKI_getbuf(sizeof(BT_HDR))) != NULL) + { + p_buf->event = BTA_GATTS_API_DISABLE_EVT; + bta_sys_sendmsg(p_buf); + } + bta_sys_deregister(BTA_ID_GATTS); + +} + +/******************************************************************************* +** +** Function BTA_GATTS_AppRegister +** +** Description This function is called to register application callbacks +** with BTA GATTS module. +** +** Parameters p_app_uuid - applicaiton UUID +** p_cback - pointer to the application callback function. +** +** Returns None +** +*******************************************************************************/ +void BTA_GATTS_AppRegister(tBT_UUID *p_app_uuid, tBTA_GATTS_CBACK *p_cback) +{ + tBTA_GATTS_API_REG *p_buf; + + /* register with BTA system manager */ + if (bta_sys_is_register(BTA_ID_GATTS) == FALSE) + { + bta_sys_register(BTA_ID_GATTS, &bta_gatts_reg); + } + + if ((p_buf = (tBTA_GATTS_API_REG *) GKI_getbuf(sizeof(tBTA_GATTS_API_REG))) != NULL) + { + p_buf->hdr.event = BTA_GATTS_API_REG_EVT; + + if (p_app_uuid != NULL) + memcpy(&p_buf->app_uuid, p_app_uuid, sizeof(tBT_UUID)); + p_buf->p_cback = p_cback; + + bta_sys_sendmsg(p_buf); + } + return; +} + + + +/******************************************************************************* +** +** Function BTA_GATTS_AppDeregister +** +** Description De-register with GATT Server. +** +** Parameters app_id: applicatino ID. +** +** Returns void +** +*******************************************************************************/ +void BTA_GATTS_AppDeregister(tBTA_GATTS_IF server_if) +{ + tBTA_GATTS_API_DEREG *p_buf; + + if ((p_buf = (tBTA_GATTS_API_DEREG *) GKI_getbuf(sizeof(tBTA_GATTS_API_DEREG))) != NULL) + { + p_buf->hdr.event = BTA_GATTS_API_DEREG_EVT; + p_buf->server_if = server_if; + + bta_sys_sendmsg(p_buf); + } + return; +} + +/******************************************************************************* +** +** Function BTA_GATTS_CreateService +** +** Description Create a service. When service creation is done, a callback +** event BTA_GATTS_CREATE_SRVC_EVT is called to report status +** and service ID to the profile. The service ID obtained in +** the callback function needs to be used when adding included +** service and characteristics/descriptors into the service. +** +** Parameters app_id: Profile ID this service is belonged to. +** p_service_uuid: service UUID. +** inst: instance ID number of this service. +** num_handle: numble of handle requessted for this service. +** is_primary: is this service a primary one or not. +** +** Returns void +** +*******************************************************************************/ +void BTA_GATTS_CreateService(tBTA_GATTS_IF server_if, tBT_UUID *p_service_uuid, UINT8 inst, + UINT16 num_handle, BOOLEAN is_primary) +{ + tBTA_GATTS_API_CREATE_SRVC *p_buf; + + if ((p_buf = (tBTA_GATTS_API_CREATE_SRVC *) GKI_getbuf(sizeof(tBTA_GATTS_API_CREATE_SRVC))) != NULL) + { + p_buf->hdr.event = BTA_GATTS_API_CREATE_SRVC_EVT; + + p_buf->server_if = server_if; + p_buf->inst = inst; + memcpy(&p_buf->service_uuid, p_service_uuid, sizeof(tBT_UUID)); + p_buf->num_handle = num_handle; + p_buf->is_pri = is_primary; + + bta_sys_sendmsg(p_buf); + } + return; +} +/******************************************************************************* +** +** Function BTA_GATTS_AddIncludeService +** +** Description This function is called to add an included service. After included +** service is included, a callback event BTA_GATTS_ADD_INCL_SRVC_EVT +** is reported the included service ID. +** +** Parameters service_id: service ID to which this included service is to +** be added. +** included_service_id: the service ID to be included. +** +** Returns void +** +*******************************************************************************/ +void BTA_GATTS_AddIncludeService(UINT16 service_id, UINT16 included_service_id) +{ + tBTA_GATTS_API_ADD_INCL_SRVC *p_buf; + + if ((p_buf = + (tBTA_GATTS_API_ADD_INCL_SRVC *) GKI_getbuf(sizeof(tBTA_GATTS_API_ADD_INCL_SRVC))) + != NULL) + { + p_buf->hdr.event = BTA_GATTS_API_ADD_INCL_SRVC_EVT; + + p_buf->hdr.layer_specific = service_id; + p_buf->included_service_id = included_service_id; + + bta_sys_sendmsg(p_buf); + } + return; + +} +/******************************************************************************* +** +** Function BTA_GATTS_AddCharacteristic +** +** Description This function is called to add a characteristic into a service. +** +** Parameters service_id: service ID to which this included service is to +** be added. +** p_char_uuid : Characteristic UUID. +** perm : Characteristic value declaration attribute permission. +** property : Characteristic Properties +** +** Returns None +** +*******************************************************************************/ +void BTA_GATTS_AddCharacteristic (UINT16 service_id, tBT_UUID *p_char_uuid, + tBTA_GATT_PERM perm, tBTA_GATT_CHAR_PROP property) +{ + tBTA_GATTS_API_ADD_CHAR *p_buf; + + if ((p_buf = (tBTA_GATTS_API_ADD_CHAR *) GKI_getbuf(sizeof(tBTA_GATTS_API_ADD_CHAR))) != NULL) + { + memset(p_buf, 0, sizeof(tBTA_GATTS_API_ADD_CHAR)); + + p_buf->hdr.event = BTA_GATTS_API_ADD_CHAR_EVT; + p_buf->hdr.layer_specific = service_id; + p_buf->perm = perm; + p_buf->property = property; + + if (p_char_uuid) + { + memcpy(&p_buf->char_uuid, p_char_uuid, sizeof(tBT_UUID)); + } + bta_sys_sendmsg(p_buf); + } + return; +} + +/******************************************************************************* +** +** Function BTA_GATTS_AddCharDescriptor +** +** Description This function is called to add characteristic descriptor. When +** it's done, a callback event BTA_GATTS_ADD_DESCR_EVT is called +** to report the status and an ID number for this descriptor. +** +** Parameters service_id: service ID to which this charatceristic descriptor is to +** be added. +** perm: descriptor access permission. +** p_descr_uuid: descriptor UUID. +** +** Returns returns status. +** +*******************************************************************************/ +void BTA_GATTS_AddCharDescriptor (UINT16 service_id, + tBTA_GATT_PERM perm, + tBT_UUID * p_descr_uuid) +{ + tBTA_GATTS_API_ADD_DESCR *p_buf; + UINT16 len = sizeof(tBTA_GATTS_API_ADD_DESCR); + + + if ((p_buf = (tBTA_GATTS_API_ADD_DESCR *) GKI_getbuf(len)) != NULL) + { + memset(p_buf, 0, len); + + p_buf->hdr.event = BTA_GATTS_API_ADD_DESCR_EVT; + p_buf->hdr.layer_specific = service_id; + p_buf->perm = perm; + + if (p_descr_uuid) + { + memcpy(&p_buf->descr_uuid, p_descr_uuid, sizeof(tBT_UUID)); + } + bta_sys_sendmsg(p_buf); + } + return; + +} + +/******************************************************************************* +** +** Function BTA_GATTS_DeleteService +** +** Description This function is called to delete a service. When this is done, +** a callback event BTA_GATTS_DELETE_EVT is report with the status. +** +** Parameters service_id: service_id to be deleted. +** +** Returns returns none. +** +*******************************************************************************/ +void BTA_GATTS_DeleteService(UINT16 service_id) +{ + BT_HDR *p_buf; + + if ((p_buf = (BT_HDR *) GKI_getbuf(sizeof(BT_HDR))) != NULL) + { + p_buf->event = BTA_GATTS_API_DEL_SRVC_EVT; + + p_buf->layer_specific = service_id; + + bta_sys_sendmsg(p_buf); + } + return; + +} + +/******************************************************************************* +** +** Function BTA_GATTS_StartService +** +** Description This function is called to start a service. +** +** Parameters service_id: the service ID to be started. +** sup_transport: supported trasnport. +** +** Returns None. +** +*******************************************************************************/ +void BTA_GATTS_StartService(UINT16 service_id, tBTA_GATT_TRANSPORT sup_transport) +{ + tBTA_GATTS_API_START *p_buf; + + if ((p_buf = (tBTA_GATTS_API_START *) GKI_getbuf(sizeof(tBTA_GATTS_API_START))) != NULL) + { + p_buf->hdr.event = BTA_GATTS_API_START_SRVC_EVT; + + p_buf->hdr.layer_specific = service_id; + p_buf->transport = sup_transport; + + bta_sys_sendmsg(p_buf); + } + return; +} + +/******************************************************************************* +** +** Function BTA_GATTS_StopService +** +** Description This function is called to stop a service. +** +** Parameters service_id - service to be topped. +** +** Returns None +** +*******************************************************************************/ +void BTA_GATTS_StopService(UINT16 service_id) +{ + BT_HDR *p_buf; + + if ((p_buf = (BT_HDR *) GKI_getbuf(sizeof(BT_HDR))) != NULL) + { + p_buf->event = BTA_GATTS_API_STOP_SRVC_EVT; + + p_buf->layer_specific = service_id; + + bta_sys_sendmsg(p_buf); + } + return; +} + +/******************************************************************************* +** +** Function BTA_GATTS_HandleValueIndication +** +** Description This function is called to read a characteristics descriptor. +** +** Parameters bda - remote device bd address to indicate. +** attr_id - attribute ID to indicate. +** data_len - indicate data length. +** p_data: data to indicate. +** need_confirm - if this indication expects a confirmation or not. +** +** Returns None +** +*******************************************************************************/ +void BTA_GATTS_HandleValueIndication (UINT16 conn_id, UINT16 attr_id, UINT16 data_len, + UINT8 *p_data, BOOLEAN need_confirm) +{ + tBTA_GATTS_API_INDICATION *p_buf; + UINT16 len = sizeof(tBTA_GATTS_API_INDICATION); + + if ((p_buf = (tBTA_GATTS_API_INDICATION *) GKI_getbuf(len)) != NULL) + { + memset(p_buf, 0, len); + + p_buf->hdr.event = BTA_GATTS_API_INDICATION_EVT; + p_buf->hdr.layer_specific = conn_id; + p_buf->attr_id = attr_id; + p_buf->need_confirm = need_confirm; + + if (data_len > 0 && p_data != NULL) + { + p_buf->len = data_len; + memcpy(p_buf->value, p_data, data_len); + + } + bta_sys_sendmsg(p_buf); + } + return; + +} +/******************************************************************************* +** +** Function BTA_GATTS_SendRsp +** +** Description This function is called to send a response to a request. +** +** Parameters conn_id - connection identifier. +** trans_id - transaction ID. +** status - response status +** p_msg - response data. +** +** Returns None +** +*******************************************************************************/ +void BTA_GATTS_SendRsp (UINT16 conn_id, UINT32 trans_id, + tBTA_GATT_STATUS status, tBTA_GATTS_RSP *p_msg) +{ + tBTA_GATTS_API_RSP *p_buf; + UINT16 len = sizeof(tBTA_GATTS_API_RSP) + sizeof(tBTA_GATTS_RSP); + + if ((p_buf = (tBTA_GATTS_API_RSP *) GKI_getbuf(len)) != NULL) + { + memset(p_buf, 0, len); + + p_buf->hdr.event = BTA_GATTS_API_RSP_EVT; + p_buf->hdr.layer_specific = conn_id; + p_buf->trans_id = trans_id; + p_buf->status = status; + + if (p_msg != NULL) + { + p_buf->p_rsp = (tBTA_GATTS_RSP *)(p_buf + 1); + memcpy(p_buf->p_rsp, p_msg, sizeof(tBTA_GATTS_RSP)); + } + + bta_sys_sendmsg(p_buf); + } + return; + +} + + + +/******************************************************************************* +** +** Function BTA_GATTS_Open +** +** Description Open a direct open connection or add a background auto connection +** bd address +** +** Parameters server_if: server interface. +** remote_bda: remote device BD address. +** is_direct: direct connection or background auto connection +** transport : Transport on which GATT connection to be opened (BR/EDR or LE) +** +** Returns void +** +*******************************************************************************/ +void BTA_GATTS_Open(tBTA_GATTS_IF server_if, BD_ADDR remote_bda, BOOLEAN is_direct, + tBTA_GATT_TRANSPORT transport) +{ + tBTA_GATTS_API_OPEN *p_buf; + + if ((p_buf = (tBTA_GATTS_API_OPEN *) GKI_getbuf(sizeof(tBTA_GATTS_API_OPEN))) != NULL) + { + p_buf->hdr.event = BTA_GATTS_API_OPEN_EVT; + p_buf->server_if = server_if; + p_buf->is_direct = is_direct; + p_buf->transport = transport; + memcpy(p_buf->remote_bda, remote_bda, BD_ADDR_LEN); + + bta_sys_sendmsg(p_buf); + } + return; +} + + +/******************************************************************************* +** +** Function BTA_GATTS_CancelOpen +** +** Description Cancel a direct open connection or remove a background auto connection +** bd address +** +** Parameters server_if: server interface. +** remote_bda: remote device BD address. +** is_direct: direct connection or background auto connection +** +** Returns void +** +*******************************************************************************/ +void BTA_GATTS_CancelOpen(tBTA_GATTS_IF server_if, BD_ADDR remote_bda, BOOLEAN is_direct) +{ + tBTA_GATTS_API_CANCEL_OPEN *p_buf; + + if ((p_buf = (tBTA_GATTS_API_CANCEL_OPEN *) GKI_getbuf(sizeof(tBTA_GATTS_API_CANCEL_OPEN))) != NULL) + { + p_buf->hdr.event = BTA_GATTS_API_CANCEL_OPEN_EVT; + p_buf->server_if = server_if; + p_buf->is_direct = is_direct; + memcpy(p_buf->remote_bda, remote_bda, BD_ADDR_LEN); + bta_sys_sendmsg(p_buf); + } + return; +} + +/******************************************************************************* +** +** Function BTA_GATTS_Close +** +** Description Close a connection a remote device. +** +** Parameters conn_id: connectino ID to be closed. +** +** Returns void +** +*******************************************************************************/ +void BTA_GATTS_Close(UINT16 conn_id) +{ + BT_HDR *p_buf; + + if ((p_buf = (BT_HDR *) GKI_getbuf(sizeof(BT_HDR))) != NULL) + { + p_buf->event = BTA_GATTS_API_CLOSE_EVT; + p_buf->layer_specific = conn_id; + bta_sys_sendmsg(p_buf); + } + return; + +} +/******************************************************************************* +** +** Function BTA_GATTS_Listen +** +** Description Start advertisement to listen for connection request for a +** GATT server +** +** Parameters server_if: server interface. +** start: to start or stop listening for connection +** remote_bda: remote device BD address, if listen to all device +** use NULL. +** +** Returns void +** +*******************************************************************************/ +void BTA_GATTS_Listen(tBTA_GATTS_IF server_if, BOOLEAN start, BD_ADDR_PTR target_bda) +{ + tBTA_GATTS_API_LISTEN *p_buf; + + if ((p_buf = (tBTA_GATTS_API_LISTEN *) GKI_getbuf((UINT16)(sizeof(tBTA_GATTS_API_LISTEN) + BD_ADDR_LEN))) != NULL) + { + p_buf->hdr.event = BTA_GATTS_API_LISTEN_EVT; + + p_buf->server_if = server_if; + p_buf->start = start; + + if (target_bda) + { + p_buf->remote_bda = (UINT8*)(p_buf + 1); + memcpy(p_buf->remote_bda, target_bda, BD_ADDR_LEN); + } + else + p_buf->remote_bda = NULL; + + bta_sys_sendmsg(p_buf); + } + return; +} + +#endif /* BTA_GATT_INCLUDED */ diff --git a/components/bt/bluedroid/bta/gatt/bta_gatts_main.c b/components/bt/bluedroid/bta/gatt/bta_gatts_main.c new file mode 100755 index 0000000000..716c7c94ea --- /dev/null +++ b/components/bt/bluedroid/bta/gatt/bta_gatts_main.c @@ -0,0 +1,144 @@ +/****************************************************************************** + * + * Copyright (C) 2003-2012 Broadcom Corporation + * + * 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 GATT server main functions and state machine. + * + ******************************************************************************/ + +#include "bt_target.h" + +#if defined(BTA_GATT_INCLUDED) && (BTA_GATT_INCLUDED == TRUE) + +#include + +#include "bta_gatts_int.h" +#include "gki.h" + +/* type for service building action functions */ +typedef void (*tBTA_GATTS_SRVC_ACT)(tBTA_GATTS_SRVC_CB *p_rcb, tBTA_GATTS_DATA *p_data); + +/* service building action function list */ +const tBTA_GATTS_SRVC_ACT bta_gatts_srvc_build_act[] = +{ + bta_gatts_add_include_srvc, + bta_gatts_add_char, + bta_gatts_add_char_descr, + bta_gatts_delete_service, + bta_gatts_start_service, + bta_gatts_stop_service, +}; + +/* GATTS control block */ +#if BTA_DYNAMIC_MEMORY == FALSE +tBTA_GATTS_CB bta_gatts_cb; +#endif + +/******************************************************************************* +** +** Function bta_gatts_hdl_event +** +** Description BTA GATT server main event handling function. +** +** +** Returns void +** +*******************************************************************************/ +BOOLEAN bta_gatts_hdl_event(BT_HDR *p_msg) +{ + tBTA_GATTS_CB *p_cb = &bta_gatts_cb; + tBTA_GATTS_SRVC_CB *p_srvc_cb = NULL; + + switch (p_msg->event) + { + case BTA_GATTS_API_DISABLE_EVT: + bta_gatts_api_disable(p_cb); + break; + + case BTA_GATTS_API_REG_EVT: + LOG_ERROR("bta_gatts_register\n"); + bta_gatts_register(p_cb, (tBTA_GATTS_DATA *) p_msg); + break; + + case BTA_GATTS_INT_START_IF_EVT: + bta_gatts_start_if(p_cb, (tBTA_GATTS_DATA *) p_msg); + break; + + case BTA_GATTS_API_DEREG_EVT: + bta_gatts_deregister(p_cb, (tBTA_GATTS_DATA *) p_msg); + break; + + case BTA_GATTS_API_CREATE_SRVC_EVT: + bta_gatts_create_srvc(p_cb, (tBTA_GATTS_DATA *) p_msg); + break; + + case BTA_GATTS_API_INDICATION_EVT: + bta_gatts_indicate_handle(p_cb,(tBTA_GATTS_DATA *) p_msg); + break; + + case BTA_GATTS_API_OPEN_EVT: + bta_gatts_open(p_cb,(tBTA_GATTS_DATA *) p_msg); + break; + + case BTA_GATTS_API_CANCEL_OPEN_EVT: + bta_gatts_cancel_open(p_cb,(tBTA_GATTS_DATA *) p_msg); + break; + + case BTA_GATTS_API_CLOSE_EVT: + bta_gatts_close(p_cb,(tBTA_GATTS_DATA *) p_msg); + break; + + case BTA_GATTS_API_RSP_EVT: + bta_gatts_send_rsp(p_cb,(tBTA_GATTS_DATA *) p_msg); + break; + + case BTA_GATTS_API_LISTEN_EVT: + bta_gatts_listen(p_cb,(tBTA_GATTS_DATA *) p_msg); + break; + + + case BTA_GATTS_API_ADD_INCL_SRVC_EVT: + case BTA_GATTS_API_ADD_CHAR_EVT: + case BTA_GATTS_API_ADD_DESCR_EVT: + case BTA_GATTS_API_DEL_SRVC_EVT: + case BTA_GATTS_API_START_SRVC_EVT: + case BTA_GATTS_API_STOP_SRVC_EVT: + + p_srvc_cb = bta_gatts_find_srvc_cb_by_srvc_id(p_cb, + ((tBTA_GATTS_DATA *)p_msg)->api_add_incl_srvc.hdr.layer_specific); + + if (p_srvc_cb != NULL) + { + bta_gatts_srvc_build_act[p_msg->event - BTA_GATTS_API_ADD_INCL_SRVC_EVT](p_srvc_cb, (tBTA_GATTS_DATA *) p_msg); + } + else + { + APPL_TRACE_ERROR("service not created"); + } + break; + + default: + break; + } + + + return (TRUE); +} + +#endif /* BTA_GATT_INCLUDED */ diff --git a/components/bt/bluedroid/bta/gatt/bta_gatts_utils.c b/components/bt/bluedroid/bta/gatt/bta_gatts_utils.c new file mode 100755 index 0000000000..c5deef3024 --- /dev/null +++ b/components/bt/bluedroid/bta/gatt/bta_gatts_utils.c @@ -0,0 +1,234 @@ +/****************************************************************************** + * + * Copyright (C) 2003-2012 Broadcom Corporation + * + * 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 GATT client utility function. + * + ******************************************************************************/ + +#include "bt_target.h" + +#if defined(BTA_GATT_INCLUDED) && (BTA_GATT_INCLUDED == TRUE) + +#include +#include "utl.h" +#include "gki.h" +#include "bta_sys.h" +#include "bta_gatts_int.h" + +static const UINT8 base_uuid[LEN_UUID_128] = {0xFB, 0x34, 0x9B, 0x5F, 0x80, 0x00, 0x00, 0x80, + 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + +/******************************************************************************* +** +** Function bta_gatt_convert_uuid16_to_uuid128 +** +** Description Convert a 16 bits UUID to be an standard 128 bits one. +** +** Returns TRUE if two uuid match; FALSE otherwise. +** +*******************************************************************************/ +static void bta_gatt_convert_uuid16_to_uuid128(UINT8 uuid_128[LEN_UUID_128], UINT16 uuid_16) +{ + UINT8 *p = &uuid_128[LEN_UUID_128 - 4]; + + memcpy (uuid_128, base_uuid, LEN_UUID_128); + + UINT16_TO_STREAM(p, uuid_16); +} +/******************************************************************************* +** +** Function bta_gatts_alloc_srvc_cb +** +** Description allocate a service control block. +** +** Returns pointer to the control block, or otherwise NULL when failed. +** +*******************************************************************************/ +UINT8 bta_gatts_alloc_srvc_cb(tBTA_GATTS_CB *p_cb, UINT8 rcb_idx) +{ + UINT8 i; + + for (i = 0; i < BTA_GATTS_MAX_SRVC_NUM; i ++) + { + if (!p_cb->srvc_cb[i].in_use) + { + p_cb->srvc_cb[i].in_use = TRUE; + p_cb->srvc_cb[i].rcb_idx = rcb_idx; + return i; + } + } + return BTA_GATTS_INVALID_APP; +} + +/******************************************************************************* +** +** Function bta_gatts_find_app_rcb_by_app_if +** +** Description find the index of the application control block by app ID. +** +** Returns pointer to the control block if success, otherwise NULL +** +*******************************************************************************/ +tBTA_GATTS_RCB *bta_gatts_find_app_rcb_by_app_if(tBTA_GATTS_IF server_if) +{ + UINT8 i; + tBTA_GATTS_RCB *p_reg; + + for (i = 0, p_reg = bta_gatts_cb.rcb; i < BTA_GATTS_MAX_APP_NUM; i ++, p_reg++) + { + if (p_reg->in_use && p_reg->gatt_if == server_if) + return p_reg; + } + return NULL; +} + +/******************************************************************************* +** +** Function bta_gatts_find_app_rcb_idx_by_app_if +** +** Description find the index of the application control block by app ID. +** +** Returns index of the control block, or BTA_GATTS_INVALID_APP if failed. +** +*******************************************************************************/ + +UINT8 bta_gatts_find_app_rcb_idx_by_app_if(tBTA_GATTS_CB *p_cb, tBTA_GATTS_IF server_if) +{ + UINT8 i; + + for (i = 0; i < BTA_GATTS_MAX_APP_NUM; i ++) + { + if (p_cb->rcb[i].in_use && p_cb->rcb[i].gatt_if == server_if) + return i; + } + return BTA_GATTS_INVALID_APP; +} +/******************************************************************************* +** +** Function bta_gatts_find_srvc_cb_by_srvc_id +** +** Description find the service control block by service ID. +** +** Returns pointer to the rcb. +** +*******************************************************************************/ +tBTA_GATTS_SRVC_CB * bta_gatts_find_srvc_cb_by_srvc_id(tBTA_GATTS_CB *p_cb, UINT16 service_id) +{ + UINT8 i; + APPL_TRACE_DEBUG("bta_gatts_find_srvc_cb_by_srvc_id service_id=%d", service_id); + for (i = 0; i < BTA_GATTS_MAX_SRVC_NUM; i ++) + { + if (p_cb->srvc_cb[i].in_use && + p_cb->srvc_cb[i].service_id == service_id) + { + APPL_TRACE_DEBUG("bta_gatts_find_srvc_cb_by_srvc_id found service cb index =%d", i); + return &p_cb->srvc_cb[i]; + } + } + return NULL; +} +/******************************************************************************* +** +** Function bta_gatts_find_srvc_cb_by_attr_id +** +** Description find the service control block by attribute ID. +** +** Returns pointer to the rcb. +** +*******************************************************************************/ +tBTA_GATTS_SRVC_CB * bta_gatts_find_srvc_cb_by_attr_id(tBTA_GATTS_CB *p_cb, UINT16 attr_id) +{ + UINT8 i; + + for (i = 0; i < (BTA_GATTS_MAX_SRVC_NUM); i ++) + { + if (/* middle service */ + (i < (BTA_GATTS_MAX_SRVC_NUM - 1) && + p_cb->srvc_cb[i].in_use && + p_cb->srvc_cb[i + 1].in_use && + attr_id >= p_cb->srvc_cb[i].service_id && + attr_id < p_cb->srvc_cb[i + 1].service_id) || + /* last active service */ + (i < (BTA_GATTS_MAX_SRVC_NUM - 1) && + p_cb->srvc_cb[i].in_use && + !p_cb->srvc_cb[i + 1].in_use && + attr_id >= p_cb->srvc_cb[i].service_id) || + /* last service incb */ + (i == (BTA_GATTS_MAX_SRVC_NUM - 1) && + attr_id >= p_cb->srvc_cb[i].service_id) + ) + { + return &p_cb->srvc_cb[i]; + } + } + return NULL; +} +/******************************************************************************* +** +** Function bta_gatts_uuid_compare +** +** Description Compare two UUID to see if they are the same. +** +** Returns TRUE if two uuid match; FALSE otherwise. +** +*******************************************************************************/ +BOOLEAN bta_gatts_uuid_compare(tBT_UUID tar, tBT_UUID src) +{ + UINT8 su[LEN_UUID_128], tu[LEN_UUID_128]; + UINT8 *ps, *pt; + + /* any of the UUID is unspecified */ + if (src.len == 0 || tar.len == 0) + { + return TRUE; + } + + /* If both are 16-bit, we can do a simple compare */ + if (src.len == 2 && tar.len == 2) + { + return src.uu.uuid16 == tar.uu.uuid16; + } + + /* One or both of the UUIDs is 128-bit */ + if (src.len == LEN_UUID_16) + { + /* convert a 16 bits UUID to 128 bits value */ + bta_gatt_convert_uuid16_to_uuid128(su, src.uu.uuid16); + ps = su; + } + else + ps = src.uu.uuid128; + + if (tar.len == LEN_UUID_16) + { + /* convert a 16 bits UUID to 128 bits value */ + bta_gatt_convert_uuid16_to_uuid128(tu, tar.uu.uuid16); + pt = tu; + } + else + pt = tar.uu.uuid128; + + return(memcmp(ps, pt, LEN_UUID_128) == 0); +} + + + + +#endif diff --git a/components/bt/bluedroid/bta/hh/bta_hh_act.c b/components/bt/bluedroid/bta/hh/bta_hh_act.c new file mode 100644 index 0000000000..fdcc998211 --- /dev/null +++ b/components/bt/bluedroid/bta/hh/bta_hh_act.c @@ -0,0 +1,1329 @@ +/****************************************************************************** + * + * Copyright (C) 2005-2012 Broadcom Corporation + * + * 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 HID host action functions. + * + ******************************************************************************/ + +#include "bt_target.h" + +#if defined(BTA_HH_INCLUDED) && (BTA_HH_INCLUDED == TRUE) + +#include + +#include "bta_sys.h" +#include "btm_api.h" +#include "l2c_api.h" +#include "bta_hh_int.h" +#include "bta_hh_co.h" +#include "utl.h" + +/***************************************************************************** +** Constants +*****************************************************************************/ + + +/***************************************************************************** +** Local Function prototypes +*****************************************************************************/ +static void bta_hh_cback (UINT8 dev_handle, BD_ADDR addr, UINT8 event, + UINT32 data, BT_HDR *pdata); +static tBTA_HH_STATUS bta_hh_get_trans_status(UINT32 result); + +#if BTA_HH_DEBUG +static char* bta_hh_get_w4_event(UINT16 event); +static char * bta_hh_hid_event_name(UINT16 event); +#endif + +/***************************************************************************** +** Action Functions +*****************************************************************************/ +/******************************************************************************* +** +** Function bta_hh_api_enable +** +** Description Perform necessary operations to enable HID host. +** +** +** Returns void +** +*******************************************************************************/ +void bta_hh_api_enable(tBTA_HH_DATA *p_data) +{ + tBTA_HH_STATUS status = BTA_HH_ERR; + UINT8 xx; + + /* initialize BTE HID */ + HID_HostInit(); + + memset(&bta_hh_cb, 0, sizeof(tBTA_HH_CB)); + + HID_HostSetSecurityLevel("", p_data->api_enable.sec_mask); + + /* Register with L2CAP */ + if ( HID_HostRegister (bta_hh_cback) == HID_SUCCESS) + { + /* store parameters */ + bta_hh_cb.p_cback = p_data->api_enable.p_cback; + + status = BTA_HH_OK; + /* initialize device CB */ + for (xx = 0; xx < BTA_HH_MAX_DEVICE; xx ++) + { + bta_hh_cb.kdev[xx].state = BTA_HH_IDLE_ST; + bta_hh_cb.kdev[xx].hid_handle = BTA_HH_INVALID_HANDLE; + bta_hh_cb.kdev[xx].index = xx; + } + + /* initialize control block map */ + for (xx = 0; xx < BTA_HH_MAX_KNOWN; xx ++) + bta_hh_cb.cb_index[xx] = BTA_HH_IDX_INVALID; + } + +#if (BTA_HH_LE_INCLUDED == TRUE) + if (status == BTA_HH_OK) + { + bta_hh_le_enable(); + } + else +#endif + /* signal BTA call back event */ + (* bta_hh_cb.p_cback)(BTA_HH_ENABLE_EVT, (tBTA_HH *)&status); +} +/******************************************************************************* +** +** Function bta_hh_api_disable +** +** Description Perform necessary operations to disable HID host. +** +** +** Returns void +** +*******************************************************************************/ +void bta_hh_api_disable(void) +{ + UINT8 xx; + + /* service is not enabled */ + if (bta_hh_cb.p_cback == NULL) + return; + + /* no live connection, signal DISC_CMPL_EVT directly */ + if (!bta_hh_cb.cnt_num) + { + bta_hh_disc_cmpl(); + } + else /* otherwise, disconnect all live connections */ + { + bta_hh_cb.w4_disable = TRUE; + + for(xx = 0; xx < BTA_HH_MAX_DEVICE; xx ++) + { + /* send API_CLOSE event to every connected device */ + if ( bta_hh_cb.kdev[xx].state == BTA_HH_CONN_ST ) + { + /* disconnect all connected devices */ + bta_hh_sm_execute(&bta_hh_cb.kdev[xx], + BTA_HH_API_CLOSE_EVT, + NULL); + } + } + } + + return; +} + +/******************************************************************************* +** +** Function bta_hh_disc_cmpl +** +** Description All connections have been closed, disable service. +** +** +** Returns void +** +*******************************************************************************/ +void bta_hh_disc_cmpl(void) +{ + tBTA_HH_STATUS status = BTA_HH_OK; + + /* Deregister with lower layer */ + if (HID_HostDeregister() != HID_SUCCESS) + status = BTA_HH_ERR; + +#if (BTA_HH_LE_INCLUDED == TRUE) + bta_hh_le_deregister(); + UNUSED(status); +#else + bta_hh_cleanup_disable(status); +#endif +} + +/******************************************************************************* +** +** Function bta_hh_sdp_cback +** +** Description SDP callback function. +** +** Returns void +** +*******************************************************************************/ +static void bta_hh_sdp_cback(UINT16 result, UINT16 attr_mask, + tHID_DEV_SDP_INFO *sdp_rec ) +{ + tBTA_HH_DEV_CB *p_cb = bta_hh_cb.p_cur; + UINT8 hdl = 0; + tBTA_HH_STATUS status = BTA_HH_ERR_SDP; + + /* make sure sdp succeeded and hh has not been disabled */ + if ((result == SDP_SUCCESS) && (p_cb != NULL)) + { + /* security is required for the connection, add attr_mask bit*/ + if (p_cb->sec_mask) + attr_mask |= HID_SEC_REQUIRED; + +#if BTA_HH_DEBUG + APPL_TRACE_EVENT("bta_hh_sdp_cback: p_cb: %d result 0x%02x, \ + attr_mask 0x%02x, handle %x", \ + p_cb, result, attr_mask,p_cb->hid_handle); +#endif + + /* check to see type of device is supported , and should not been added before */ + if (bta_hh_tod_spt(p_cb, sdp_rec->sub_class)) + { + /* if not added before */ + if (p_cb->hid_handle == BTA_HH_INVALID_HANDLE) + { + /* add device/update attr_mask information */ + if(HID_HostAddDev (p_cb->addr, attr_mask, &hdl) == HID_SUCCESS) + { + status = BTA_HH_OK; + /* update cb_index[] map */ + bta_hh_cb.cb_index[hdl] = p_cb->index; + } + else + { + p_cb->app_id = 0; + } + } + else + { + hdl = p_cb->hid_handle; + } + /* else : incoming connection after SDP should update the SDP information as well */ + + if (p_cb->app_id != 0) + { + /* update cb information with attr_mask, dscp_info etc. */ + bta_hh_add_device_to_list(p_cb, hdl, attr_mask, + &sdp_rec->dscp_info, + sdp_rec->sub_class, + sdp_rec->ssr_max_latency, + sdp_rec->ssr_min_tout, + p_cb->app_id); + + p_cb->dscp_info.ctry_code = sdp_rec->ctry_code; + + status = BTA_HH_OK; + } + + } + else /* type of device is not supported */ + status = BTA_HH_ERR_TOD_UNSPT; + } + + /* free disc_db when SDP is completed */ + utl_freebuf((void **)&bta_hh_cb.p_disc_db); + + /* send SDP_CMPL_EVT into state machine */ + bta_hh_sm_execute(p_cb, BTA_HH_SDP_CMPL_EVT, (tBTA_HH_DATA *)&status); + + return; +} +/******************************************************************************* +** +** Function bta_hh_di_sdp_cback +** +** Description SDP DI callback function. +** +** Returns void +** +*******************************************************************************/ +static void bta_hh_di_sdp_cback(UINT16 result) +{ + tBTA_HH_DEV_CB *p_cb = bta_hh_cb.p_cur; + tBTA_HH_STATUS status = BTA_HH_ERR_SDP; + tSDP_DI_GET_RECORD di_rec; + tHID_STATUS ret; +#if BTA_HH_DEBUG + APPL_TRACE_EVENT("bta_hh_di_sdp_cback: p_cb: %d result 0x%02x", p_cb, result); +#endif + + /* if DI record does not exist on remote device, vendor_id in tBTA_HH_DEV_DSCP_INFO will be + * set to 0xffff and we will allow the connection to go through. Spec mandates that DI + * record be set, but many HID devices do not set this. So for IOP purposes, we allow the + * connection to go through and update the DI record to invalid DI entry.*/ + if (((result == SDP_SUCCESS) || (result == SDP_NO_RECS_MATCH)) && (p_cb != NULL)) + { + if(result == SDP_SUCCESS && SDP_GetNumDiRecords(bta_hh_cb.p_disc_db) != 0) + { + /* always update information with primary DI record */ + if (SDP_GetDiRecord(1, &di_rec, bta_hh_cb.p_disc_db) == SDP_SUCCESS) + { + bta_hh_update_di_info(p_cb, di_rec.rec.vendor, di_rec.rec.product, di_rec.rec.version, 0); + } + + } + else /* no DI recrod available */ + { + bta_hh_update_di_info(p_cb, BTA_HH_VENDOR_ID_INVALID, 0, 0, 0); + } + + if ((ret = HID_HostGetSDPRecord(p_cb->addr, + bta_hh_cb.p_disc_db, + p_bta_hh_cfg->sdp_db_size, + bta_hh_sdp_cback)) == HID_SUCCESS) + { + status = BTA_HH_OK; + } + else + { +#if BTA_HH_DEBUG + APPL_TRACE_DEBUG ("bta_hh_di_sdp_cback: HID_HostGetSDPRecord failed: Status 0x%2x", + ret); +#endif + } + } + + + if (status != BTA_HH_OK) + { + utl_freebuf((void **)&bta_hh_cb.p_disc_db); + /* send SDP_CMPL_EVT into state machine */ + bta_hh_sm_execute(p_cb, BTA_HH_SDP_CMPL_EVT, (tBTA_HH_DATA *)&status); + } + return; + +} + + +/******************************************************************************* +** +** Function bta_hh_start_sdp +** +** Description Start SDP service search, and obtain necessary SDP records. +** Only one SDP service search request is allowed at the same +** time. For every BTA_HhOpen API call, do SDP first unless SDP +** has been done previously. +** +** Returns void +** +*******************************************************************************/ +void bta_hh_start_sdp(tBTA_HH_DEV_CB *p_cb, tBTA_HH_DATA *p_data) +{ + tBTA_HH_STATUS status = BTA_HH_ERR_SDP; + UINT8 hdl; + + p_cb->sec_mask = p_data->api_conn.sec_mask; + p_cb->mode = p_data->api_conn.mode; + bta_hh_cb.p_cur = p_cb; + +#if (BTA_HH_LE_INCLUDED == TRUE) + if (bta_hh_is_le_device(p_cb, p_data->api_conn.bd_addr)) + { + bta_hh_le_open_conn(p_cb, p_data->api_conn.bd_addr); + return; + } +#endif + + /* if previously virtually cabled device, skip SDP */ + if (p_cb->app_id) + { + status = BTA_HH_OK; +#if BTA_HH_DEBUG + APPL_TRACE_DEBUG("bta_hh_start_sdp:: skip SDP for known devices"); +#endif + if (p_cb->hid_handle == BTA_HH_INVALID_HANDLE) + { + if (HID_HostAddDev (p_cb->addr, p_cb->attr_mask, &hdl) \ + == HID_SUCCESS) + { + /* update device CB with newly register device handle */ + bta_hh_add_device_to_list(p_cb, hdl, p_cb->attr_mask, NULL, + p_cb->sub_class, + p_cb->dscp_info.ssr_max_latency, + p_cb->dscp_info.ssr_min_tout, + p_cb->app_id); + /* update cb_index[] map */ + bta_hh_cb.cb_index[hdl] = p_cb->index; + } + else + status = BTA_HH_ERR_NO_RES; + } + bta_hh_sm_execute(p_cb, BTA_HH_SDP_CMPL_EVT, (tBTA_HH_DATA *)&status); + + return; + } + /* GetSDPRecord. at one time only one SDP precedure can be active */ + else if (!bta_hh_cb.p_disc_db) + { + bta_hh_cb.p_disc_db = (tSDP_DISCOVERY_DB *) GKI_getbuf(p_bta_hh_cfg->sdp_db_size); + + if (bta_hh_cb.p_disc_db == NULL) + { + status = BTA_HH_ERR_NO_RES; + } + else + { + bta_hh_cb.p_cur = p_cb; + /* do DI discovery first */ + if (SDP_DiDiscover(p_data->api_conn.bd_addr, + bta_hh_cb.p_disc_db, + p_bta_hh_cfg->sdp_db_size, + bta_hh_di_sdp_cback) != SDP_SUCCESS) + { +#if BTA_HH_DEBUG + APPL_TRACE_DEBUG ("bta_hh_start_sdp: SDP_DiDiscover failed: \ + Status 0x%2X",status); +#endif + status = BTA_HH_ERR_SDP; + utl_freebuf((void **)&bta_hh_cb.p_disc_db); + } + else + status = BTA_HH_OK; + } + } + + if (status != BTA_HH_OK) + bta_hh_sm_execute(p_cb, BTA_HH_SDP_CMPL_EVT, (tBTA_HH_DATA *)&status); + + return; + +} +/******************************************************************************* +** +** Function bta_hh_sdp_cmpl +** +** Description When SDP completed, initiate a connection or report error depend +** on SDP result. +** +** +** Returns void +** +*******************************************************************************/ +void bta_hh_sdp_cmpl(tBTA_HH_DEV_CB *p_cb, tBTA_HH_DATA *p_data) +{ + tBTA_HH_CONN conn_dat; + tBTA_HH_STATUS status = p_data->status; + +#if BTA_HH_DEBUG + APPL_TRACE_DEBUG ("bta_hh_sdp_cmpl: status 0x%2X",p_data->status); +#endif + + /* initialize call back data */ + memset((void *)&conn_dat, 0, sizeof(tBTA_HH_CONN)); + conn_dat.handle = p_cb->hid_handle; + bdcpy(conn_dat.bda, p_cb->addr); + + /* if SDP compl success */ + if ( status == BTA_HH_OK) + { + /* not incoming connection doing SDP, initiate a HID connection */ + if (!p_cb->incoming_conn) + { + tHID_STATUS ret; + /* set security level */ + HID_HostSetSecurityLevel("", p_cb->sec_mask); + + /* open HID connection */ + if ((ret = HID_HostOpenDev (p_cb->hid_handle)) != HID_SUCCESS) + { +#if BTA_HH_DEBUG + APPL_TRACE_DEBUG ("bta_hh_sdp_cmpl: HID_HostOpenDev failed: \ + Status 0x%2X",ret); +#endif + /* open fail, remove device from management device list */ + HID_HostRemoveDev( p_cb->hid_handle); + status = BTA_HH_ERR; + } + else + { + status = BTA_HH_OK; + } + } + else /* incoming connection SDP finish */ + { + bta_hh_sm_execute(p_cb, BTA_HH_OPEN_CMPL_EVT, NULL); + } + } + + if (status != BTA_HH_OK) + { + /* Check if this was incoming connection request from an unknown device + **and connection failed due to missing HID Device SDP UUID + **In above condition, disconnect the link as well as remove the + **device from list of HID devices*/ + if ((status == BTA_HH_ERR_SDP) && + (p_cb->incoming_conn) &&(p_cb->app_id == 0)) + { + APPL_TRACE_DEBUG ("bta_hh_sdp_cmpl:SDP failed for incoming conn :hndl %d", + p_cb->incoming_hid_handle); + HID_HostRemoveDev( p_cb->incoming_hid_handle); + } + conn_dat.status = status; + (* bta_hh_cb.p_cback)(BTA_HH_OPEN_EVT, (tBTA_HH *)&conn_dat); + + /* move state machine W4_CONN ->IDLE */ + bta_hh_sm_execute(p_cb, BTA_HH_API_CLOSE_EVT, NULL); + + /* if this is an outgoing connection to an unknown device, clean up cb */ + if (p_cb->app_id == 0 && !p_cb->incoming_conn) + { + /* clean up device control block */ + bta_hh_clean_up_kdev(p_cb); + } +#if BTA_HH_DEBUG + bta_hh_trace_dev_db(); +#endif + } + return; +} + +/******************************************************************************* +** +** Function bta_hh_api_disc_act +** +** Description HID Host initiate a disconnection. +** +** +** Returns void +** +*******************************************************************************/ +void bta_hh_api_disc_act(tBTA_HH_DEV_CB *p_cb, tBTA_HH_DATA *p_data) +{ + tBTA_HH_CBDATA disc_dat; + tHID_STATUS status; + +#if BTA_HH_LE_INCLUDED == TRUE + if (p_cb->is_le_device) + bta_hh_le_api_disc_act(p_cb); + else +#endif + { + /* found an active connection */ + disc_dat.handle = p_data ?(UINT8)p_data->hdr.layer_specific :p_cb->hid_handle; + disc_dat.status = BTA_HH_ERR; + + status = HID_HostCloseDev(disc_dat.handle); + + if (status) + (* bta_hh_cb.p_cback)(BTA_HH_CLOSE_EVT, (tBTA_HH *)&disc_dat); + } + + return; + +} +/******************************************************************************* +** +** Function bta_hh_open_cmpl_act +** +** Description HID host connection completed +** +** +** Returns void +** +*******************************************************************************/ +void bta_hh_open_cmpl_act(tBTA_HH_DEV_CB *p_cb, tBTA_HH_DATA *p_data) +{ + tBTA_HH_CONN conn ; + UINT8 dev_handle = p_data ? (UINT8)p_data->hid_cback.hdr.layer_specific : \ + p_cb->hid_handle; + + memset((void *)&conn, 0, sizeof (tBTA_HH_CONN)); + conn.handle = dev_handle; + bdcpy(conn.bda, p_cb->addr); + + /* increase connection number */ + bta_hh_cb.cnt_num ++; + + /* initialize device driver */ + bta_hh_co_open(p_cb->hid_handle, p_cb->sub_class, + p_cb->attr_mask, p_cb->app_id); + +#if (BTA_HH_LE_INCLUDED == TRUE) + conn.status = p_cb->status; + conn.le_hid = p_cb->is_le_device; + conn.scps_supported = p_cb->scps_supported; + + if (!p_cb->is_le_device) +#endif + { + /* inform role manager */ + bta_sys_conn_open( BTA_ID_HH ,p_cb->app_id, p_cb->addr); + } + /* set protocol mode when not default report mode */ + if ( p_cb->mode != BTA_HH_PROTO_RPT_MODE +#if (BTA_HH_LE_INCLUDED == TRUE) + && !p_cb->is_le_device +#endif + ) + { + if ((HID_HostWriteDev(dev_handle, + HID_TRANS_SET_PROTOCOL, HID_PAR_PROTOCOL_BOOT_MODE, + 0, + 0, NULL)) != HID_SUCCESS) + { + /* HID connection is up, while SET_PROTO fail */ + conn.status = BTA_HH_ERR_PROTO; + (* bta_hh_cb.p_cback)(BTA_HH_OPEN_EVT, (tBTA_HH *)&conn); + } + else + { + conn.status = BTA_HH_OK; + p_cb->w4_evt = BTA_HH_OPEN_EVT; + } + } + else + (* bta_hh_cb.p_cback)(BTA_HH_OPEN_EVT, (tBTA_HH *)&conn); + + p_cb->incoming_conn = FALSE; + p_cb->incoming_hid_handle = BTA_HH_INVALID_HANDLE; + +} +/******************************************************************************* +** +** Function bta_hh_open_act +** +** Description HID host receive HID_OPEN_EVT . +** +** +** Returns void +** +*******************************************************************************/ +void bta_hh_open_act(tBTA_HH_DEV_CB *p_cb, tBTA_HH_DATA *p_data) +{ + tBTA_HH_API_CONN conn_data; + + UINT8 dev_handle = p_data ? (UINT8)p_data->hid_cback.hdr.layer_specific : \ + p_cb->hid_handle; + +#if BTA_HH_DEBUG + APPL_TRACE_EVENT ("bta_hh_open_act: Device[%d] connected", dev_handle); +#endif + + /* SDP has been done */ + if (p_cb->app_id != 0) + { + bta_hh_sm_execute(p_cb, BTA_HH_OPEN_CMPL_EVT, p_data); + } + else + /* app_id == 0 indicates an incoming conenction request arrives without SDP + performed, do it first */ + { + p_cb->incoming_conn = TRUE; + /* store the handle here in case sdp fails - need to disconnect */ + p_cb->incoming_hid_handle = dev_handle; + + memset(&conn_data, 0, sizeof(tBTA_HH_API_CONN)); + bdcpy(conn_data.bd_addr, p_cb->addr); + bta_hh_start_sdp(p_cb, (tBTA_HH_DATA *)&conn_data); + } + + return; +} + + +/******************************************************************************* +** +** Function bta_hh_data_act +** +** Description HID Host process a data report +** +** +** Returns void +** +*******************************************************************************/ +void bta_hh_data_act(tBTA_HH_DEV_CB *p_cb, tBTA_HH_DATA * p_data) +{ + BT_HDR *pdata = p_data->hid_cback.p_data; + UINT8 *p_rpt = (UINT8 *)(pdata + 1) + pdata->offset; + + bta_hh_co_data((UINT8)p_data->hid_cback.hdr.layer_specific, p_rpt, pdata->len, + p_cb->mode, p_cb->sub_class, p_cb->dscp_info.ctry_code, p_cb->addr, p_cb->app_id); + + utl_freebuf((void **)&pdata); +} + + +/******************************************************************************* +** +** Function bta_hh_handsk_act +** +** Description HID Host process a handshake acknoledgement. +** +** +** Returns void +** +*******************************************************************************/ +void bta_hh_handsk_act(tBTA_HH_DEV_CB *p_cb, tBTA_HH_DATA * p_data) +{ + tBTA_HH_CBDATA cback_data ; + tBTA_HH_HSDATA hs_data; + tBTA_HH_CONN conn ; + +#if BTA_HH_DEBUG + APPL_TRACE_DEBUG("HANDSHAKE received for: event = %s data= %d", + bta_hh_get_w4_event(p_cb->w4_evt), p_data->hid_cback.data); +#endif + + memset(&hs_data, 0, sizeof(tBTA_HH_HSDATA)); + memset(&cback_data, 0, sizeof(tBTA_HH_CBDATA)); + + switch (p_cb->w4_evt) + { + /* GET_ transsaction, handshake indicate unsupported request */ + case BTA_HH_GET_PROTO_EVT: + hs_data.rsp_data.proto_mode = BTA_HH_PROTO_UNKNOWN; + /* fall through */ + case BTA_HH_GET_RPT_EVT: + case BTA_HH_GET_IDLE_EVT : + hs_data.handle = p_cb->hid_handle; + /* if handshake gives an OK code for these transaction, fill in UNSUPT */ + if ((hs_data.status = bta_hh_get_trans_status(p_data->hid_cback.data)) == BTA_HH_OK) + hs_data.status = BTA_HH_HS_TRANS_NOT_SPT; + + (* bta_hh_cb.p_cback)(p_cb->w4_evt, (tBTA_HH *)&hs_data); + p_cb->w4_evt = 0; + break; + + /* acknoledgement from HID device for SET_ transaction */ + case BTA_HH_SET_RPT_EVT: + case BTA_HH_SET_PROTO_EVT: + case BTA_HH_SET_IDLE_EVT : + cback_data.handle = p_cb->hid_handle; + cback_data.status = bta_hh_get_trans_status(p_data->hid_cback.data); + (* bta_hh_cb.p_cback)(p_cb->w4_evt, (tBTA_HH *)&cback_data); + p_cb->w4_evt = 0; + break; + + /* SET_PROTOCOL when open connection */ + case BTA_HH_OPEN_EVT: + conn.status =p_data->hid_cback.data ? BTA_HH_ERR_PROTO: BTA_HH_OK; + conn.handle = p_cb->hid_handle; + bdcpy(conn.bda, p_cb->addr); + (* bta_hh_cb.p_cback)(p_cb->w4_evt, (tBTA_HH *)&conn); +#if BTA_HH_DEBUG + bta_hh_trace_dev_db(); +#endif + p_cb->w4_evt = 0; + break; + + default: + /* unknow transaction handshake response */ + APPL_TRACE_DEBUG("unknown transaction type"); + break; + } + + /* transaction achknoledgement received, inform PM for mode change */ + bta_sys_idle(BTA_ID_HH, p_cb->app_id, p_cb->addr); + return; +} +/******************************************************************************* +** +** Function bta_hh_ctrl_dat_act +** +** Description HID Host process a data report from control channel. +** +** +** Returns void +** +*******************************************************************************/ +void bta_hh_ctrl_dat_act(tBTA_HH_DEV_CB *p_cb, tBTA_HH_DATA * p_data) +{ + BT_HDR *pdata = p_data->hid_cback.p_data; + UINT8 *data = (UINT8 *)(pdata + 1) + pdata->offset; + tBTA_HH_HSDATA hs_data; + +#if BTA_HH_DEBUG + APPL_TRACE_DEBUG("Ctrl DATA received w4: event[%s]", + bta_hh_get_w4_event(p_cb->w4_evt)); +#endif + hs_data.status = BTA_HH_OK; + hs_data.handle = p_cb->hid_handle; + + switch (p_cb->w4_evt) + { + case BTA_HH_GET_IDLE_EVT: + hs_data.rsp_data.idle_rate = *data; + break; + case BTA_HH_GET_RPT_EVT: + hs_data.rsp_data.p_rpt_data = pdata; + break; + case BTA_HH_GET_PROTO_EVT: + /* match up BTE/BTA report/boot mode def*/ + hs_data.rsp_data.proto_mode = ((*data) == HID_PAR_PROTOCOL_REPORT)? \ + BTA_HH_PROTO_RPT_MODE : BTA_HH_PROTO_BOOT_MODE; +#if BTA_HH_DEBUG + APPL_TRACE_DEBUG("GET_PROTOCOL Mode = [%s]", + (hs_data.rsp_data.proto_mode == BTA_HH_PROTO_RPT_MODE)? "Report" : "Boot"); +#endif + break; + /* should not expect control DATA for SET_ transaction */ + case BTA_HH_SET_PROTO_EVT: + /* fall through */ + case BTA_HH_SET_RPT_EVT: + /* fall through */ + case BTA_HH_SET_IDLE_EVT : + /* fall through */ + default: +#if BTA_HH_DEBUG + APPL_TRACE_DEBUG("invalid transaction type for DATA payload: 4_evt[%s]", + bta_hh_get_w4_event(p_cb->w4_evt)); +#endif + break; + } + + /* inform PM for mode change */ + bta_sys_busy(BTA_ID_HH, p_cb->app_id, p_cb->addr); + bta_sys_idle(BTA_ID_HH, p_cb->app_id, p_cb->addr); + + (* bta_hh_cb.p_cback)(p_cb->w4_evt, (tBTA_HH *)&hs_data); + + p_cb->w4_evt = 0; + utl_freebuf((void **)&pdata); + +} + +/******************************************************************************* +** +** Function bta_hh_open_failure +** +** Description report HID open failure when at wait for connection state and receive +** device close event. +** +** +** Returns void +** +*******************************************************************************/ +void bta_hh_open_failure(tBTA_HH_DEV_CB *p_cb, tBTA_HH_DATA *p_data) +{ + tBTA_HH_CONN conn_dat ; + UINT32 reason = p_data->hid_cback.data; /* Reason for closing (32-bit) */ + + memset(&conn_dat, 0, sizeof(tBTA_HH_CONN)); + conn_dat.handle = p_cb->hid_handle; + conn_dat.status = (reason == HID_ERR_AUTH_FAILED) ? + BTA_HH_ERR_AUTH_FAILED : BTA_HH_ERR; + bdcpy(conn_dat.bda, p_cb->addr); + HID_HostCloseDev(p_cb->hid_handle); + + /* Report OPEN fail event */ + (*bta_hh_cb.p_cback)(BTA_HH_OPEN_EVT, (tBTA_HH *)&conn_dat); + +#if BTA_HH_DEBUG + bta_hh_trace_dev_db(); +#endif + /* clean up control block, but retain SDP info and device handle */ + p_cb->vp = FALSE; + p_cb->w4_evt = 0; + + /* if no connection is active and HH disable is signaled, disable service */ + if (bta_hh_cb.cnt_num == 0 && bta_hh_cb.w4_disable) + { + bta_hh_disc_cmpl(); + } + +} + +/******************************************************************************* +** +** Function bta_hh_close_act +** +** Description HID Host process a close event +** +** +** Returns void +** +*******************************************************************************/ +void bta_hh_close_act (tBTA_HH_DEV_CB *p_cb, tBTA_HH_DATA *p_data) +{ + tBTA_HH_CONN conn_dat ; + tBTA_HH_CBDATA disc_dat = {BTA_HH_OK, 0}; + UINT32 reason = p_data->hid_cback.data; /* Reason for closing (32-bit) */ + + /* if HID_HDEV_EVT_VC_UNPLUG was received, report BTA_HH_VC_UNPLUG_EVT */ + UINT16 event = p_cb->vp ? BTA_HH_VC_UNPLUG_EVT : BTA_HH_CLOSE_EVT; + + disc_dat.handle = p_cb->hid_handle; + disc_dat.status = p_data->hid_cback.data; + + /* Check reason for closing */ + if ((reason & (HID_L2CAP_CONN_FAIL|HID_L2CAP_REQ_FAIL)) || /* Failure to initialize connection (page timeout or l2cap error) */ + (reason == HID_ERR_AUTH_FAILED) || /* Authenication error (while initiating) */ + (reason == HID_ERR_L2CAP_FAILED)) /* Failure creating l2cap connection */ + { + /* Failure in opening connection */ + conn_dat.handle = p_cb->hid_handle; + conn_dat.status = (reason == HID_ERR_AUTH_FAILED) ? BTA_HH_ERR_AUTH_FAILED : BTA_HH_ERR; + bdcpy(conn_dat.bda, p_cb->addr); + HID_HostCloseDev(p_cb->hid_handle); + + /* Report OPEN fail event */ + (*bta_hh_cb.p_cback)(BTA_HH_OPEN_EVT, (tBTA_HH *)&conn_dat); + +#if BTA_HH_DEBUG + bta_hh_trace_dev_db(); +#endif + return; + } + /* otherwise report CLOSE/VC_UNPLUG event */ + else + { + /* finaliza device driver */ + bta_hh_co_close(p_cb->hid_handle, p_cb->app_id); + /* inform role manager */ + bta_sys_conn_close( BTA_ID_HH ,p_cb->app_id, p_cb->addr); + /* update total conn number */ + bta_hh_cb.cnt_num --; + + if (disc_dat.status) + disc_dat.status = BTA_HH_ERR; + + (*bta_hh_cb.p_cback)(event, (tBTA_HH *)&disc_dat); + + /* if virtually unplug, remove device */ + if (p_cb->vp ) + { + HID_HostRemoveDev( p_cb->hid_handle); + bta_hh_clean_up_kdev(p_cb); + } + +#if BTA_HH_DEBUG + bta_hh_trace_dev_db(); +#endif + } + + /* clean up control block, but retain SDP info and device handle */ + p_cb->vp = FALSE; + p_cb->w4_evt = 0; + + /* if no connection is active and HH disable is signaled, disable service */ + if (bta_hh_cb.cnt_num == 0 && bta_hh_cb.w4_disable) + { + bta_hh_disc_cmpl(); + } + + return; +} + +/******************************************************************************* +** +** Function bta_hh_get_dscp_act +** +** Description Get device report descriptor +** +** +** Returns void +** +*******************************************************************************/ +void bta_hh_get_dscp_act(tBTA_HH_DEV_CB *p_cb, tBTA_HH_DATA *p_data) +{ + UNUSED(p_data); + +#if (BTA_HH_LE_INCLUDED == TRUE) + if (p_cb->is_le_device) + { + bta_hh_le_get_dscp_act(p_cb); + } + else +#endif + (*bta_hh_cb.p_cback)(BTA_HH_GET_DSCP_EVT, (tBTA_HH *)&p_cb->dscp_info); +} + +/******************************************************************************* +** +** Function bta_hh_maint_dev_act +** +** Description HID Host maintain device list. +** +** +** Returns void +** +*******************************************************************************/ +void bta_hh_maint_dev_act(tBTA_HH_DEV_CB *p_cb, tBTA_HH_DATA *p_data) +{ + tBTA_HH_MAINT_DEV *p_dev_info = &p_data->api_maintdev; + tBTA_HH_DEV_INFO dev_info ; + UINT8 dev_handle; + + dev_info.status = BTA_HH_ERR; + dev_info.handle = BTA_HH_INVALID_HANDLE; + + switch (p_dev_info->sub_event) + { + case BTA_HH_ADD_DEV_EVT: /* add a device */ + bdcpy(dev_info.bda, p_dev_info->bda); + /* initialize callback data */ + if (p_cb->hid_handle == BTA_HH_INVALID_HANDLE) + { +#if (BTA_HH_LE_INCLUDED == TRUE) + if (bta_hh_is_le_device(p_cb, p_data->api_conn.bd_addr)) + { + dev_info.handle = bta_hh_le_add_device(p_cb, p_dev_info); + dev_info.status = BTA_HH_OK; + } + else +#endif + + if (HID_HostAddDev(p_dev_info->bda, p_dev_info->attr_mask, &dev_handle)\ + == HID_SUCCESS) + { + dev_info.handle = dev_handle; + dev_info.status = BTA_HH_OK; + +#if (defined BTA_HH_LE_INCLUDED && BTA_HH_LE_INCLUDED == TRUE) + /* update DI information */ + bta_hh_update_di_info(p_cb, + p_dev_info->dscp_info.vendor_id, + p_dev_info->dscp_info.product_id, + p_dev_info->dscp_info.version, + p_dev_info->dscp_info.flag); +#else + bta_hh_update_di_info(p_cb, + p_dev_info->dscp_info.vendor_id, + p_dev_info->dscp_info.product_id, + p_dev_info->dscp_info.version, + 0); + +#endif + /* add to BTA device list */ + bta_hh_add_device_to_list(p_cb, dev_handle, + p_dev_info->attr_mask, + &p_dev_info->dscp_info.descriptor, + p_dev_info->sub_class, + p_dev_info->dscp_info.ssr_max_latency, + p_dev_info->dscp_info.ssr_min_tout, + p_dev_info->app_id); + /* update cb_index[] map */ + bta_hh_cb.cb_index[dev_handle] = p_cb->index; + } + } + else /* device already been added */ + { + dev_info.handle = p_cb->hid_handle; + dev_info.status = BTA_HH_OK; + } +#if BTA_HH_DEBUG + bta_hh_trace_dev_db(); +#endif + + break; + case BTA_HH_RMV_DEV_EVT: /* remove device */ + dev_info.handle = (UINT8)p_dev_info->hdr.layer_specific; + bdcpy(dev_info.bda, p_cb->addr); + +#if BTA_HH_LE_INCLUDED == TRUE + if (p_cb->is_le_device) + { + bta_hh_le_remove_dev_bg_conn(p_cb); + bta_hh_sm_execute(p_cb, BTA_HH_API_CLOSE_EVT, NULL); + bta_hh_clean_up_kdev(p_cb); + } + else +#endif + { + if(HID_HostRemoveDev( dev_info.handle ) == HID_SUCCESS) + { + dev_info.status = BTA_HH_OK; + + /* remove from known device list in BTA */ + bta_hh_clean_up_kdev(p_cb); + } + } + break; + + default: + APPL_TRACE_DEBUG("invalid command"); + break; + } + + (* bta_hh_cb.p_cback)(p_dev_info->sub_event, (tBTA_HH *)&dev_info); +} +/******************************************************************************* +** +** Function bta_hh_write_dev_act +** +** Description Write device action. can be SET/GET/DATA transaction. +** +** Returns void +** +*******************************************************************************/ +void bta_hh_write_dev_act(tBTA_HH_DEV_CB *p_cb, tBTA_HH_DATA *p_data) +{ + tBTA_HH_CBDATA cbdata = {BTA_HH_OK, 0}; + UINT16 event = (p_data->api_sndcmd.t_type - BTA_HH_FST_BTE_TRANS_EVT) + + BTA_HH_FST_TRANS_CB_EVT; + +#if BTA_HH_LE_INCLUDED == TRUE + if (p_cb->is_le_device) + bta_hh_le_write_dev_act(p_cb, p_data); + else +#endif + { + + cbdata.handle = p_cb->hid_handle; + + /* match up BTE/BTA report/boot mode def */ + if (p_data->api_sndcmd.t_type == HID_TRANS_SET_PROTOCOL) + { + p_data->api_sndcmd.param = ( p_data->api_sndcmd.param == BTA_HH_PROTO_RPT_MODE) ?\ + HID_PAR_PROTOCOL_REPORT :HID_PAR_PROTOCOL_BOOT_MODE; + } + + if (HID_HostWriteDev (p_cb->hid_handle, + p_data->api_sndcmd.t_type, + p_data->api_sndcmd.param, + p_data->api_sndcmd.data, + p_data->api_sndcmd.rpt_id, + p_data->api_sndcmd.p_data) != HID_SUCCESS) + { + APPL_TRACE_ERROR("HID_HostWriteDev Error "); + cbdata.status = BTA_HH_ERR; + + if (p_data->api_sndcmd.t_type != HID_TRANS_CONTROL && + p_data->api_sndcmd.t_type != HID_TRANS_DATA) + (* bta_hh_cb.p_cback)(event, (tBTA_HH *)&cbdata); + else if (p_data->api_sndcmd.param == BTA_HH_CTRL_VIRTUAL_CABLE_UNPLUG) + (* bta_hh_cb.p_cback)(BTA_HH_VC_UNPLUG_EVT, (tBTA_HH *)&cbdata); + } + else + { + + switch(p_data->api_sndcmd.t_type) + { + case HID_TRANS_SET_PROTOCOL: + /* fall through */ + case HID_TRANS_GET_REPORT: + /* fall through */ + case HID_TRANS_SET_REPORT: + /* fall through */ + case HID_TRANS_GET_PROTOCOL: + /* fall through */ + case HID_TRANS_GET_IDLE: + /* fall through */ + case HID_TRANS_SET_IDLE:/* set w4_handsk event name for callback function use */ + p_cb->w4_evt = event; + break; + case HID_TRANS_DATA: /* output report */ + /* fall through */ + case HID_TRANS_CONTROL: + /* no handshake event will be generated */ + /* if VC_UNPLUG is issued, set flag */ + if (p_data->api_sndcmd.param == BTA_HH_CTRL_VIRTUAL_CABLE_UNPLUG) + p_cb->vp = TRUE; + + break; + /* currently not expected */ + case HID_TRANS_DATAC: + default: + APPL_TRACE_DEBUG("bta_hh_write_dev_act:: cmd type = %d", + p_data->api_sndcmd.t_type); + break; + } + + /* if not control type transaction, notify PM for energy control */ + if (p_data->api_sndcmd.t_type != HID_TRANS_CONTROL) + { + /* inform PM for mode change */ + bta_sys_busy(BTA_ID_HH, p_cb->app_id, p_cb->addr); + bta_sys_idle(BTA_ID_HH, p_cb->app_id, p_cb->addr); + } + else if (p_data->api_sndcmd.param == BTA_HH_CTRL_SUSPEND) + { + bta_sys_sco_close(BTA_ID_HH, p_cb->app_id, p_cb->addr); + } + else if (p_data->api_sndcmd.param == BTA_HH_CTRL_EXIT_SUSPEND) + { + bta_sys_busy(BTA_ID_HH, p_cb->app_id, p_cb->addr); + } + } + + } + return; +} + +/***************************************************************************** +** Static Function +*****************************************************************************/ +/******************************************************************************* +** +** Function bta_hh_cback +** +** Description BTA HH callback function. +** +** +** Returns void +** +*******************************************************************************/ +static void bta_hh_cback (UINT8 dev_handle, BD_ADDR addr, UINT8 event, + UINT32 data, BT_HDR *pdata) +{ + tBTA_HH_CBACK_DATA *p_buf = NULL; + UINT16 sm_event = BTA_HH_INVALID_EVT; + UINT8 xx = 0; + +#if BTA_HH_DEBUG + APPL_TRACE_DEBUG("bta_hh_cback::HID_event [%s]", bta_hh_hid_event_name(event)); +#endif + + switch (event) + { + case HID_HDEV_EVT_OPEN: + sm_event = BTA_HH_INT_OPEN_EVT; + break; + case HID_HDEV_EVT_CLOSE: + sm_event = BTA_HH_INT_CLOSE_EVT; + break; + case HID_HDEV_EVT_INTR_DATA: + sm_event = BTA_HH_INT_DATA_EVT; + break; + case HID_HDEV_EVT_HANDSHAKE: + sm_event = BTA_HH_INT_HANDSK_EVT; + break; + case HID_HDEV_EVT_CTRL_DATA: + sm_event = BTA_HH_INT_CTRL_DATA; + break; + case HID_HDEV_EVT_RETRYING: + break; + case HID_HDEV_EVT_INTR_DATC: + case HID_HDEV_EVT_CTRL_DATC: + /* Unhandled events: Free buffer for DATAC */ + utl_freebuf((void **)&pdata); + break; + case HID_HDEV_EVT_VC_UNPLUG: + for (xx = 0; xx < BTA_HH_MAX_DEVICE; xx++) + { + if (bta_hh_cb.kdev[xx].hid_handle == dev_handle) + { + bta_hh_cb.kdev[xx].vp = TRUE; + break; + } + } + break; + } + + if (sm_event != BTA_HH_INVALID_EVT && + (p_buf = (tBTA_HH_CBACK_DATA *)GKI_getbuf(sizeof(tBTA_HH_CBACK_DATA) + + sizeof(BT_HDR))) != NULL) + { + p_buf->hdr.event = sm_event; + p_buf->hdr.layer_specific = (UINT16)dev_handle; + p_buf->data = data; + bdcpy(p_buf->addr, addr); + p_buf->p_data = pdata; + + bta_sys_sendmsg(p_buf); + } + +} +/******************************************************************************* +** +** Function bta_hh_get_trans_status +** +** Description translate a handshake result code into BTA HH +** status code +** +*******************************************************************************/ +static tBTA_HH_STATUS bta_hh_get_trans_status(UINT32 result) +{ + switch(result) + { + case HID_PAR_HANDSHAKE_RSP_SUCCESS : /* (0) */ + return BTA_HH_OK; + case HID_PAR_HANDSHAKE_RSP_NOT_READY : /* (1) */ + case HID_PAR_HANDSHAKE_RSP_ERR_INVALID_REP_ID: /* (2) */ + case HID_PAR_HANDSHAKE_RSP_ERR_UNSUPPORTED_REQ : /* (3) */ + case HID_PAR_HANDSHAKE_RSP_ERR_INVALID_PARAM : /* (4) */ + return (tBTA_HH_STATUS)result; + case HID_PAR_HANDSHAKE_RSP_ERR_UNKNOWN : /* (14) */ + case HID_PAR_HANDSHAKE_RSP_ERR_FATAL : /* (15) */ + default: + return BTA_HH_HS_ERROR; + break; + } +} +/***************************************************************************** +** Debug Functions +*****************************************************************************/ + +#if (defined BTA_HH_DEBUG && BTA_HH_DEBUG == TRUE) +static char* bta_hh_get_w4_event(UINT16 event) +{ + switch (event) + { + case BTA_HH_GET_RPT_EVT: + return "BTA_HH_GET_RPT_EVT"; + case BTA_HH_SET_RPT_EVT: + return "BTA_HH_SET_RPT_EVT"; + case BTA_HH_GET_PROTO_EVT: + return "BTA_HH_GET_PROTO_EVT"; + case BTA_HH_SET_PROTO_EVT: + return "BTA_HH_SET_PROTO_EVT"; + case BTA_HH_GET_IDLE_EVT: + return "BTA_HH_GET_IDLE_EVT"; + case BTA_HH_SET_IDLE_EVT: + return "BTA_HH_SET_IDLE_EVT"; + case BTA_HH_OPEN_EVT: + return "BTA_HH_OPEN_EVT"; + default: + return "Unknown event"; + } + +} + +static char * bta_hh_hid_event_name(UINT16 event) +{ + switch (event) + { + case HID_HDEV_EVT_OPEN: + return "HID_HDEV_EVT_OPEN"; + case HID_HDEV_EVT_CLOSE: + return "HID_HDEV_EVT_CLOSE"; + case HID_HDEV_EVT_RETRYING: + return "HID_HDEV_EVT_RETRYING"; + case HID_HDEV_EVT_INTR_DATA: + return "HID_HDEV_EVT_INTR_DATA"; + case HID_HDEV_EVT_INTR_DATC: + return "HID_HDEV_EVT_INTR_DATC"; + case HID_HDEV_EVT_CTRL_DATA: + return "HID_HDEV_EVT_CTRL_DATA"; + case HID_HDEV_EVT_CTRL_DATC: + return "HID_HDEV_EVT_CTRL_DATC"; + case HID_HDEV_EVT_HANDSHAKE: + return "HID_HDEV_EVT_HANDSHAKE"; + case HID_HDEV_EVT_VC_UNPLUG: + return "HID_HDEV_EVT_VC_UNPLUG"; + default: + return "Unknown HID event"; + } +} +#endif +#endif /* BTA_HH_INCLUDED */ + diff --git a/components/bt/bluedroid/bta/hh/bta_hh_api.c b/components/bt/bluedroid/bta/hh/bta_hh_api.c new file mode 100644 index 0000000000..1fdbc29284 --- /dev/null +++ b/components/bt/bluedroid/bta/hh/bta_hh_api.c @@ -0,0 +1,496 @@ +/****************************************************************************** + * + * Copyright (C) 2005-2012 Broadcom Corporation + * + * 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 HID HOST API in the subsystem of BTA. + * + ******************************************************************************/ + +#include "bt_target.h" + +#if defined(BTA_HH_INCLUDED) && (BTA_HH_INCLUDED == TRUE) + +#include +#include +#include + +#include "bta_hh_api.h" +#include "bta_hh_int.h" +#include "l2c_api.h" +#include "utl.h" + +#define LOG_TAG "bt_bta_hh" +#include "osi/include/log.h" + +/***************************************************************************** +** Constants +*****************************************************************************/ + +static const tBTA_SYS_REG bta_hh_reg = +{ + bta_hh_hdl_event, + BTA_HhDisable +}; + +/******************************************************************************* +** +** Function BTA_HhEnable +** +** Description Enable the HID host. This function must be called before +** any other functions in the HID host API are called. When the +** enable operation is complete the callback function will be +** called with BTA_HH_ENABLE_EVT. +** +** +** Returns void +** +*******************************************************************************/ +void BTA_HhEnable(tBTA_SEC sec_mask, tBTA_HH_CBACK *p_cback) +{ + tBTA_HH_API_ENABLE *p_buf; + + /* register with BTA system manager */ + bta_sys_register(BTA_ID_HH, &bta_hh_reg); + + LOG_INFO("%s sec_mask:0x%x p_cback:%p", __func__, sec_mask, p_cback); + p_buf = (tBTA_HH_API_ENABLE *)GKI_getbuf((UINT16)sizeof(tBTA_HH_API_ENABLE)); + + if (p_buf != NULL) + { + memset(p_buf, 0, sizeof(tBTA_HH_API_ENABLE)); + + p_buf->hdr.event = BTA_HH_API_ENABLE_EVT; + p_buf->p_cback = p_cback; + p_buf->sec_mask = sec_mask; + + bta_sys_sendmsg(p_buf); + } +} + +/******************************************************************************* +** +** Function BTA_HhDisable +** +** Description Disable the HID host. If the server is currently +** connected, the connection will be closed. +** +** Returns void +** +*******************************************************************************/ +void BTA_HhDisable(void) +{ + BT_HDR *p_buf; + + bta_sys_deregister(BTA_ID_HH); + if ((p_buf = (BT_HDR *)GKI_getbuf(sizeof(BT_HDR))) != NULL) + { + p_buf->event = BTA_HH_API_DISABLE_EVT; + bta_sys_sendmsg(p_buf); + } +} + +/******************************************************************************* +** +** Function BTA_HhClose +** +** Description Disconnect a connection. +** +** Returns void +** +*******************************************************************************/ +void BTA_HhClose(UINT8 dev_handle) +{ + BT_HDR *p_buf; + + if ((p_buf = (BT_HDR *)GKI_getbuf((UINT16)sizeof(BT_HDR))) != NULL) + { + memset(p_buf, 0, sizeof(BT_HDR)); + p_buf->event = BTA_HH_API_CLOSE_EVT; + p_buf->layer_specific = (UINT16) dev_handle; + + bta_sys_sendmsg(p_buf); + } +} + +/******************************************************************************* +** +** Function BTA_HhOpen +** +** Description Connect to a device of specified BD address in specified +** protocol mode and security level. +** +** Returns void +** +*******************************************************************************/ +void BTA_HhOpen(BD_ADDR dev_bda, tBTA_HH_PROTO_MODE mode, tBTA_SEC sec_mask) +{ + tBTA_HH_API_CONN *p_buf; + + p_buf = (tBTA_HH_API_CONN *)GKI_getbuf((UINT16)sizeof(tBTA_HH_API_CONN)); + + if (p_buf!= NULL) + { + memset((void *)p_buf, 0, sizeof(tBTA_HH_API_CONN)); + + p_buf->hdr.event = BTA_HH_API_OPEN_EVT; + p_buf->hdr.layer_specific = BTA_HH_INVALID_HANDLE; + p_buf->sec_mask = sec_mask; + p_buf->mode = mode; + bdcpy(p_buf->bd_addr, dev_bda); + + bta_sys_sendmsg((void *)p_buf); + } + else + { + APPL_TRACE_ERROR("No resource to send HID host Connect request."); + } +} + +/******************************************************************************* +** +** Function bta_hh_snd_write_dev +** +*******************************************************************************/ +static void bta_hh_snd_write_dev(UINT8 dev_handle, UINT8 t_type, UINT8 param, + UINT16 data, UINT8 rpt_id, BT_HDR *p_data) +{ + tBTA_HH_CMD_DATA *p_buf; + UINT16 len = (UINT16) (sizeof(tBTA_HH_CMD_DATA) ); + + if ((p_buf = (tBTA_HH_CMD_DATA *)GKI_getbuf(len))!= NULL) + { + memset(p_buf, 0, sizeof(tBTA_HH_CMD_DATA)); + + p_buf->hdr.event = BTA_HH_API_WRITE_DEV_EVT; + p_buf->hdr.layer_specific = (UINT16) dev_handle; + p_buf->t_type = t_type; + p_buf->data = data; + p_buf->param = param; + p_buf->p_data = p_data; + p_buf->rpt_id = rpt_id; + + bta_sys_sendmsg(p_buf); + } +} +/******************************************************************************* +** +** Function BTA_HhSetReport +** +** Description send SET_REPORT to device. +** +** Parameter dev_handle: device handle +** r_type: report type, could be BTA_HH_RPTT_OUTPUT or +** BTA_HH_RPTT_FEATURE. +** Returns void +** +*******************************************************************************/ +void BTA_HhSetReport(UINT8 dev_handle, tBTA_HH_RPT_TYPE r_type, BT_HDR *p_data) +{ + bta_hh_snd_write_dev(dev_handle, HID_TRANS_SET_REPORT, r_type, 0, 0, p_data); +} +/******************************************************************************* +** +** Function BTA_HhGetReport +** +** Description Send a GET_REPORT to HID device. +** +** Returns void +** +*******************************************************************************/ +void BTA_HhGetReport(UINT8 dev_handle, tBTA_HH_RPT_TYPE r_type, UINT8 rpt_id, UINT16 buf_size) +{ + UINT8 param = (buf_size) ? (r_type | 0x08) : r_type; + + bta_hh_snd_write_dev(dev_handle, HID_TRANS_GET_REPORT, param, + buf_size, rpt_id, NULL); +} +/******************************************************************************* +** +** Function BTA_HhSetProtoMode +** +** Description This function set the protocol mode at specified HID handle +** +** Returns void +** +*******************************************************************************/ +void BTA_HhSetProtoMode(UINT8 dev_handle, tBTA_HH_PROTO_MODE p_type) +{ + bta_hh_snd_write_dev(dev_handle, HID_TRANS_SET_PROTOCOL, (UINT8)p_type, + 0, 0, NULL); +} +/******************************************************************************* +** +** Function BTA_HhGetProtoMode +** +** Description This function get protocol mode information. +** +** Returns void +** +*******************************************************************************/ +void BTA_HhGetProtoMode(UINT8 dev_handle) +{ + bta_hh_snd_write_dev(dev_handle, HID_TRANS_GET_PROTOCOL, 0, 0, 0, NULL); +} +/******************************************************************************* +** +** Function BTA_HhSetIdle +** +** Description send SET_IDLE to device. +** +** Returns void +** +*******************************************************************************/ +void BTA_HhSetIdle(UINT8 dev_handle, UINT16 idle_rate) +{ + bta_hh_snd_write_dev(dev_handle, HID_TRANS_SET_IDLE, 0, idle_rate, 0, NULL); +} + +/******************************************************************************* +** +** Function BTA_HhGetIdle +** +** Description Send a GET_IDLE from HID device. +** +** Returns void +** +*******************************************************************************/ +void BTA_HhGetIdle(UINT8 dev_handle) +{ + bta_hh_snd_write_dev(dev_handle, HID_TRANS_GET_IDLE, 0, 0, 0, NULL); +} +/******************************************************************************* +** +** Function BTA_HhSendCtrl +** +** Description Send a control command to HID device. +** +** Returns void +** +*******************************************************************************/ +void BTA_HhSendCtrl(UINT8 dev_handle, tBTA_HH_TRANS_CTRL_TYPE c_type) +{ + bta_hh_snd_write_dev(dev_handle, HID_TRANS_CONTROL, (UINT8)c_type, 0, 0, NULL); +} +/******************************************************************************* +** +** Function BTA_HhSendData +** +** Description This function send DATA transaction to HID device. +** +** Parameter dev_handle: device handle +** dev_bda: remote device address +** p_data: data to be sent in the DATA transaction; or +** the data to be write into the Output Report of a LE HID +** device. The report is identified the report ID which is +** the value of the byte (UINT8 *)(p_buf + 1) + p_buf->offset. +** p_data->layer_specific needs to be set to the report type, +** it can be OUTPUT report, or FEATURE report. +** +** Returns void +** +*******************************************************************************/ +void BTA_HhSendData(UINT8 dev_handle, BD_ADDR dev_bda, BT_HDR *p_data) +{ + UNUSED(dev_bda); +#if (defined BTA_HH_LE_INCLUDED && BTA_HH_LE_INCLUDED == TRUE) + if (p_data->layer_specific != BTA_HH_RPTT_OUTPUT) + { + APPL_TRACE_ERROR("ERROR! Wrong report type! Write Command only valid for output report!"); + return; + } +#endif + bta_hh_snd_write_dev(dev_handle, HID_TRANS_DATA, (UINT8)p_data->layer_specific, 0, 0, p_data); +} + +/******************************************************************************* +** +** Function BTA_HhGetDscpInfo +** +** Description Get HID device report descriptor +** +** Returns void +** +*******************************************************************************/ +void BTA_HhGetDscpInfo(UINT8 dev_handle) +{ + BT_HDR *p_buf; + + if ((p_buf = (BT_HDR *)GKI_getbuf((UINT16)sizeof(BT_HDR))) != NULL) + { + memset(p_buf, 0, sizeof(BT_HDR)); + p_buf->event = BTA_HH_API_GET_DSCP_EVT; + p_buf->layer_specific = (UINT16) dev_handle; + + bta_sys_sendmsg(p_buf); + } +} + +/******************************************************************************* +** +** Function BTA_HhAddDev +** +** Description Add a virtually cabled device into HID-Host device list +** to manage and assign a device handle for future API call, +** host applciation call this API at start-up to initialize its +** virtually cabled devices. +** +** Returns void +** +*******************************************************************************/ +void BTA_HhAddDev(BD_ADDR bda, tBTA_HH_ATTR_MASK attr_mask, UINT8 sub_class, + UINT8 app_id, tBTA_HH_DEV_DSCP_INFO dscp_info) +{ + tBTA_HH_MAINT_DEV *p_buf; + UINT16 len = sizeof(tBTA_HH_MAINT_DEV) + dscp_info.descriptor.dl_len; + + p_buf = (tBTA_HH_MAINT_DEV *)GKI_getbuf(len); + + if (p_buf != NULL) + { + memset(p_buf, 0, sizeof(tBTA_HH_MAINT_DEV)); + + p_buf->hdr.event = BTA_HH_API_MAINT_DEV_EVT; + p_buf->sub_event = BTA_HH_ADD_DEV_EVT; + p_buf->hdr.layer_specific = BTA_HH_INVALID_HANDLE; + + p_buf->attr_mask = (UINT16) attr_mask; + p_buf->sub_class = sub_class; + p_buf->app_id = app_id; + bdcpy(p_buf->bda, bda); + + memcpy(&p_buf->dscp_info, &dscp_info, sizeof(tBTA_HH_DEV_DSCP_INFO)); + if ( dscp_info.descriptor.dl_len != 0 && dscp_info.descriptor.dsc_list) + { + p_buf->dscp_info.descriptor.dl_len = dscp_info.descriptor.dl_len; + p_buf->dscp_info.descriptor.dsc_list = (UINT8 *)(p_buf + 1); + memcpy(p_buf->dscp_info.descriptor.dsc_list, dscp_info.descriptor.dsc_list, dscp_info.descriptor.dl_len); + } + else + { + p_buf->dscp_info.descriptor.dsc_list = NULL; + p_buf->dscp_info.descriptor.dl_len = 0; + } + + bta_sys_sendmsg(p_buf); + } +} +/******************************************************************************* +** +** Function BTA_HhRemoveDev +** +** Description Remove a device from the HID host devices list. +** +** Returns void +** +*******************************************************************************/ +void BTA_HhRemoveDev(UINT8 dev_handle ) +{ + tBTA_HH_MAINT_DEV *p_buf; + + p_buf = (tBTA_HH_MAINT_DEV *)GKI_getbuf((UINT16)sizeof(tBTA_HH_MAINT_DEV)); + + if (p_buf != NULL) + { + memset(p_buf, 0, sizeof(tBTA_HH_MAINT_DEV)); + + p_buf->hdr.event = BTA_HH_API_MAINT_DEV_EVT; + p_buf->sub_event = BTA_HH_RMV_DEV_EVT; + p_buf->hdr.layer_specific = (UINT16) dev_handle; + + bta_sys_sendmsg(p_buf); + } +} +#if BTA_HH_LE_INCLUDED == TRUE + +/******************************************************************************* +** +** Function BTA_HhUpdateLeScanParam +** +** Description Update the scan paramteters if connected to a LE hid device as +** report host. +** +** Returns void +** +*******************************************************************************/ +void BTA_HhUpdateLeScanParam(UINT8 dev_handle, UINT16 scan_int, UINT16 scan_win) +{ + tBTA_HH_SCPP_UPDATE *p_buf; + + p_buf = (tBTA_HH_SCPP_UPDATE *)GKI_getbuf((UINT16)sizeof(tBTA_HH_SCPP_UPDATE)); + + if (p_buf != NULL) + { + memset(p_buf, 0, sizeof(tBTA_HH_SCPP_UPDATE)); + + p_buf->hdr.event = BTA_HH_API_SCPP_UPDATE_EVT; + p_buf->hdr.layer_specific = (UINT16) dev_handle; + p_buf->scan_int = scan_int; + p_buf->scan_win = scan_win; + + bta_sys_sendmsg(p_buf); + } +} +#endif +/*******************************************************************************/ +/* Utility Function */ +/*******************************************************************************/ + +/******************************************************************************* +** +** Function BTA_HhParseBootRpt +** +** Description This utility function parse a boot mode report. +** For keyboard report, report data will carry the keycode max +** up to 6 key press in one report. Application need to convert +** the keycode into keypress character according to keyboard +** language. +** +** Returns void +** +*******************************************************************************/ +void BTA_HhParseBootRpt(tBTA_HH_BOOT_RPT *p_data, UINT8 *p_report, + UINT16 report_len) +{ + p_data->dev_type = BTA_HH_DEVT_UNKNOWN; + + if (p_report) + { + /* first byte is report ID */ + switch (p_report[0]) + { + case BTA_HH_KEYBD_RPT_ID: /* key board report ID */ + p_data->dev_type = p_report[0]; + bta_hh_parse_keybd_rpt(p_data, p_report + 1, (UINT16)(report_len -1)); + break; + + case BTA_HH_MOUSE_RPT_ID: /* mouse report ID */ + p_data->dev_type = p_report[0]; + bta_hh_parse_mice_rpt(p_data, p_report + 1, (UINT16)(report_len - 1)); + break; + + default: + APPL_TRACE_DEBUG("Unknown boot report: %d", p_report[0]);; + break; + } + } + + return; +} + +#endif /* BTA_HH_INCLUDED */ diff --git a/components/bt/bluedroid/bta/hh/bta_hh_cfg.c b/components/bt/bluedroid/bta/hh/bta_hh_cfg.c new file mode 100644 index 0000000000..e3ffefe9b6 --- /dev/null +++ b/components/bt/bluedroid/bta/hh/bta_hh_cfg.c @@ -0,0 +1,62 @@ +/****************************************************************************** + * + * Copyright (C) 2005-2012 Broadcom Corporation + * + * 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 compile-time configurable constants for the BTA Hid + * Host. + * + ******************************************************************************/ + +#include "bt_target.h" +#include "bta_hh_api.h" + +/* max number of device types supported by BTA */ +#define BTA_HH_MAX_DEVT_SPT 9 + +/* size of database for service discovery */ +#ifndef BTA_HH_DISC_BUF_SIZE +#define BTA_HH_DISC_BUF_SIZE GKI_MAX_BUF_SIZE +#endif + + + +/* The type of devices supported by BTA HH and corresponding application ID */ +tBTA_HH_SPT_TOD p_devt_list[BTA_HH_MAX_DEVT_SPT] = +{ + {BTA_HH_DEVT_MIC, BTA_HH_APP_ID_MI}, + {BTA_HH_DEVT_KBD, BTA_HH_APP_ID_KB}, + {BTA_HH_DEVT_KBD|BTA_HH_DEVT_MIC, BTA_HH_APP_ID_KB}, + {BTA_HH_DEVT_RMC, BTA_HH_APP_ID_RMC}, + {BTA_HH_DEVT_RMC | BTA_HH_DEVT_KBD, BTA_HH_APP_ID_RMC}, + {BTA_HH_DEVT_MIC | BTA_HH_DEVT_DGT, BTA_HH_APP_ID_MI}, + {BTA_HH_DEVT_JOS, BTA_HH_APP_ID_JOY}, + {BTA_HH_DEVT_GPD, BTA_HH_APP_ID_GPAD}, + {BTA_HH_DEVT_UNKNOWN, BTA_HH_APP_ID_3DSG} +}; + + +const tBTA_HH_CFG bta_hh_cfg = +{ + BTA_HH_MAX_DEVT_SPT, /* number of supported type of devices */ + p_devt_list, /* ToD & AppID list */ + BTA_HH_DISC_BUF_SIZE /* HH SDP discovery database size */ +}; + + +tBTA_HH_CFG *p_bta_hh_cfg = (tBTA_HH_CFG *)&bta_hh_cfg; diff --git a/components/bt/bluedroid/bta/hh/bta_hh_int.h b/components/bt/bluedroid/bta/hh/bta_hh_int.h new file mode 100644 index 0000000000..4e1173aca7 --- /dev/null +++ b/components/bt/bluedroid/bta/hh/bta_hh_int.h @@ -0,0 +1,415 @@ +/****************************************************************************** + * + * Copyright (C) 2005-2012 Broadcom Corporation + * + * 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 BTA HID Host internal definitions + * + ******************************************************************************/ + +#ifndef BTA_HH_INT_H +#define BTA_HH_INT_H + +#include "bta_sys.h" +#include "utl.h" +#include "bta_hh_api.h" + +#if BTA_HH_LE_INCLUDED == TRUE +xxx +#include "bta_gatt_api.h" +#endif + +/* can be moved to bta_api.h */ +#define BTA_HH_MAX_RPT_CHARS 8 + +#if (BTA_GATT_INCLUDED == FALSE || BLE_INCLUDED == FALSE) +#undef BTA_HH_LE_INCLUDED +#define BTA_HH_LE_INCLUDED FALSE +#endif + +/* state machine events, these events are handled by the state machine */ +enum +{ + BTA_HH_API_OPEN_EVT = BTA_SYS_EVT_START(BTA_ID_HH), + BTA_HH_API_CLOSE_EVT, + BTA_HH_INT_OPEN_EVT, + BTA_HH_INT_CLOSE_EVT, + BTA_HH_INT_DATA_EVT, + BTA_HH_INT_CTRL_DATA, + BTA_HH_INT_HANDSK_EVT, + BTA_HH_SDP_CMPL_EVT, + BTA_HH_API_WRITE_DEV_EVT, + BTA_HH_API_GET_DSCP_EVT, + BTA_HH_API_MAINT_DEV_EVT, + BTA_HH_OPEN_CMPL_EVT, +#if (defined BTA_HH_LE_INCLUDED && BTA_HH_LE_INCLUDED == TRUE) + BTA_HH_GATT_CLOSE_EVT, + BTA_HH_GATT_OPEN_EVT, + BTA_HH_START_ENC_EVT, + BTA_HH_ENC_CMPL_EVT, + BTA_HH_GATT_READ_CHAR_CMPL_EVT, + BTA_HH_GATT_WRITE_CHAR_CMPL_EVT, + BTA_HH_GATT_READ_DESCR_CMPL_EVT, + BTA_HH_GATT_WRITE_DESCR_CMPL_EVT, + BTA_HH_API_SCPP_UPDATE_EVT, + BTA_HH_GATT_ENC_CMPL_EVT, +#endif + + /* not handled by execute state machine */ + BTA_HH_API_ENABLE_EVT, + BTA_HH_API_DISABLE_EVT, + BTA_HH_DISC_CMPL_EVT +}; +typedef UINT16 tBTA_HH_INT_EVT; /* HID host internal events */ + +#define BTA_HH_INVALID_EVT (BTA_HH_DISC_CMPL_EVT + 1) + +/* event used to map between BTE event and BTA event */ +#define BTA_HH_FST_TRANS_CB_EVT BTA_HH_GET_RPT_EVT +#define BTA_HH_FST_BTE_TRANS_EVT HID_TRANS_GET_REPORT + +/* sub event code used for device maintainence API call */ +#define BTA_HH_ADD_DEV 0 +#define BTA_HH_REMOVE_DEV 1 + +/* state machine states */ +enum +{ + BTA_HH_NULL_ST, + BTA_HH_IDLE_ST, + BTA_HH_W4_CONN_ST, + BTA_HH_CONN_ST +#if (defined BTA_HH_LE_INCLUDED && BTA_HH_LE_INCLUDED == TRUE) + ,BTA_HH_W4_SEC +#endif + ,BTA_HH_INVALID_ST /* Used to check invalid states before executing SM function */ + +}; +typedef UINT8 tBTA_HH_STATE; + +/* data structure used to send a command/data to HID device */ +typedef struct +{ + BT_HDR hdr; + UINT8 t_type; + UINT8 param; + UINT8 rpt_id; +#if (defined BTA_HH_LE_INCLUDED && BTA_HH_LE_INCLUDED == TRUE) + UINT8 srvc_id; +#endif + UINT16 data; + BT_HDR *p_data; +}tBTA_HH_CMD_DATA; + +/* data type for BTA_HH_API_ENABLE_EVT */ +typedef struct +{ + BT_HDR hdr; + UINT8 sec_mask; + UINT8 service_name[BTA_SERVICE_NAME_LEN+1]; + tBTA_HH_CBACK *p_cback; +} tBTA_HH_API_ENABLE; + +typedef struct +{ + BT_HDR hdr; + BD_ADDR bd_addr; + UINT8 sec_mask; + tBTA_HH_PROTO_MODE mode; +}tBTA_HH_API_CONN; + +/* internal event data from BTE HID callback */ +typedef struct +{ + BT_HDR hdr; + BD_ADDR addr; + UINT32 data; + BT_HDR *p_data; +}tBTA_HH_CBACK_DATA; + +typedef struct +{ + BT_HDR hdr; + BD_ADDR bda; + UINT16 attr_mask; + UINT16 sub_event; + UINT8 sub_class; + UINT8 app_id; + tBTA_HH_DEV_DSCP_INFO dscp_info; +}tBTA_HH_MAINT_DEV; + +#if BTA_HH_LE_INCLUDED == TRUE +typedef struct +{ + BT_HDR hdr; + UINT16 conn_id; + tBTA_GATT_REASON reason; /* disconnect reason code, not useful when connect event is reported */ + +}tBTA_HH_LE_CLOSE; + +typedef struct +{ + BT_HDR hdr; + UINT16 scan_int; + UINT16 scan_win; +}tBTA_HH_SCPP_UPDATE; +#endif +/* union of all event data types */ +typedef union +{ + BT_HDR hdr; + tBTA_HH_API_ENABLE api_enable; + tBTA_HH_API_CONN api_conn; + tBTA_HH_CMD_DATA api_sndcmd; + tBTA_HH_CBACK_DATA hid_cback; + tBTA_HH_STATUS status; + tBTA_HH_MAINT_DEV api_maintdev; +#if BTA_HH_LE_INCLUDED == TRUE + tBTA_HH_LE_CLOSE le_close; + tBTA_GATTC_OPEN le_open; + tBTA_HH_SCPP_UPDATE le_scpp_update; + tBTA_GATTC_ENC_CMPL_CB le_enc_cmpl; +#endif +} tBTA_HH_DATA; + +#if (defined BTA_HH_LE_INCLUDED && BTA_HH_LE_INCLUDED == TRUE) +typedef struct +{ + UINT8 index; + BOOLEAN in_use; + UINT8 inst_id; /* share service instance ID and report instance ID, as + hi 4 for service instance ID, low 4 as charatceristic instance ID */ + tBTA_HH_RPT_TYPE rpt_type; + UINT16 uuid; + UINT8 prop; + UINT8 rpt_id; + BOOLEAN client_cfg_exist; + UINT16 client_cfg_value; +}tBTA_HH_LE_RPT; + +#ifndef BTA_HH_LE_RPT_MAX +#define BTA_HH_LE_RPT_MAX 20 +#endif + +typedef struct +{ + BOOLEAN in_use; + tBTA_HH_LE_RPT report[BTA_HH_LE_RPT_MAX]; + +#define BTA_HH_LE_PROTO_MODE_BIT 0x01 +#define BTA_HH_LE_CP_BIT 0x02 + UINT8 option_char; /* control point char exisit or not */ + + BOOLEAN expl_incl_srvc; + UINT8 incl_srvc_inst; /* assuming only one included service : battery service */ + UINT8 cur_expl_char_idx; /* currently discovering service index */ + UINT8 *rpt_map; + UINT16 ext_rpt_ref; + tBTA_HH_DEV_DESCR descriptor; + +}tBTA_HH_LE_HID_SRVC; + +#ifndef BTA_HH_LE_HID_SRVC_MAX +#define BTA_HH_LE_HID_SRVC_MAX 1 +#endif + +/* convert a HID handle to the LE CB index */ +#define BTA_HH_GET_LE_CB_IDX(x) (((x) >> 4) - 1) +/* convert a GATT connection ID to HID device handle, it is the hi 4 bits of a UINT8 */ +#define BTA_HH_GET_LE_DEV_HDL(x) (UINT8)(((x) + 1) << 4) +/* check to see if th edevice handle is a LE device handle */ +#define BTA_HH_IS_LE_DEV_HDL(x) ((x) & 0xf0) +#define BTA_HH_IS_LE_DEV_HDL_VALID(x) (((x)>>4) <= BTA_HH_LE_MAX_KNOWN) +#endif + +/* device control block */ +typedef struct +{ + tBTA_HH_DEV_DSCP_INFO dscp_info; /* report descriptor and DI information */ + BD_ADDR addr; /* BD-Addr of the HID device */ + UINT16 attr_mask; /* attribute mask */ + UINT16 w4_evt; /* W4_handshake event name */ + UINT8 index; /* index number referenced to handle index */ + UINT8 sub_class; /* Cod sub class */ + UINT8 sec_mask; /* security mask */ + UINT8 app_id; /* application ID for this connection */ + UINT8 hid_handle; /* device handle : low 4 bits for regular HID: HID_HOST_MAX_DEVICES can not exceed 15; + high 4 bits for LE HID: GATT_MAX_PHY_CHANNEL can not exceed 15 */ + BOOLEAN vp; /* virtually unplug flag */ + BOOLEAN in_use; /* control block currently in use */ + BOOLEAN incoming_conn; /* is incoming connection? */ + UINT8 incoming_hid_handle; /* temporary handle for incoming connection? */ + BOOLEAN opened; /* TRUE if device successfully opened HID connection */ + tBTA_HH_PROTO_MODE mode; /* protocol mode */ + tBTA_HH_STATE state; /* CB state */ + +#if (BTA_HH_LE_INCLUDED == TRUE) +#define BTA_HH_LE_DISC_NONE 0x00 +#define BTA_HH_LE_DISC_HIDS 0x01 +#define BTA_HH_LE_DISC_DIS 0x02 +#define BTA_HH_LE_DISC_SCPS 0x04 + + UINT8 disc_active; + tBTA_HH_STATUS status; + tBTA_GATT_REASON reason; + BOOLEAN is_le_device; + tBTA_HH_LE_HID_SRVC hid_srvc[BTA_HH_LE_HID_SRVC_MAX]; + UINT16 conn_id; + BOOLEAN in_bg_conn; + UINT8 total_srvc; + UINT8 clt_cfg_idx; + UINT8 cur_srvc_index; /* currently discovering service index */ + BOOLEAN scps_supported; + +#define BTA_HH_LE_SCPS_NOTIFY_NONE 0 +#define BTA_HH_LE_SCPS_NOTIFY_SPT 0x01 +#define BTA_HH_LE_SCPS_NOTIFY_ENB 0x02 + UINT8 scps_notify; /* scan refresh supported/notification enabled */ +#endif + + BOOLEAN security_pending; +} tBTA_HH_DEV_CB; + +/* key board parsing control block */ +typedef struct +{ + BOOLEAN mod_key[4]; /* ctrl, shift(upper), Alt, GUI */ + BOOLEAN num_lock; + BOOLEAN caps_lock; + UINT8 last_report[BTA_HH_MAX_RPT_CHARS]; +} tBTA_HH_KB_CB; + +/****************************************************************************** +** Main Control Block +*******************************************************************************/ +typedef struct +{ + tBTA_HH_KB_CB kb_cb; /* key board control block, + suppose BTA will connect + to only one keyboard at + the same time */ + tBTA_HH_DEV_CB kdev[BTA_HH_MAX_DEVICE]; /* device control block */ + tBTA_HH_DEV_CB* p_cur; /* current device control + block idx, used in sdp */ + UINT8 cb_index[BTA_HH_MAX_KNOWN]; /* maintain a CB index + map to dev handle */ +#if (defined BTA_HH_LE_INCLUDED && BTA_HH_LE_INCLUDED == TRUE) + UINT8 le_cb_index[BTA_HH_MAX_DEVICE]; /* maintain a CB index map to LE dev handle */ + tBTA_GATTC_IF gatt_if; +#endif + tBTA_HH_CBACK *p_cback; /* Application callbacks */ + tSDP_DISCOVERY_DB* p_disc_db; + UINT8 trace_level; /* tracing level */ + UINT8 cnt_num; /* connected device number */ + BOOLEAN w4_disable; /* w4 disable flag */ +} +tBTA_HH_CB; + +#if BTA_DYNAMIC_MEMORY == FALSE +extern tBTA_HH_CB bta_hh_cb; +#else +extern tBTA_HH_CB *bta_hh_cb_ptr; +#define bta_hh_cb (*bta_hh_cb_ptr) +#endif + +/* from bta_hh_cfg.c */ +extern tBTA_HH_CFG *p_bta_hh_cfg; + +/***************************************************************************** +** Function prototypes +*****************************************************************************/ +extern BOOLEAN bta_hh_hdl_event(BT_HDR *p_msg); +extern void bta_hh_sm_execute(tBTA_HH_DEV_CB *p_cb, UINT16 event, + tBTA_HH_DATA *p_data); + +/* action functions */ +extern void bta_hh_api_disc_act(tBTA_HH_DEV_CB *p_cb, tBTA_HH_DATA *p_data); +extern void bta_hh_open_act(tBTA_HH_DEV_CB *p_cb, tBTA_HH_DATA *p_data); +extern void bta_hh_close_act(tBTA_HH_DEV_CB *p_cb, tBTA_HH_DATA *p_data); +extern void bta_hh_data_act(tBTA_HH_DEV_CB *p_cb, tBTA_HH_DATA * p_data); +extern void bta_hh_ctrl_dat_act(tBTA_HH_DEV_CB *p_cb, tBTA_HH_DATA * p_data); +extern void bta_hh_start_sdp(tBTA_HH_DEV_CB *p_cb, tBTA_HH_DATA *p_data); +extern void bta_hh_sdp_cmpl(tBTA_HH_DEV_CB *p_cb, tBTA_HH_DATA *p_data); +extern void bta_hh_write_dev_act(tBTA_HH_DEV_CB *p_cb, tBTA_HH_DATA *p_data); +extern void bta_hh_get_dscp_act(tBTA_HH_DEV_CB *p_cb, tBTA_HH_DATA *p_data); +extern void bta_hh_handsk_act(tBTA_HH_DEV_CB *p_cb, tBTA_HH_DATA *p_data); +extern void bta_hh_maint_dev_act(tBTA_HH_DEV_CB *p_cb, tBTA_HH_DATA *p_data); +extern void bta_hh_open_cmpl_act(tBTA_HH_DEV_CB *p_cb, tBTA_HH_DATA *p_data); +extern void bta_hh_open_failure(tBTA_HH_DEV_CB *p_cb, tBTA_HH_DATA *p_data); + +/* utility functions */ +extern UINT8 bta_hh_find_cb(BD_ADDR bda); +extern void bta_hh_parse_keybd_rpt(tBTA_HH_BOOT_RPT *p_kb_data, + UINT8 *p_report, UINT16 report_len); +extern void bta_hh_parse_mice_rpt(tBTA_HH_BOOT_RPT *p_kb_data, + UINT8 *p_report, UINT16 report_len); +extern BOOLEAN bta_hh_tod_spt(tBTA_HH_DEV_CB *p_cb,UINT8 sub_class); +extern void bta_hh_clean_up_kdev(tBTA_HH_DEV_CB *p_cb); + +extern void bta_hh_add_device_to_list(tBTA_HH_DEV_CB *p_cb, UINT8 handle, + UINT16 attr_mask, + tHID_DEV_DSCP_INFO *p_dscp_info, + UINT8 sub_class, UINT16 max_latency, UINT16 min_tout, UINT8 app_id); +extern void bta_hh_update_di_info(tBTA_HH_DEV_CB *p_cb, UINT16 vendor_id, UINT16 product_id, + UINT16 version, UINT8 flag); +extern void bta_hh_cleanup_disable(tBTA_HH_STATUS status); + +extern UINT8 bta_hh_dev_handle_to_cb_idx(UINT8 dev_handle); + +/* action functions used outside state machine */ +extern void bta_hh_api_enable(tBTA_HH_DATA *p_data); +extern void bta_hh_api_disable(void); +extern void bta_hh_disc_cmpl(void); + +extern tBTA_HH_STATUS bta_hh_read_ssr_param(BD_ADDR bd_addr, UINT16 *p_max_ssr_lat, UINT16 *p_min_ssr_tout); + +/* functions for LE HID */ +extern void bta_hh_le_enable(void); +extern BOOLEAN bta_hh_le_is_hh_gatt_if(tBTA_GATTC_IF client_if); +extern void bta_hh_le_deregister(void); +extern BOOLEAN bta_hh_is_le_device(tBTA_HH_DEV_CB *p_cb, BD_ADDR remote_bda); +extern void bta_hh_le_open_conn(tBTA_HH_DEV_CB *p_cb, BD_ADDR remote_bda); +extern void bta_hh_le_api_disc_act(tBTA_HH_DEV_CB *p_cb); +extern void bta_hh_le_get_dscp_act(tBTA_HH_DEV_CB *p_cb); +extern void bta_hh_le_write_dev_act(tBTA_HH_DEV_CB *p_cb, tBTA_HH_DATA *p_data); +extern UINT8 bta_hh_le_add_device(tBTA_HH_DEV_CB *p_cb, tBTA_HH_MAINT_DEV *p_dev_info); +extern void bta_hh_le_remove_dev_bg_conn(tBTA_HH_DEV_CB *p_cb); +extern void bta_hh_le_open_fail(tBTA_HH_DEV_CB *p_cb, tBTA_HH_DATA *p_data); +extern void bta_hh_gatt_open(tBTA_HH_DEV_CB *p_cb, tBTA_HH_DATA *p_data); +extern void bta_hh_gatt_close(tBTA_HH_DEV_CB *p_cb, tBTA_HH_DATA *p_data); +extern void bta_hh_start_security(tBTA_HH_DEV_CB *p_cb, tBTA_HH_DATA *p_buf); +extern void bta_hh_start_srvc_discovery(tBTA_HH_DEV_CB *p_cb, tBTA_HH_DATA *p_buf); +extern void bta_hh_w4_le_read_char_cmpl(tBTA_HH_DEV_CB *p_cb, tBTA_HH_DATA *p_buf); +extern void bta_hh_le_read_char_cmpl(tBTA_HH_DEV_CB *p_cb, tBTA_HH_DATA *p_buf); +extern void bta_hh_w4_le_read_descr_cmpl(tBTA_HH_DEV_CB *p_cb, tBTA_HH_DATA *p_buf); +extern void bta_hh_le_read_descr_cmpl(tBTA_HH_DEV_CB *p_cb, tBTA_HH_DATA *p_buf); +extern void bta_hh_w4_le_write_cmpl(tBTA_HH_DEV_CB *p_cb, tBTA_HH_DATA *p_buf); +extern void bta_hh_le_write_cmpl(tBTA_HH_DEV_CB *p_cb, tBTA_HH_DATA *p_buf); +extern void bta_hh_le_write_char_descr_cmpl(tBTA_HH_DEV_CB *p_cb, tBTA_HH_DATA *p_buf); +extern void bta_hh_start_security(tBTA_HH_DEV_CB *p_cb, tBTA_HH_DATA *p_buf); +extern void bta_hh_security_cmpl(tBTA_HH_DEV_CB *p_cb, tBTA_HH_DATA *p_buf); +extern void bta_hh_le_update_scpp(tBTA_HH_DEV_CB *p_cb, tBTA_HH_DATA *p_buf); +extern void bta_hh_le_notify_enc_cmpl(tBTA_HH_DEV_CB *p_cb, tBTA_HH_DATA *p_data); +extern void bta_hh_ci_load_rpt (tBTA_HH_DEV_CB *p_cb, tBTA_HH_DATA *p_buf); + +#if BTA_HH_DEBUG +extern void bta_hh_trace_dev_db(void); +#endif + +#endif + diff --git a/components/bt/bluedroid/bta/hh/bta_hh_le.c b/components/bt/bluedroid/bta/hh/bta_hh_le.c new file mode 100644 index 0000000000..48b0610723 --- /dev/null +++ b/components/bt/bluedroid/bta/hh/bta_hh_le.c @@ -0,0 +1,3168 @@ +/****************************************************************************** + * + * Copyright (C) 2009-2013 Broadcom Corporation + * + * 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. + * + ******************************************************************************/ + +#include "bta_api.h" +#include "bta_hh_int.h" + +#if (defined BTA_HH_LE_INCLUDED && BTA_HH_LE_INCLUDED == TRUE) + +#include "bta_api.h" +#include +#include "btm_api.h" +#include "btm_ble_api.h" +#include "bta_hh_co.h" +#include "bta_gatt_api.h" +#include "srvc_api.h" +#include "btm_int.h" +#include "utl.h" + +#define LOG_TAG "bt_bta_hh" +#include "osi/include/log.h" + +#ifndef BTA_HH_LE_RECONN +#define BTA_HH_LE_RECONN TRUE +#endif + +#define BTA_HH_APP_ID_LE 0xff + +#define BTA_HH_LE_RPT_TYPE_VALID(x) ((x) <= BTA_LE_HID_RPT_FEATURE && (x)>=BTA_LE_HID_RPT_INPUT) + +#define BTA_HH_LE_RPT_INST_ID_MAP(s,c) (UINT8)(((s)<<4)|(c)) +#define BTA_HH_LE_RPT_GET_SRVC_INST_ID(x) (UINT8)(x >> 4) +#define BTA_HH_LE_RPT_GET_RPT_INST_ID(x) (UINT8)(x & 0x0f) + + +#define BTA_HH_LE_PROTO_BOOT_MODE 0x00 +#define BTA_HH_LE_PROTO_REPORT_MODE 0x01 + +#define BTA_HH_SCPP_INST_DEF 0 + +#define BTA_HH_LE_DISC_CHAR_NUM 8 +static const UINT16 bta_hh_le_disc_char_uuid[BTA_HH_LE_DISC_CHAR_NUM] = +{ + GATT_UUID_HID_INFORMATION, + GATT_UUID_HID_REPORT_MAP, + GATT_UUID_HID_CONTROL_POINT, + GATT_UUID_HID_REPORT, + GATT_UUID_HID_BT_KB_INPUT, + GATT_UUID_HID_BT_KB_OUTPUT, + GATT_UUID_HID_BT_MOUSE_INPUT, + GATT_UUID_HID_PROTO_MODE /* always make sure this is the last attribute to discover */ +}; + +#define BTA_LE_HID_RTP_UUID_MAX 5 +static const UINT16 bta_hh_uuid_to_rtp_type[BTA_LE_HID_RTP_UUID_MAX][2] = +{ + {GATT_UUID_HID_REPORT, BTA_HH_RPTT_INPUT}, + {GATT_UUID_HID_BT_KB_INPUT, BTA_HH_RPTT_INPUT}, + {GATT_UUID_HID_BT_KB_OUTPUT, BTA_HH_RPTT_OUTPUT}, + {GATT_UUID_HID_BT_MOUSE_INPUT, BTA_HH_RPTT_INPUT}, + {GATT_UUID_BATTERY_LEVEL, BTA_HH_RPTT_INPUT} +}; + + +static void bta_hh_gattc_callback(tBTA_GATTC_EVT event, tBTA_GATTC *p_data); +static void bta_hh_le_search_hid_chars(tBTA_HH_DEV_CB *p_dev_cb); +static void bta_hh_le_search_hid_included(tBTA_HH_DEV_CB *p_dev_cb); +static void bta_hh_le_search_scps(tBTA_HH_DEV_CB *p_cb); +static void bta_hh_le_search_scps_chars(tBTA_HH_DEV_CB *p_cb); +static void bta_hh_le_register_scpp_notif(tBTA_HH_DEV_CB *p_dev_cb, tBTA_GATT_STATUS status); +static void bta_hh_le_register_scpp_notif_cmpl(tBTA_HH_DEV_CB *p_dev_cb, tBTA_GATT_STATUS status); +static void bta_hh_le_add_dev_bg_conn(tBTA_HH_DEV_CB *p_cb, BOOLEAN check_bond); +static void bta_hh_process_cache_rpt (tBTA_HH_DEV_CB *p_cb, + tBTA_HH_RPT_CACHE_ENTRY *p_rpt_cache, + UINT8 num_rpt); + +#define BTA_HH_LE_SRVC_DEF 0 + +#if BTA_HH_DEBUG == TRUE +static const char *bta_hh_le_rpt_name[4] = +{ + "UNKNOWN", + "INPUT", + "OUTPUT", + "FEATURE" +}; + +/******************************************************************************* +** +** Function bta_hh_le_hid_report_dbg +** +** Description debug function to print out all HID report available on remote +** device. +** +** Returns void +** +*******************************************************************************/ +static void bta_hh_le_hid_report_dbg(tBTA_HH_DEV_CB *p_cb) +{ + UINT8 i , j; + tBTA_HH_LE_RPT *p_rpt; + char * rpt_name; + + APPL_TRACE_DEBUG("HID Report DB"); + for (i = 0; i < BTA_HH_LE_HID_SRVC_MAX; i ++) + { + if (p_cb->hid_srvc[i].in_use) + { + p_rpt = &p_cb->hid_srvc[i].report[0]; + + APPL_TRACE_DEBUG("\t HID serivce inst: %d", i); + + for (j = 0; j < BTA_HH_LE_RPT_MAX; j ++, p_rpt++) + { + rpt_name = "Unknown"; + if (p_rpt->in_use) + { + if (p_rpt->uuid == GATT_UUID_HID_REPORT) + rpt_name = "Report"; + if (p_rpt->uuid == GATT_UUID_HID_BT_KB_INPUT) + rpt_name = "Boot KB Input"; + if (p_rpt->uuid == GATT_UUID_HID_BT_KB_OUTPUT) + rpt_name = "Boot KB Output"; + if (p_rpt->uuid == GATT_UUID_HID_BT_MOUSE_INPUT) + rpt_name = "Boot MI Input"; + + + APPL_TRACE_DEBUG("\t\t [%s- 0x%04x] [Type: %s], [ReportID: %d] [inst_id: %d] [Clt_cfg: %d]", + rpt_name, + p_rpt->uuid , + ((p_rpt->rpt_type < 4) ? bta_hh_le_rpt_name[p_rpt->rpt_type] : "UNKNOWN"), + p_rpt->rpt_id, + p_rpt->inst_id, + p_rpt->client_cfg_value); + } + else + break; + } + } + else + break; + } +} + +/******************************************************************************* +** +** Function bta_hh_uuid_to_str +** +** Description +** +** Returns void +** +*******************************************************************************/ +static char *bta_hh_uuid_to_str(UINT16 uuid) +{ + switch(uuid) + { + case GATT_UUID_HID_INFORMATION: + return "GATT_UUID_HID_INFORMATION"; + case GATT_UUID_HID_REPORT_MAP: + return "GATT_UUID_HID_REPORT_MAP"; + case GATT_UUID_HID_CONTROL_POINT: + return "GATT_UUID_HID_CONTROL_POINT"; + case GATT_UUID_HID_REPORT: + return "GATT_UUID_HID_REPORT"; + case GATT_UUID_HID_PROTO_MODE: + return "GATT_UUID_HID_PROTO_MODE"; + case GATT_UUID_HID_BT_KB_INPUT: + return "GATT_UUID_HID_BT_KB_INPUT"; + case GATT_UUID_HID_BT_KB_OUTPUT: + return "GATT_UUID_HID_BT_KB_OUTPUT"; + case GATT_UUID_HID_BT_MOUSE_INPUT: + return "GATT_UUID_HID_BT_MOUSE_INPUT"; + case GATT_UUID_CHAR_CLIENT_CONFIG: + return "GATT_UUID_CHAR_CLIENT_CONFIG"; + case GATT_UUID_EXT_RPT_REF_DESCR: + return "GATT_UUID_EXT_RPT_REF_DESCR"; + case GATT_UUID_RPT_REF_DESCR: + return "GATT_UUID_RPT_REF_DESCR"; + default: + return "Unknown UUID"; + } +} + +#endif +/******************************************************************************* +** +** Function bta_hh_le_enable +** +** Description initialize LE HID related functionality +** +** +** Returns void +** +*******************************************************************************/ +void bta_hh_le_enable(void) +{ + char app_name[LEN_UUID_128 + 1]; + tBT_UUID app_uuid = {LEN_UUID_128,{0}}; + UINT8 xx; + + bta_hh_cb.gatt_if = BTA_GATTS_INVALID_IF; + + for (xx = 0; xx < BTA_HH_MAX_DEVICE; xx ++) + bta_hh_cb.le_cb_index[xx] = BTA_HH_IDX_INVALID; + + memset (app_name, 0, LEN_UUID_128 + 1); + strncpy(app_name, "BTA HH OVER LE", LEN_UUID_128); + + memcpy((void *)app_uuid.uu.uuid128, (void *)app_name, LEN_UUID_128); + + BTA_GATTC_AppRegister(&app_uuid, bta_hh_gattc_callback); + + return; +} + +/******************************************************************************* +** +** Function bta_hh_le_register_cmpl +** +** Description BTA HH register with BTA GATTC completed +** +** Parameters: +** +*******************************************************************************/ +void bta_hh_le_register_cmpl(tBTA_GATTC_REG *p_reg) +{ + tBTA_HH_STATUS status = BTA_HH_ERR; + + if (p_reg->status == BTA_GATT_OK) + { + bta_hh_cb.gatt_if = p_reg->client_if; + status = BTA_HH_OK; + } + else + bta_hh_cb.gatt_if = BTA_GATTS_INVALID_IF; + + /* signal BTA call back event */ + (* bta_hh_cb.p_cback)(BTA_HH_ENABLE_EVT, (tBTA_HH *)&status); +} + +/******************************************************************************* +** +** Function bta_hh_le_is_hh_gatt_if +** +** Description Check to see if client_if is BTA HH LE GATT interface +** +** +** Returns whether it is HH GATT IF +** +*******************************************************************************/ +BOOLEAN bta_hh_le_is_hh_gatt_if(tBTA_GATTC_IF client_if) +{ + return (bta_hh_cb.gatt_if == client_if); +} + +/******************************************************************************* +** +** Function bta_hh_le_deregister +** +** Description De-register BTA HH from BTA GATTC +** +** +** Returns void +** +*******************************************************************************/ +void bta_hh_le_deregister(void) +{ + BTA_GATTC_AppDeregister(bta_hh_cb.gatt_if); +} + +/******************************************************************************* +** +** Function bta_hh_is_le_device +** +** Description Check to see if the remote device is a LE only device +** +** Parameters: +** +*******************************************************************************/ +BOOLEAN bta_hh_is_le_device(tBTA_HH_DEV_CB *p_cb, BD_ADDR remote_bda) +{ + p_cb->is_le_device = BTM_UseLeLink (remote_bda); + + return p_cb->is_le_device; +} + +/******************************************************************************* +** +** Function bta_hh_le_add_hid_srvc_entry +** +** Description Add a HID service entry in the HID device control block +** +** Parameters: +** +*******************************************************************************/ +BOOLEAN bta_hh_le_add_hid_srvc_entry(tBTA_HH_DEV_CB *p_dev_cb, UINT8 idx) +{ + BOOLEAN added = FALSE; + + if (idx < BTA_HH_LE_HID_SRVC_MAX) + { + p_dev_cb->hid_srvc[idx].in_use = TRUE; + added = TRUE; + } + else + { + APPL_TRACE_ERROR("DB full,max HID service entry!"); + } + return added; +} + +/******************************************************************************* +** +** Function bta_hh_le_open_conn +** +** Description open a GATT connection first. +** +** Parameters: +** +*******************************************************************************/ +void bta_hh_le_open_conn(tBTA_HH_DEV_CB *p_cb, BD_ADDR remote_bda) +{ + /* update cb_index[] map */ + p_cb->hid_handle = BTA_HH_GET_LE_DEV_HDL(p_cb->index); + memcpy(p_cb->addr, remote_bda, BD_ADDR_LEN); + bta_hh_cb.le_cb_index[BTA_HH_GET_LE_CB_IDX(p_cb->hid_handle)] = p_cb->index; + p_cb->in_use = TRUE; + + BTA_GATTC_Open(bta_hh_cb.gatt_if, remote_bda, TRUE, BTA_GATT_TRANSPORT_LE); +} + +/******************************************************************************* +** +** Function bta_hh_le_fill_16bits_gatt_id +** +** Description Utility function to fill a GATT ID strucure +** +*******************************************************************************/ +void bta_hh_le_fill_16bits_gatt_id(UINT8 inst_id, UINT16 uuid, tBTA_GATT_ID *p_output) +{ + p_output->inst_id = inst_id; + p_output->uuid.len = LEN_UUID_16; + p_output->uuid.uu.uuid16 = uuid; +} + +/******************************************************************************* +** +** Function bta_hh_le_fill_16bits_srvc_id +** +** Description Utility function to fill a service ID strucure with a 16 bits +** service UUID. +** +*******************************************************************************/ +void bta_hh_le_fill_16bits_srvc_id(BOOLEAN is_pri, UINT8 inst_id, UINT16 srvc_uuid, + tBTA_GATT_SRVC_ID *p_output) +{ + memset((void *)p_output, 0, sizeof(tBTA_GATT_SRVC_ID)); + p_output->is_primary = is_pri; + bta_hh_le_fill_16bits_gatt_id(inst_id, srvc_uuid, &p_output->id); + +} + +/******************************************************************************* +** +** Function bta_hh_le_fill_16bits_char_id +** +** Description Utility function to fill a char ID strucure with a 16 bits +** char UUID. +** +*******************************************************************************/ +void bta_hh_le_fill_16bits_char_id(UINT8 inst_id, UINT16 char_uuid, + tBTA_GATT_ID *p_output) +{ + memset((void *)p_output, 0, sizeof(tBTA_GATT_ID)); + bta_hh_le_fill_16bits_gatt_id(inst_id, char_uuid, p_output); +} + +/******************************************************************************* +** +** Function bta_hh_le_find_dev_cb_by_conn_id +** +** Description Utility function find a device control block by connection ID. +** +*******************************************************************************/ +tBTA_HH_DEV_CB * bta_hh_le_find_dev_cb_by_conn_id(UINT16 conn_id) +{ + UINT8 i; + tBTA_HH_DEV_CB *p_dev_cb = &bta_hh_cb.kdev[0]; + + for (i = 0; i < BTA_HH_MAX_DEVICE; i ++, p_dev_cb ++) + { + if (p_dev_cb->in_use && p_dev_cb->conn_id == conn_id) + return p_dev_cb; + } + return NULL; +} + +/******************************************************************************* +** +** Function bta_hh_le_find_dev_cb_by_bda +** +** Description Utility function find a device control block by BD address. +** +*******************************************************************************/ +tBTA_HH_DEV_CB * bta_hh_le_find_dev_cb_by_bda(BD_ADDR bda) +{ + UINT8 i; + tBTA_HH_DEV_CB *p_dev_cb = &bta_hh_cb.kdev[0]; + + for (i = 0; i < BTA_HH_MAX_DEVICE; i ++, p_dev_cb ++) + { + if (p_dev_cb->in_use && + memcmp(p_dev_cb->addr, bda, BD_ADDR_LEN) == 0) + return p_dev_cb; + } + return NULL; +} + +/******************************************************************************* +** +** Function bta_hh_le_find_service_inst_by_battery_inst_id +** +** Description find HID service instance ID by battery service instance ID +** +*******************************************************************************/ +UINT8 bta_hh_le_find_service_inst_by_battery_inst_id(tBTA_HH_DEV_CB *p_cb, UINT8 ba_inst_id) +{ + UINT8 i; + + for (i = 0; i < BTA_HH_LE_HID_SRVC_MAX; i ++) + { + if (p_cb->hid_srvc[i].in_use && + p_cb->hid_srvc[i].incl_srvc_inst == ba_inst_id) + { + return i; + } + } + return BTA_HH_IDX_INVALID; +} + +/******************************************************************************* +** +** Function bta_hh_le_find_report_entry +** +** Description find the report entry by service instance and report UUID and +** instance ID +** +*******************************************************************************/ +tBTA_HH_LE_RPT * bta_hh_le_find_report_entry(tBTA_HH_DEV_CB *p_cb, + UINT8 srvc_inst_id, /* service instance ID */ + UINT16 rpt_uuid, + UINT8 char_inst_id) +{ + UINT8 i; + UINT8 hid_inst_id = srvc_inst_id; + tBTA_HH_LE_RPT *p_rpt; + + if (rpt_uuid == GATT_UUID_BATTERY_LEVEL) + { + hid_inst_id = bta_hh_le_find_service_inst_by_battery_inst_id(p_cb, srvc_inst_id); + + if (hid_inst_id == BTA_HH_IDX_INVALID) + return NULL; + } + + p_rpt = &p_cb->hid_srvc[hid_inst_id].report[0]; + + for (i = 0; i < BTA_HH_LE_RPT_MAX; i ++, p_rpt ++) + { + if (p_rpt->uuid == rpt_uuid && + p_rpt->inst_id == BTA_HH_LE_RPT_INST_ID_MAP(srvc_inst_id, char_inst_id)) + { + + return p_rpt; + } + } + return NULL; + +} + +/******************************************************************************* +** +** Function bta_hh_le_find_rpt_by_idtype +** +** Description find a report entry by report ID and protocol mode +** +** Returns void +** +*******************************************************************************/ +tBTA_HH_LE_RPT * bta_hh_le_find_rpt_by_idtype(tBTA_HH_LE_RPT*p_head, UINT8 mode, + tBTA_HH_RPT_TYPE r_type, UINT8 rpt_id) +{ + tBTA_HH_LE_RPT *p_rpt = p_head; + UINT8 i; + +#if BTA_HH_DEBUG == TRUE + APPL_TRACE_DEBUG("bta_hh_le_find_rpt_by_idtype: r_type: %d rpt_id: %d", r_type, rpt_id); +#endif + + for (i = 0 ; i < BTA_HH_LE_RPT_MAX; i ++, p_rpt++) + { + if (p_rpt->in_use && p_rpt->rpt_id == rpt_id && r_type == p_rpt->rpt_type) + { + /* return battery report w/o condition */ + if (p_rpt->uuid == GATT_UUID_BATTERY_LEVEL) + return p_rpt; + + if (mode == BTA_HH_PROTO_RPT_MODE && p_rpt->uuid == GATT_UUID_HID_REPORT) + return p_rpt; + + if ( mode ==BTA_HH_PROTO_BOOT_MODE && + (p_rpt->uuid >= GATT_UUID_HID_BT_KB_INPUT && p_rpt->uuid <= GATT_UUID_HID_BT_MOUSE_INPUT)) + return p_rpt; + } + } + return NULL; +} + +/******************************************************************************* +** +** Function bta_hh_le_find_alloc_report_entry +** +** Description find or allocate a report entry in the HID service report list. +** +*******************************************************************************/ +tBTA_HH_LE_RPT * bta_hh_le_find_alloc_report_entry(tBTA_HH_DEV_CB *p_cb, + UINT8 srvc_inst_id, + UINT16 rpt_uuid, + UINT8 inst_id, + UINT8 prop) +{ + UINT8 i, hid_inst_id = srvc_inst_id; + tBTA_HH_LE_RPT *p_rpt; + + if (rpt_uuid == GATT_UUID_BATTERY_LEVEL) + { + hid_inst_id = bta_hh_le_find_service_inst_by_battery_inst_id(p_cb, srvc_inst_id); + + if (hid_inst_id == BTA_HH_IDX_INVALID) + return NULL; + } + p_rpt = &p_cb->hid_srvc[hid_inst_id].report[0]; + + for (i = 0; i < BTA_HH_LE_RPT_MAX; i ++, p_rpt ++) + { + if (!p_rpt->in_use || + (p_rpt->uuid == rpt_uuid && + p_rpt->inst_id == BTA_HH_LE_RPT_INST_ID_MAP(srvc_inst_id, inst_id))) + { + if (!p_rpt->in_use) + { + p_rpt->in_use = TRUE; + p_rpt->index = i; + p_rpt->inst_id = BTA_HH_LE_RPT_INST_ID_MAP(srvc_inst_id, inst_id); + p_rpt->prop = prop; + p_rpt->uuid = rpt_uuid; + + /* assign report type */ + for (i = 0; i < BTA_LE_HID_RTP_UUID_MAX; i ++) + { + if (bta_hh_uuid_to_rtp_type[i][0] == rpt_uuid) + { + p_rpt->rpt_type = (tBTA_HH_RPT_TYPE)bta_hh_uuid_to_rtp_type[i][1]; + + if (rpt_uuid == GATT_UUID_HID_BT_KB_INPUT || rpt_uuid == GATT_UUID_HID_BT_KB_OUTPUT) + p_rpt->rpt_id = BTA_HH_KEYBD_RPT_ID; + + if (rpt_uuid == GATT_UUID_HID_BT_MOUSE_INPUT) + p_rpt->rpt_id = BTA_HH_MOUSE_RPT_ID; + + break; + } + } + } + return p_rpt; + } + } + return NULL; +} + +/******************************************************************************* +** +** Function bta_hh_le_read_char_dscrpt +** +** Description read characteristic descriptor +** +*******************************************************************************/ +tBTA_HH_STATUS bta_hh_le_read_char_dscrpt(tBTA_HH_DEV_CB *p_cb, UINT16 srvc_uuid, UINT8 srvc_inst_id, + UINT16 char_uuid, UINT8 char_inst_id, UINT16 char_descp_uuid) +{ + tBTA_GATTC_CHAR_ID char_id; + tBT_UUID descr_uuid; + tBTA_GATTC_CHAR_DESCR_ID descr_id; + tBTA_HH_STATUS status = BTA_HH_ERR; + + bta_hh_le_fill_16bits_srvc_id(TRUE, srvc_inst_id, srvc_uuid, &char_id.srvc_id); + bta_hh_le_fill_16bits_char_id(char_inst_id, char_uuid, &char_id.char_id); + + descr_uuid.len = LEN_UUID_16; + descr_uuid.uu.uuid16 = char_descp_uuid; + + /* find the report reference descriptor */ + if (BTA_GATTC_GetFirstCharDescr(p_cb->conn_id, + &char_id, + &descr_uuid, + &descr_id) == BTA_GATT_OK) + { + BTA_GATTC_ReadCharDescr(p_cb->conn_id, + &descr_id, + BTA_GATT_AUTH_REQ_NONE); + + status = BTA_HH_OK; + } + else + { +#if BTA_HH_DEBUG == TRUE + LOG_WARN("%s No descriptor exists: %s(0x%04x)", __func__, + bta_hh_uuid_to_str(char_descp_uuid), char_descp_uuid); +#endif + } + return status; +} + +/******************************************************************************* +** +** Function bta_hh_le_read_rpt_ref_descr +** +** Description read report refernece descriptors in service discovery process +** +*******************************************************************************/ +void bta_hh_le_read_rpt_ref_descr(tBTA_HH_DEV_CB *p_dev_cb, tBTA_HH_LE_RPT *p_rpt) +{ + BOOLEAN started = FALSE; + UINT16 srvc_uuid, char_uuid; + + while (p_rpt != NULL) + { + if(!p_rpt->in_use) + break; + + if (p_rpt->rpt_type == BTA_HH_RPTT_INPUT) + { + /* is battery report */ + if (p_rpt->uuid == GATT_UUID_BATTERY_LEVEL) + { +#if BTA_HH_DEBUG == TRUE + APPL_TRACE_DEBUG("read battery level report reference descriptor"); +#endif + srvc_uuid = UUID_SERVCLASS_BATTERY; + char_uuid = GATT_UUID_BATTERY_LEVEL; + } + else + { +#if BTA_HH_DEBUG == TRUE + APPL_TRACE_DEBUG("read HID report reference descriptor"); +#endif + srvc_uuid = UUID_SERVCLASS_LE_HID; + char_uuid = GATT_UUID_HID_REPORT; + } + + if (bta_hh_le_read_char_dscrpt(p_dev_cb, + srvc_uuid, + BTA_HH_LE_RPT_GET_SRVC_INST_ID(p_rpt->inst_id), + char_uuid, + BTA_HH_LE_RPT_GET_RPT_INST_ID(p_rpt->inst_id), + GATT_UUID_RPT_REF_DESCR) + == BTA_HH_OK) + { + started = TRUE; + break; + } + } + + if (p_rpt->index == BTA_HH_LE_RPT_MAX - 1) + break; + + p_rpt ++; + } + + + /* if no report reference descriptor */ + if (!started) + { + /* explore next char */ + bta_hh_le_search_hid_chars(p_dev_cb); + } +} + +/******************************************************************************* +** +** Function bta_hh_le_save_rpt_ref +** +** Description save report reference information and move to next one. +** +** Parameters: +** +*******************************************************************************/ +void bta_hh_le_save_rpt_ref(tBTA_HH_DEV_CB *p_dev_cb, tBTA_HH_LE_RPT *p_rpt, + tBTA_GATTC_READ *p_data) +{ + UINT8 *pp; + tBTA_HH_RPT_CACHE_ENTRY rpt_entry; + + /* if the length of the descriptor value is right, parse it */ + if (p_data->status == BTA_GATT_OK && + p_data->p_value && p_data->p_value->unformat.len == 2) + { + pp = p_data->p_value->unformat.p_value; + + STREAM_TO_UINT8(p_rpt->rpt_id, pp); + STREAM_TO_UINT8(p_rpt->rpt_type, pp); + + if (p_rpt->rpt_type > BTA_HH_RPTT_FEATURE) /* invalid report type */ + p_rpt->rpt_type = BTA_HH_RPTT_RESRV; + +#if BTA_HH_DEBUG == TRUE + APPL_TRACE_DEBUG("report ID: %d", p_rpt->rpt_id); +#endif + rpt_entry.rpt_id = p_rpt->rpt_id; + rpt_entry.rpt_type = p_rpt->rpt_type; + rpt_entry.rpt_uuid = p_rpt->uuid; + rpt_entry.prop = p_rpt->prop; + rpt_entry.inst_id = p_rpt->inst_id; + + bta_hh_le_co_rpt_info(p_dev_cb->addr, + &rpt_entry, + p_dev_cb->app_id); + } + else if (p_data->status == BTA_GATT_INSUF_AUTHENTICATION) + { + /* close connection right away */ + p_dev_cb->status = BTA_HH_ERR_AUTH_FAILED; + /* close the connection and report service discovery complete with error */ + bta_hh_le_api_disc_act(p_dev_cb); + return; + } + + if (p_rpt->index < BTA_HH_LE_RPT_MAX - 1) + p_rpt ++; + else + p_rpt = NULL; + + /* read next report reference descriptor */ + bta_hh_le_read_rpt_ref_descr(p_dev_cb, p_rpt); + +} + +/******************************************************************************* +** +** Function bta_hh_le_save_rpt_ref +** +** Description save report reference information and move to next one. +** +** Parameters: +** +*******************************************************************************/ +void bta_hh_le_save_ext_rpt_ref(tBTA_HH_DEV_CB *p_dev_cb, + tBTA_GATTC_READ *p_data) +{ + UINT8 *pp; + + /* if the length of the descriptor value is right, parse it + assume it's a 16 bits UUID */ + if (p_data->status == BTA_GATT_OK && + p_data->p_value && p_data->p_value->unformat.len == 2) + { + pp = p_data->p_value->unformat.p_value; + STREAM_TO_UINT16(p_dev_cb->hid_srvc[p_dev_cb->cur_srvc_index].ext_rpt_ref, pp); + +#if BTA_HH_DEBUG == TRUE + APPL_TRACE_DEBUG("External Report Reference UUID 0x%04x", + p_dev_cb->hid_srvc[p_dev_cb->cur_srvc_index].ext_rpt_ref); +#endif + } + bta_hh_le_search_hid_chars(p_dev_cb); + +} + +/******************************************************************************* +** +** Function bta_hh_le_register_input_notif +** +** Description Register for all notifications for the report applicable +** for the protocol mode. +** +** Parameters: +** +*******************************************************************************/ +void bta_hh_le_register_input_notif(tBTA_HH_DEV_CB *p_dev_cb, UINT8 srvc_inst, + UINT8 proto_mode, BOOLEAN register_ba) +{ + tBTA_HH_LE_RPT *p_rpt = &p_dev_cb->hid_srvc[srvc_inst].report[0]; + tBTA_GATTC_CHAR_ID char_id; + UINT8 i; + UINT16 srvc_uuid; + +#if BTA_HH_DEBUG == TRUE + APPL_TRACE_DEBUG("bta_hh_le_register_input_notif mode: %d", proto_mode); +#endif + + for (i = 0; i < BTA_HH_LE_RPT_MAX; i ++, p_rpt ++) + { + if (p_rpt->rpt_type == BTA_HH_RPTT_INPUT) + { + if (p_rpt->uuid == GATT_UUID_BATTERY_LEVEL) + srvc_uuid = UUID_SERVCLASS_BATTERY; + else + srvc_uuid = UUID_SERVCLASS_LE_HID; + + bta_hh_le_fill_16bits_srvc_id(TRUE, BTA_HH_LE_RPT_GET_SRVC_INST_ID(p_rpt->inst_id), srvc_uuid, &char_id.srvc_id); + bta_hh_le_fill_16bits_char_id(BTA_HH_LE_RPT_GET_RPT_INST_ID(p_rpt->inst_id), p_rpt->uuid, &char_id.char_id); + + if (register_ba && p_rpt->uuid == GATT_UUID_BATTERY_LEVEL) + { + BTA_GATTC_RegisterForNotifications(bta_hh_cb.gatt_if, + p_dev_cb->addr, + &char_id); + } + /* boot mode, deregister report input notification */ + else if (proto_mode == BTA_HH_PROTO_BOOT_MODE) + { + if (p_rpt->uuid == GATT_UUID_HID_REPORT && + p_rpt->client_cfg_value == BTA_GATT_CLT_CONFIG_NOTIFICATION) + { + APPL_TRACE_DEBUG("---> Deregister Report ID: %d", p_rpt->rpt_id); + BTA_GATTC_DeregisterForNotifications(bta_hh_cb.gatt_if, + p_dev_cb->addr, + &char_id); + } + /* register boot reports notification */ + else if (p_rpt->uuid == GATT_UUID_HID_BT_KB_INPUT || + p_rpt->uuid == GATT_UUID_HID_BT_MOUSE_INPUT) + { + APPL_TRACE_DEBUG("<--- Register Boot Report ID: %d", p_rpt->rpt_id); + BTA_GATTC_RegisterForNotifications(bta_hh_cb.gatt_if, + p_dev_cb->addr, + &char_id); + } + } + else if (proto_mode == BTA_HH_PROTO_RPT_MODE) + { + if ((p_rpt->uuid == GATT_UUID_HID_BT_KB_INPUT || + p_rpt->uuid == GATT_UUID_HID_BT_MOUSE_INPUT) && + p_rpt->client_cfg_value == BTA_GATT_CLT_CONFIG_NOTIFICATION) + { + + APPL_TRACE_DEBUG("---> Deregister Boot Report ID: %d", p_rpt->rpt_id); + BTA_GATTC_DeregisterForNotifications(bta_hh_cb.gatt_if, + p_dev_cb->addr, + &char_id); + } + else if (p_rpt->uuid == GATT_UUID_HID_REPORT && + p_rpt->client_cfg_value == BTA_GATT_CLT_CONFIG_NOTIFICATION) + { + APPL_TRACE_DEBUG("<--- Register Report ID: %d", p_rpt->rpt_id); + BTA_GATTC_RegisterForNotifications(bta_hh_cb.gatt_if, + p_dev_cb->addr, + &char_id); + } + } + /* + else unknow protocol mode */ + } + } +} + +/******************************************************************************* +** +** Function bta_hh_le_open_cmpl +** +** Description HID over GATT connection sucessfully opened +** +*******************************************************************************/ +void bta_hh_le_open_cmpl(tBTA_HH_DEV_CB *p_cb) +{ + if ( p_cb->disc_active == BTA_HH_LE_DISC_NONE) + { +#if BTA_HH_DEBUG + bta_hh_le_hid_report_dbg(p_cb); +#endif + bta_hh_le_register_input_notif(p_cb, 0, p_cb->mode, TRUE); + bta_hh_sm_execute(p_cb, BTA_HH_OPEN_CMPL_EVT, NULL); + +#if (BTA_HH_LE_RECONN == TRUE) + if (p_cb->status == BTA_HH_OK) + { + bta_hh_le_add_dev_bg_conn(p_cb, TRUE); + } +#endif + } +} + +/******************************************************************************* +** +** Function bta_hh_le_write_char_clt_cfg +** +** Description Utility function to find and write client configuration of +** a characteristic +** +*******************************************************************************/ +BOOLEAN bta_hh_le_write_char_clt_cfg(tBTA_HH_DEV_CB *p_cb, + UINT8 srvc_inst_id, UINT16 srvc_uuid16, + UINT8 char_inst_id, UINT16 char_uuid16, + UINT16 clt_cfg_value) +{ + tBTA_GATTC_CHAR_ID char_id; + tBT_UUID descr_cond; + tBTA_GATTC_CHAR_DESCR_ID descr_id; + tBTA_GATT_UNFMT value; + UINT8 buf[2], *pp = buf; + + bta_hh_le_fill_16bits_srvc_id(TRUE, srvc_inst_id, srvc_uuid16, &char_id.srvc_id); + bta_hh_le_fill_16bits_char_id(char_inst_id, char_uuid16, &char_id.char_id); + + descr_cond.len = LEN_UUID_16; + descr_cond.uu.uuid16 = GATT_UUID_CHAR_CLIENT_CONFIG; + + value.len = 2; + value.p_value = buf; + + UINT16_TO_STREAM(pp, clt_cfg_value); + + if (BTA_GATTC_GetFirstCharDescr(p_cb->conn_id, + &char_id, + &descr_cond, + &descr_id) == BTA_GATT_OK) + { + BTA_GATTC_WriteCharDescr(p_cb->conn_id, + &descr_id, + BTA_GATTC_TYPE_WRITE, + &value, + BTA_GATT_AUTH_REQ_NONE); + + return TRUE; + } + return FALSE; +} + +/******************************************************************************* +** +** Function bta_hh_le_write_rpt_clt_cfg +** +** Description write client configuration. This is only for input report +** enable all input notification upon connection open. +** +*******************************************************************************/ +BOOLEAN bta_hh_le_write_rpt_clt_cfg(tBTA_HH_DEV_CB *p_cb, UINT8 srvc_inst_id) +{ + UINT8 i; + tBTA_HH_LE_RPT *p_rpt = &p_cb->hid_srvc[srvc_inst_id].report[p_cb->clt_cfg_idx]; + UINT16 srvc_uuid; + + for (i = p_cb->clt_cfg_idx; i < BTA_HH_LE_RPT_MAX && p_rpt->in_use; i ++, p_rpt ++) + { + /* enable notification for all input report, regardless mode */ + if (p_rpt->rpt_type == BTA_HH_RPTT_INPUT) + + { + if (p_rpt->uuid == GATT_UUID_BATTERY_LEVEL) + srvc_uuid = UUID_SERVCLASS_BATTERY; + else + srvc_uuid = UUID_SERVCLASS_LE_HID; + + if (bta_hh_le_write_char_clt_cfg(p_cb, + BTA_HH_LE_RPT_GET_SRVC_INST_ID(p_rpt->inst_id), + srvc_uuid, + BTA_HH_LE_RPT_GET_RPT_INST_ID(p_rpt->inst_id), + p_rpt->uuid, + BTA_GATT_CLT_CONFIG_NOTIFICATION)) + { + p_cb->clt_cfg_idx = i; + return TRUE; + } + } + + } + p_cb->clt_cfg_idx = 0; + + /* client configuration is completed, send open callback */ + if (p_cb->state == BTA_HH_W4_CONN_ST) + { + p_cb->disc_active &= ~BTA_HH_LE_DISC_HIDS; + + /* discover scan parameter profile is act as report host */ + bta_hh_le_search_scps(p_cb); + } + return FALSE; +} + +/******************************************************************************* +** +** Function bta_hh_le_set_protocol_mode +** +** Description Set remote device protocol mode. +** +*******************************************************************************/ +BOOLEAN bta_hh_le_set_protocol_mode(tBTA_HH_DEV_CB *p_cb, tBTA_HH_PROTO_MODE mode) +{ + tBTA_GATTC_CHAR_ID char_id; + tBTA_HH_CBDATA cback_data ; + BOOLEAN exec = FALSE; + + APPL_TRACE_DEBUG("bta_hh_le_set_protocol_mode attempt mode: %s", + (mode == BTA_HH_PROTO_RPT_MODE)? "Report": "Boot"); + + cback_data.handle = p_cb->hid_handle; + /* boot mode is not supported in the remote device */ + if ((p_cb->hid_srvc[BTA_HH_LE_SRVC_DEF].option_char & BTA_HH_LE_PROTO_MODE_BIT) == 0) + { + p_cb->mode = BTA_HH_PROTO_RPT_MODE; + + if (mode == BTA_HH_PROTO_BOOT_MODE) + { + APPL_TRACE_ERROR("Set Boot Mode failed!! No PROTO_MODE Char!"); + cback_data.status = BTA_HH_ERR; + } + else + { + /* if set to report mode, need to de-register all input report notification */ + bta_hh_le_register_input_notif(p_cb, 0, p_cb->mode, FALSE); + cback_data.status = BTA_HH_OK; + } + if (p_cb->state == BTA_HH_W4_CONN_ST) + { + p_cb->status = (cback_data.status == BTA_HH_OK)? BTA_HH_OK: BTA_HH_ERR_PROTO; + } + else + (* bta_hh_cb.p_cback)(BTA_HH_SET_PROTO_EVT, (tBTA_HH *)&cback_data); + } + else if (p_cb->mode != mode) + { + bta_hh_le_fill_16bits_srvc_id(TRUE, 0, UUID_SERVCLASS_LE_HID, &char_id.srvc_id); + bta_hh_le_fill_16bits_char_id(0, GATT_UUID_HID_PROTO_MODE, &char_id.char_id); + + p_cb->mode = mode; + mode = (mode == BTA_HH_PROTO_BOOT_MODE)? BTA_HH_LE_PROTO_BOOT_MODE : BTA_HH_LE_PROTO_REPORT_MODE; + + BTA_GATTC_WriteCharValue(p_cb->conn_id, + &char_id, + BTA_GATTC_TYPE_WRITE_NO_RSP, + 1, + &mode, + BTA_GATT_AUTH_REQ_NONE); + exec = TRUE; + } + + return exec; +} + +/******************************************************************************* +** +** Function bta_hh_le_get_protocol_mode +** +** Description Get remote device protocol mode. +** +*******************************************************************************/ +void bta_hh_le_get_protocol_mode(tBTA_HH_DEV_CB *p_cb) +{ + tBTA_GATTC_CHAR_ID char_id; + tBTA_HH_HSDATA hs_data; + UINT8 i; + + p_cb->w4_evt = BTA_HH_GET_PROTO_EVT; + + for (i = 0; i< BTA_HH_LE_HID_SRVC_MAX; i ++) + { + if (p_cb->hid_srvc[i].in_use && + p_cb->hid_srvc[i].option_char & BTA_HH_LE_PROTO_MODE_BIT) + { + bta_hh_le_fill_16bits_srvc_id(TRUE, 0, UUID_SERVCLASS_LE_HID, &char_id.srvc_id); + bta_hh_le_fill_16bits_char_id(0, GATT_UUID_HID_PROTO_MODE, &char_id.char_id); + + BTA_GATTC_ReadCharacteristic(p_cb->conn_id, + &char_id, + BTA_GATT_AUTH_REQ_NONE); + break; + } + } + /* no service support protocol_mode, by default report mode */ + if (i == BTA_HH_LE_HID_SRVC_MAX) + { + hs_data.status = BTA_HH_OK; + hs_data.handle = p_cb->hid_handle; + hs_data.rsp_data.proto_mode = BTA_HH_PROTO_RPT_MODE; + p_cb->w4_evt = 0; + (* bta_hh_cb.p_cback)(BTA_HH_GET_PROTO_EVT, (tBTA_HH *)&hs_data); + } + +} + +/******************************************************************************* +** +** Function bta_hh_le_expl_rpt +** +** Description explore all report characteristic +** +*******************************************************************************/ +void bta_hh_le_expl_rpt(tBTA_HH_DEV_CB *p_dev_cb, + tBTA_GATTC_CHAR_ID *p_char_id, + tBT_UUID *p_char_cond, + tBTA_GATT_CHAR_PROP prop) +{ + tBTA_GATTC_CHAR_ID char_result; + + do + { + if (bta_hh_le_find_alloc_report_entry(p_dev_cb, + p_dev_cb->cur_srvc_index, + GATT_UUID_HID_REPORT, + p_char_id->char_id.inst_id, + prop) == NULL) + { + APPL_TRACE_ERROR("Add report entry failed !!!"); + break; + } + + APPL_TRACE_DEBUG("Find more REPORT"); + + if (BTA_GATTC_GetNextChar(p_dev_cb->conn_id, + p_char_id, + p_char_cond, + &char_result, + &prop) != BTA_GATT_OK) + break; + + p_char_id = &char_result; + } + while (1); + + LOG_INFO("%s all BLE reports searched", __func__); + bta_hh_le_read_rpt_ref_descr(p_dev_cb, + &p_dev_cb->hid_srvc[p_dev_cb->cur_srvc_index].report[0]); + + + return ; +} + +/******************************************************************************* +** +** Function bta_hh_le_expl_boot_rpt +** +** Description explore boot report +** +*******************************************************************************/ +void bta_hh_le_expl_boot_rpt(tBTA_HH_DEV_CB *p_dev_cb, UINT16 char_uuid, + tBTA_GATT_CHAR_PROP prop) +{ + if (bta_hh_le_find_alloc_report_entry(p_dev_cb, + p_dev_cb->cur_srvc_index, + char_uuid, + 0, + prop) == NULL) + + { + APPL_TRACE_ERROR("Add report entry failed !!!"); + } + + return; +} + +/******************************************************************************* +** +** Function bta_hh_le_dis_cback +** +** Description DIS read complete callback +** +** Parameters: +** +*******************************************************************************/ +void bta_hh_le_dis_cback(BD_ADDR addr, tDIS_VALUE *p_dis_value) +{ + tBTA_HH_DEV_CB *p_cb = bta_hh_le_find_dev_cb_by_bda(addr); + + + if (p_cb == NULL || p_dis_value == NULL) + { + APPL_TRACE_ERROR("received unexpected/error DIS callback"); + return; + } + + p_cb->disc_active &= ~BTA_HH_LE_DISC_DIS; + /* plug in the PnP info for this device */ + if (p_dis_value->attr_mask & DIS_ATTR_PNP_ID_BIT) + { +#if BTA_HH_DEBUG == TRUE + APPL_TRACE_DEBUG("Plug in PnP info: product_id = %02x, vendor_id = %04x, version = %04x", + p_dis_value->pnp_id.product_id, + p_dis_value->pnp_id.vendor_id, + p_dis_value->pnp_id.product_version); +#endif + p_cb->dscp_info.product_id = p_dis_value->pnp_id.product_id; + p_cb->dscp_info.vendor_id = p_dis_value->pnp_id.vendor_id; + p_cb->dscp_info.version = p_dis_value->pnp_id.product_version; + } + bta_hh_le_open_cmpl(p_cb); +} + +/******************************************************************************* +** +** Function bta_hh_le_pri_service_discovery +** +** Description Initialize GATT discovery on the remote LE HID device by opening +** a GATT connection first. +** +** Parameters: +** +*******************************************************************************/ +void bta_hh_le_pri_service_discovery(tBTA_HH_DEV_CB *p_cb) +{ + tBT_UUID pri_srvc; + + bta_hh_le_co_reset_rpt_cache(p_cb->addr, p_cb->app_id); + + p_cb->disc_active |= (BTA_HH_LE_DISC_HIDS|BTA_HH_LE_DISC_DIS); + + /* read DIS info */ + if (!DIS_ReadDISInfo(p_cb->addr, bta_hh_le_dis_cback, DIS_ATTR_PNP_ID_BIT)) + { + APPL_TRACE_ERROR("read DIS failed"); + p_cb->disc_active &= ~BTA_HH_LE_DISC_DIS; + } + + /* in parallel */ + /* start primary service discovery for HID service */ + pri_srvc.len = LEN_UUID_16; + pri_srvc.uu.uuid16 = UUID_SERVCLASS_LE_HID; + BTA_GATTC_ServiceSearchRequest(p_cb->conn_id, &pri_srvc); + return; +} + +/******************************************************************************* +** +** Function bta_hh_le_encrypt_cback +** +** Description link encryption complete callback for bond verification. +** +** Returns None +** +*******************************************************************************/ +void bta_hh_le_encrypt_cback(BD_ADDR bd_addr, tBTA_GATT_TRANSPORT transport, + void *p_ref_data, tBTM_STATUS result) +{ + UINT8 idx = bta_hh_find_cb(bd_addr); + tBTA_HH_DEV_CB *p_dev_cb; + UNUSED(p_ref_data); + UNUSED (transport); + + if (idx != BTA_HH_IDX_INVALID) + p_dev_cb = &bta_hh_cb.kdev[idx]; + else + { + APPL_TRACE_ERROR("unexpected encryption callback, ignore"); + return; + } + p_dev_cb->status = (result == BTM_SUCCESS) ? BTA_HH_OK : BTA_HH_ERR_SEC; + p_dev_cb->reason = result; + + bta_hh_sm_execute(p_dev_cb, BTA_HH_ENC_CMPL_EVT, NULL); +} + +/******************************************************************************* +** +** Function bta_hh_security_cmpl +** +** Description Security check completed, start the service discovery +** if no cache available, otherwise report connection open completed +** +** Parameters: +** +*******************************************************************************/ +void bta_hh_security_cmpl(tBTA_HH_DEV_CB *p_cb, tBTA_HH_DATA *p_buf) +{ + tBTA_HH_RPT_CACHE_ENTRY *p_rpt_cache; + UINT8 num_rpt = 0; + UNUSED(p_buf); + + if (p_cb->status == BTA_HH_OK) + { + APPL_TRACE_DEBUG("bta_hh_security_cmpl OK"); + if (!p_cb->hid_srvc[BTA_HH_LE_SRVC_DEF].in_use) + { + APPL_TRACE_DEBUG("bta_hh_security_cmpl no reports loaded, try to load"); + /* start loading the cache if not in stack */ + if ((p_rpt_cache = bta_hh_le_co_cache_load(p_cb->addr, &num_rpt, p_cb->app_id)) != NULL) + { + bta_hh_process_cache_rpt(p_cb, p_rpt_cache, num_rpt); + } + } + /* discovery has been done for HID service */ + if (p_cb->app_id != 0 && p_cb->hid_srvc[BTA_HH_LE_SRVC_DEF].in_use) + { + /* configure protocol mode */ + if (bta_hh_le_set_protocol_mode(p_cb, p_cb->mode) == FALSE) + { + APPL_TRACE_ERROR("bta_hh_security_cmpl"); + bta_hh_le_open_cmpl(p_cb); + } + } + /* start primary service discovery for HID service */ + else + { + bta_hh_le_pri_service_discovery(p_cb); + } + } + else + { + APPL_TRACE_ERROR("%s() - encryption failed; status=0x%04x, reason=0x%04x", + __FUNCTION__, p_cb->status, p_cb->reason); + if (!(p_cb->status == BTA_HH_ERR_SEC && p_cb->reason == BTM_ERR_PROCESSING)) + bta_hh_le_api_disc_act(p_cb); + } +} + +/******************************************************************************* +** +** Function bta_hh_le_notify_enc_cmpl +** +** Description process GATT encryption complete event +** +** Returns +** +*******************************************************************************/ +void bta_hh_le_notify_enc_cmpl(tBTA_HH_DEV_CB *p_cb, tBTA_HH_DATA *p_buf) +{ + if (p_cb == NULL || p_cb->security_pending == FALSE || + p_buf == NULL || p_buf->le_enc_cmpl.client_if != bta_hh_cb.gatt_if) + { + return; + } + + p_cb->security_pending = FALSE; + bta_hh_start_security(p_cb, NULL); +} + +/******************************************************************************* +** +** Function bta_hh_clear_service_cache +** +** Description clear the service cache +** +** Parameters: +** +*******************************************************************************/ +void bta_hh_clear_service_cache(tBTA_HH_DEV_CB *p_cb) +{ + UINT8 i; + tBTA_HH_LE_HID_SRVC *p_hid_srvc = &p_cb->hid_srvc[0]; + + p_cb->app_id = 0; + p_cb->total_srvc = 0; + p_cb->dscp_info.descriptor.dsc_list = NULL; + + for (i = 0; i < BTA_HH_LE_HID_SRVC_MAX; i ++, p_hid_srvc ++) + { + utl_freebuf((void **)&p_hid_srvc->rpt_map); + memset(p_hid_srvc, 0, sizeof(tBTA_HH_LE_HID_SRVC)); + } +} + +/******************************************************************************* +** +** Function bta_hh_start_security +** +** Description start the security check of the established connection +** +** Parameters: +** +*******************************************************************************/ +void bta_hh_start_security(tBTA_HH_DEV_CB *p_cb, tBTA_HH_DATA *p_buf) +{ + UINT8 sec_flag=0; + tBTM_SEC_DEV_REC *p_dev_rec; + UNUSED(p_buf); + + p_dev_rec = btm_find_dev(p_cb->addr); + if (p_dev_rec) + { + if (p_dev_rec->sec_state == BTM_SEC_STATE_ENCRYPTING || + p_dev_rec->sec_state == BTM_SEC_STATE_AUTHENTICATING) + { + /* if security collision happened, wait for encryption done */ + p_cb->security_pending = TRUE; + return; + } + } + + /* verify bond */ + BTM_GetSecurityFlagsByTransport(p_cb->addr, &sec_flag, BT_TRANSPORT_LE); + + /* if link has been encrypted */ + if (sec_flag & BTM_SEC_FLAG_ENCRYPTED) + { + bta_hh_sm_execute(p_cb, BTA_HH_ENC_CMPL_EVT, NULL); + } + /* if bonded and link not encrypted */ + else if (sec_flag & BTM_SEC_FLAG_LKEY_KNOWN) + { + sec_flag = BTM_BLE_SEC_ENCRYPT; + p_cb->status = BTA_HH_ERR_AUTH_FAILED; + BTM_SetEncryption(p_cb->addr, BTA_TRANSPORT_LE, bta_hh_le_encrypt_cback, &sec_flag); + } + /* unbonded device, report security error here */ + else if (p_cb->sec_mask != BTA_SEC_NONE) + { + sec_flag = BTM_BLE_SEC_ENCRYPT_NO_MITM; + p_cb->status = BTA_HH_ERR_AUTH_FAILED; + bta_hh_clear_service_cache(p_cb); + BTM_SetEncryption(p_cb->addr, BTA_TRANSPORT_LE, bta_hh_le_encrypt_cback, &sec_flag); + } + /* otherwise let it go through */ + else + { + bta_hh_sm_execute(p_cb, BTA_HH_ENC_CMPL_EVT, NULL); + } + + +} + +/******************************************************************************* +** +** Function bta_hh_gatt_open +** +** Description process GATT open event. +** +** Parameters: +** +*******************************************************************************/ +void bta_hh_gatt_open(tBTA_HH_DEV_CB *p_cb, tBTA_HH_DATA *p_buf) +{ + tBTA_GATTC_OPEN *p_data = &p_buf->le_open; + UINT8 *p2; + tHID_STATUS status = BTA_HH_ERR; + + /* if received invalid callback data , ignore it */ + if (p_cb == NULL || p_data == NULL) + return; + + p2 = p_data->remote_bda; + + APPL_TRACE_DEBUG("bta_hh_gatt_open BTA_GATTC_OPEN_EVT bda= [%08x%04x] status =%d", + ((p2[0])<<24)+((p2[1])<<16)+((p2[2])<<8)+(p2[3]), + ((p2[4])<<8)+ p2[5],p_data->status); + + if (p_data->status == BTA_GATT_OK) + { + p_cb->is_le_device = TRUE; + p_cb->in_use = TRUE; + p_cb->conn_id = p_data->conn_id; + p_cb->hid_handle = BTA_HH_GET_LE_DEV_HDL(p_cb->index); + + bta_hh_cb.le_cb_index[BTA_HH_GET_LE_CB_IDX(p_cb->hid_handle)] = p_cb->index; + +#if BTA_HH_DEBUG == TRUE + APPL_TRACE_DEBUG("hid_handle = %2x conn_id = %04x cb_index = %d", p_cb->hid_handle, p_cb->conn_id, p_cb->index); +#endif + + bta_hh_sm_execute(p_cb, BTA_HH_START_ENC_EVT, NULL); + + } + else /* open failure */ + { + bta_hh_sm_execute(p_cb, BTA_HH_SDP_CMPL_EVT, (tBTA_HH_DATA *)&status); + } + +} + +/******************************************************************************* +** +** Function bta_hh_le_close +** +** Description This function process the GATT close event and post it as a +** BTA HH internal event +** +** Parameters: +** +*******************************************************************************/ +void bta_hh_le_close(tBTA_GATTC_CLOSE * p_data) +{ + tBTA_HH_DEV_CB *p_dev_cb = bta_hh_le_find_dev_cb_by_bda(p_data->remote_bda); + tBTA_HH_LE_CLOSE *p_buf = NULL; + UINT16 sm_event = BTA_HH_GATT_CLOSE_EVT; + + if (p_dev_cb != NULL && + (p_buf = (tBTA_HH_LE_CLOSE *)GKI_getbuf(sizeof(tBTA_HH_LE_CLOSE))) != NULL) + { + p_buf->hdr.event = sm_event; + p_buf->hdr.layer_specific = (UINT16)p_dev_cb->hid_handle; + p_buf->conn_id = p_data->conn_id; + p_buf->reason = p_data->reason; + + p_dev_cb->conn_id = BTA_GATT_INVALID_CONN_ID; + p_dev_cb->security_pending = FALSE; + bta_sys_sendmsg(p_buf); + } +} + +/******************************************************************************* +** +** Function bta_hh_le_search_result +** +** Description This function process the GATT service search result. +** +** Parameters: +** +*******************************************************************************/ +void bta_hh_le_search_result(tBTA_GATTC_SRVC_RES *p_srvc_result) +{ + tBTA_HH_DEV_CB *p_dev_cb = bta_hh_le_find_dev_cb_by_conn_id(p_srvc_result->conn_id); + + if (p_dev_cb != NULL) + { + switch (p_srvc_result->service_uuid.id.uuid.uu.uuid16) + { + case UUID_SERVCLASS_LE_HID: + if (p_srvc_result->service_uuid.is_primary) + { + /* found HID primamry service */ + /* TODO: proceed to find battery and device info */ + if (bta_hh_le_add_hid_srvc_entry(p_dev_cb, p_dev_cb->total_srvc)) + p_dev_cb->total_srvc ++; + APPL_TRACE_DEBUG("num of hid service: %d", p_dev_cb->total_srvc); + } + break; + + case UUID_SERVCLASS_SCAN_PARAM : /* scan parameter service */ + bta_hh_le_search_scps_chars(p_dev_cb); + break; + } + + } + +} + + +/******************************************************************************* +** +** Function bta_hh_le_gatt_disc_cmpl +** +** Description Check to see if the remote device is a LE only device +** +** Parameters: +** +*******************************************************************************/ +void bta_hh_le_gatt_disc_cmpl(tBTA_HH_DEV_CB *p_cb, tBTA_HH_STATUS status) +{ + APPL_TRACE_DEBUG("bta_hh_le_gatt_disc_cmpl "); + + /* if open sucessful or protocol mode not desired, keep the connection open but inform app */ + if (status == BTA_HH_OK || status == BTA_HH_ERR_PROTO) + { + /* assign a special APP ID temp, since device type unknown */ + p_cb->app_id = BTA_HH_APP_ID_LE; + + /* set report notification configuration */ + p_cb->clt_cfg_idx = 0; + bta_hh_le_write_rpt_clt_cfg(p_cb, BTA_HH_LE_SRVC_DEF); + } + else /* error, close the GATT connection */ + { + /* close GATT connection if it's on */ + bta_hh_le_api_disc_act(p_cb); + } +} + +/******************************************************************************* +** +** Function bta_hh_le_srvc_expl_srvc +** +** Description This function discover the next avaible HID service. +** +** Parameters: +** +*******************************************************************************/ +void bta_hh_le_srvc_expl_srvc(tBTA_HH_DEV_CB *p_dev_cb) +{ +#if BTA_HH_DEBUG == TRUE + APPL_TRACE_DEBUG("bta_hh_le_srvc_expl_srvc cur_srvc_index = %d in_use = %d", + p_dev_cb->cur_srvc_index, + p_dev_cb->hid_srvc[p_dev_cb->cur_srvc_index].in_use); +#endif + + if (p_dev_cb->cur_srvc_index < BTA_HH_LE_HID_SRVC_MAX && + p_dev_cb->hid_srvc[p_dev_cb->cur_srvc_index].in_use) + { + if (!p_dev_cb->hid_srvc[p_dev_cb->cur_srvc_index].expl_incl_srvc) + /* explore included service first */ + bta_hh_le_search_hid_included(p_dev_cb); + else + { + /* explore characterisc */ + p_dev_cb->hid_srvc[p_dev_cb->cur_srvc_index].cur_expl_char_idx = 0; + bta_hh_le_search_hid_chars(p_dev_cb); + } + } + else /* all service discvery finished */ + { + bta_hh_le_gatt_disc_cmpl(p_dev_cb, p_dev_cb->status); + } +} + +/******************************************************************************* +** +** Function bta_hh_le_srvc_search_cmpl +** +** Description This function process the GATT service search complete. +** +** Parameters: +** +*******************************************************************************/ +void bta_hh_le_srvc_search_cmpl(tBTA_GATTC_SEARCH_CMPL *p_data) +{ + tBTA_HH_DEV_CB *p_dev_cb = bta_hh_le_find_dev_cb_by_conn_id(p_data->conn_id); + + /* service search exception or no HID service is supported on remote */ + if (p_dev_cb == NULL) + return; + + if(p_data->status != BTA_GATT_OK || p_dev_cb->total_srvc == 0) + { + p_dev_cb->status = BTA_HH_ERR_SDP; + /* close the connection and report service discovery complete with error */ + bta_hh_le_api_disc_act(p_dev_cb); + } + /* GATT service discovery sucessfully finished */ + else + { + if (p_dev_cb->disc_active & BTA_HH_LE_DISC_SCPS) + { + p_dev_cb->disc_active &= ~BTA_HH_LE_DISC_SCPS; + bta_hh_le_open_cmpl(p_dev_cb); + } + else /* discover HID service */ + { + p_dev_cb->cur_srvc_index = 0; + bta_hh_le_srvc_expl_srvc(p_dev_cb); + } +} +} + +/******************************************************************************* +** +** Function bta_hh_le_search_hid_included +** +** Description This function search the included service within the HID service. +** +** Parameters: +** +*******************************************************************************/ +static void bta_hh_le_search_hid_included(tBTA_HH_DEV_CB *p_dev_cb) +{ + tBT_UUID srvc_cond, char_cond; + tBTA_GATTC_INCL_SVC_ID inc_srvc_result; + tBTA_GATT_SRVC_ID srvc_id; + tBTA_GATTC_CHAR_ID char_result; + tBTA_GATT_CHAR_PROP prop = 0; + + bta_hh_le_fill_16bits_srvc_id(TRUE, p_dev_cb->cur_srvc_index, UUID_SERVCLASS_LE_HID, &srvc_id); + + srvc_cond.len = LEN_UUID_16; + srvc_cond.uu.uuid16 = UUID_SERVCLASS_BATTERY; + + if (BTA_GATTC_GetFirstIncludedService(p_dev_cb->conn_id, + &srvc_id, + &srvc_cond, + &inc_srvc_result) == BTA_GATT_OK) + { + /* read include service UUID */ + p_dev_cb->hid_srvc[p_dev_cb->cur_srvc_index].incl_srvc_inst = inc_srvc_result.incl_svc_id.id.inst_id; + + char_cond.len = LEN_UUID_16; + char_cond.uu.uuid16 = GATT_UUID_BATTERY_LEVEL; + + /* find the battery characteristic */ + if (BTA_GATTC_GetFirstChar( p_dev_cb->conn_id, + &inc_srvc_result.incl_svc_id, + &char_cond, + &char_result, + &prop) == BTA_GATT_OK) + { + + if (bta_hh_le_find_alloc_report_entry(p_dev_cb, + char_result.srvc_id.id.inst_id, + GATT_UUID_BATTERY_LEVEL, + char_result.char_id.inst_id, + prop) == NULL) + { + APPL_TRACE_ERROR("Add battery report entry failed !!!") + } + + /* read the battery characteristic */ + BTA_GATTC_ReadCharacteristic(p_dev_cb->conn_id, + &char_result, + BTA_GATT_AUTH_REQ_NONE); + + return; + + } + else + { + APPL_TRACE_ERROR("Remote device does not have battery level"); + } + } + + p_dev_cb->hid_srvc[p_dev_cb->cur_srvc_index].expl_incl_srvc = TRUE; + + bta_hh_le_srvc_expl_srvc(p_dev_cb); + +} + +/******************************************************************************* +** +** Function bta_hh_read_battery_level_cmpl +** +** Description This function process the battery level read +** +** Parameters: +** +*******************************************************************************/ +void bta_hh_read_battery_level_cmpl(UINT8 status, tBTA_HH_DEV_CB *p_dev_cb, tBTA_GATTC_READ *p_data) +{ + UNUSED(status); + UNUSED(p_data); + + p_dev_cb->hid_srvc[p_dev_cb->cur_srvc_index].expl_incl_srvc = TRUE; + bta_hh_le_srvc_expl_srvc(p_dev_cb); +} +/******************************************************************************* +** +** Function bta_hh_le_search_hid_chars +** +** Description This function discover all characteristics a service and +** all descriptors available. +** +** Parameters: +** +*******************************************************************************/ +static void bta_hh_le_search_hid_chars(tBTA_HH_DEV_CB *p_dev_cb) +{ + tBT_UUID char_cond; + tBTA_GATTC_CHAR_ID char_result; + tBTA_GATT_CHAR_PROP prop; + BOOLEAN next = TRUE; + UINT16 char_uuid = 0; + tBTA_GATT_SRVC_ID srvc_id; + + if (p_dev_cb->hid_srvc[p_dev_cb->cur_srvc_index].cur_expl_char_idx == BTA_HH_LE_DISC_CHAR_NUM || + (p_dev_cb->status != BTA_HH_OK && p_dev_cb->status != BTA_HH_ERR_PROTO)) + { + p_dev_cb->hid_srvc[p_dev_cb->cur_srvc_index].cur_expl_char_idx = 0; + /* explore next service */ + p_dev_cb->cur_srvc_index ++; + bta_hh_le_srvc_expl_srvc(p_dev_cb); + return; + } + + p_dev_cb->hid_srvc[ p_dev_cb->cur_srvc_index].cur_expl_char_idx ++; + char_uuid = bta_hh_le_disc_char_uuid[p_dev_cb->hid_srvc[p_dev_cb->cur_srvc_index].cur_expl_char_idx - 1]; + + char_cond.len = LEN_UUID_16; + char_cond.uu.uuid16 = char_uuid; + + bta_hh_le_fill_16bits_srvc_id(TRUE, p_dev_cb->cur_srvc_index, UUID_SERVCLASS_LE_HID, &srvc_id); + +#if BTA_HH_DEBUG == TRUE + APPL_TRACE_DEBUG("bta_hh_le_search_hid_chars: looking for %s(0x%04x)", + bta_hh_uuid_to_str(char_uuid), char_uuid); +#endif + + if (BTA_GATTC_GetFirstChar( p_dev_cb->conn_id, + &srvc_id, + &char_cond, + &char_result, + &prop) == BTA_GATT_OK) + { + switch (char_uuid) + { + case GATT_UUID_HID_CONTROL_POINT: + p_dev_cb->hid_srvc[char_result.srvc_id.id.inst_id].option_char |= BTA_HH_LE_CP_BIT; + next = TRUE; + break; + case GATT_UUID_HID_INFORMATION: + case GATT_UUID_HID_REPORT_MAP: + /* read the char value */ + BTA_GATTC_ReadCharacteristic(p_dev_cb->conn_id, + &char_result, + BTA_GATT_AUTH_REQ_NONE); + next = FALSE; + break; + + case GATT_UUID_HID_PROTO_MODE: + p_dev_cb->hid_srvc[char_result.srvc_id.id.inst_id].option_char |= BTA_HH_LE_PROTO_MODE_BIT; + next = !bta_hh_le_set_protocol_mode(p_dev_cb, p_dev_cb->mode); + break; + + case GATT_UUID_HID_REPORT: + bta_hh_le_expl_rpt(p_dev_cb, &char_result, &char_cond, prop); + next = FALSE; + break; + + /* found boot mode report types */ + case GATT_UUID_HID_BT_KB_OUTPUT: + case GATT_UUID_HID_BT_MOUSE_INPUT: + case GATT_UUID_HID_BT_KB_INPUT: + bta_hh_le_expl_boot_rpt(p_dev_cb, char_uuid, prop); + break; + } + } + else + { + if (char_uuid == GATT_UUID_HID_PROTO_MODE) + next = !bta_hh_le_set_protocol_mode(p_dev_cb, p_dev_cb->mode); + + } + + if (next == TRUE) + { + bta_hh_le_search_hid_chars(p_dev_cb); + } +} + +/******************************************************************************* +** +** Function bta_hh_le_save_rpt_map +** +** Description save the report map into the control block. +** +** Parameters: +** +*******************************************************************************/ +void bta_hh_le_save_rpt_map(tBTA_HH_DEV_CB *p_dev_cb, tBTA_GATTC_READ *p_data) +{ + UINT8 *pp ; + tBTA_HH_LE_HID_SRVC *p_srvc = &p_dev_cb->hid_srvc[p_data->srvc_id.id.inst_id]; + + pp = p_data->p_value->unformat.p_value; + + /* save report descriptor */ + if (p_srvc->rpt_map != NULL) + GKI_freebuf((void*)p_srvc->rpt_map); + + if (p_data->p_value->unformat.len > 0) + p_srvc->rpt_map = (UINT8 *)GKI_getbuf(p_data->p_value->unformat.len); + + if (p_srvc->rpt_map != NULL) + { + STREAM_TO_ARRAY(p_srvc->rpt_map, pp, p_data->p_value->unformat.len); + p_srvc->descriptor.dl_len = p_data->p_value->unformat.len; + p_srvc->descriptor.dsc_list = p_dev_cb->hid_srvc[p_data->srvc_id.id.inst_id].rpt_map; + } + + if (bta_hh_le_read_char_dscrpt(p_dev_cb, + UUID_SERVCLASS_LE_HID, + p_data->srvc_id.id.inst_id, + GATT_UUID_HID_REPORT_MAP, + p_data->char_id.inst_id, + GATT_UUID_EXT_RPT_REF_DESCR) != BTA_HH_OK) + { + bta_hh_le_search_hid_chars(p_dev_cb); + } +} + +/******************************************************************************* +** +** Function bta_hh_le_proc_get_rpt_cmpl +** +** Description Process the Read report complete, send GET_REPORT_EVT to application +** with the report data. +** +** Parameters: +** +*******************************************************************************/ +void bta_hh_le_proc_get_rpt_cmpl(tBTA_HH_DEV_CB *p_dev_cb, tBTA_GATTC_READ *p_data) +{ + BT_HDR *p_buf = NULL; + tBTA_HH_LE_RPT *p_rpt; + tBTA_HH_HSDATA hs_data; + UINT8 *pp ; + + if (p_dev_cb->w4_evt != BTA_HH_GET_RPT_EVT) + { + APPL_TRACE_ERROR("Unexpected READ cmpl, w4_evt = %d", p_dev_cb->w4_evt); + return; + } + + memset(&hs_data, 0, sizeof(hs_data)); + hs_data.status = BTA_HH_ERR; + hs_data.handle = p_dev_cb->hid_handle; + + if (p_data->status == BTA_GATT_OK) + { + p_rpt = bta_hh_le_find_report_entry(p_dev_cb, + p_data->srvc_id.id.inst_id,//BTA_HH_LE_SRVC_DEF, + p_data->char_id.uuid.uu.uuid16, + p_data->char_id.inst_id); + + if (p_rpt != NULL && + p_data->p_value != NULL && + (p_buf = (BT_HDR *)GKI_getbuf((UINT16)(sizeof(BT_HDR) +p_data->p_value->unformat.len + 1))) != NULL) + { + /* pack data send to app */ + hs_data.status = BTA_HH_OK; + p_buf->len = p_data->p_value->unformat.len + 1; + p_buf->layer_specific = 0; + p_buf->offset = 0; + + /* attach report ID as the first byte of the report before sending it to USB HID driver */ + pp = (UINT8*)(p_buf + 1); + UINT8_TO_STREAM(pp, p_rpt->rpt_id); + memcpy(pp, p_data->p_value->unformat.p_value, p_data->p_value->unformat.len); + + hs_data.rsp_data.p_rpt_data =p_buf; + } + } + + p_dev_cb->w4_evt = 0; + (* bta_hh_cb.p_cback)(BTA_HH_GET_RPT_EVT, (tBTA_HH *)&hs_data); + + utl_freebuf((void **)&p_buf); +} + +/******************************************************************************* +** +** Function bta_hh_le_proc_read_proto_mode +** +** Description Process the Read protocol mode, send GET_PROTO_EVT to application +** with the protocol mode. +** +*******************************************************************************/ +void bta_hh_le_proc_read_proto_mode(tBTA_HH_DEV_CB *p_dev_cb, tBTA_GATTC_READ *p_data) +{ + tBTA_HH_HSDATA hs_data; + + hs_data.status = BTA_HH_ERR; + hs_data.handle = p_dev_cb->hid_handle; + hs_data.rsp_data.proto_mode = p_dev_cb->mode; + + if (p_data->status == BTA_GATT_OK && p_data->p_value) + { + hs_data.status = BTA_HH_OK; + /* match up BTE/BTA report/boot mode def*/ + hs_data.rsp_data.proto_mode = *(p_data->p_value->unformat.p_value); + /* LE repot mode is the opposite value of BR/EDR report mode, flip it here */ + if (hs_data.rsp_data.proto_mode == 0) + hs_data.rsp_data.proto_mode = BTA_HH_PROTO_BOOT_MODE; + else + hs_data.rsp_data.proto_mode = BTA_HH_PROTO_RPT_MODE; + + p_dev_cb->mode = hs_data.rsp_data.proto_mode; + } +#if BTA_HH_DEBUG + APPL_TRACE_DEBUG("LE GET_PROTOCOL Mode = [%s]", + (hs_data.rsp_data.proto_mode == BTA_HH_PROTO_RPT_MODE)? "Report" : "Boot"); +#endif + + p_dev_cb->w4_evt = 0; + (* bta_hh_cb.p_cback)(BTA_HH_GET_PROTO_EVT, (tBTA_HH *)&hs_data); + +} + +/******************************************************************************* +** +** Function bta_hh_w4_le_read_char_cmpl +** +** Description process the GATT read complete in W4_CONN state. +** +** Parameters: +** +*******************************************************************************/ +void bta_hh_w4_le_read_char_cmpl(tBTA_HH_DEV_CB *p_dev_cb, tBTA_HH_DATA *p_buf) +{ + tBTA_GATTC_READ * p_data = (tBTA_GATTC_READ *)p_buf; + UINT8 *pp ; + + if (p_data->char_id.uuid.uu.uuid16 == GATT_UUID_BATTERY_LEVEL) + { + bta_hh_read_battery_level_cmpl(p_data->status, p_dev_cb, p_data); + } + else + { + if (p_data->status == BTA_GATT_OK && p_data->p_value) + { + pp = p_data->p_value->unformat.p_value; + + switch (p_data->char_id.uuid.uu.uuid16) + { + /* save device information */ + case GATT_UUID_HID_INFORMATION: + STREAM_TO_UINT16(p_dev_cb->dscp_info.version, pp); + STREAM_TO_UINT8(p_dev_cb->dscp_info.ctry_code, pp); + STREAM_TO_UINT8(p_dev_cb->dscp_info.flag, pp); + break; + + case GATT_UUID_HID_REPORT_MAP: + bta_hh_le_save_rpt_map(p_dev_cb, p_data); + return; + + default: +#if BTA_HH_DEBUG == TRUE + APPL_TRACE_ERROR("Unexpected read %s(0x%04x)", + bta_hh_uuid_to_str(p_data->char_id.uuid.uu.uuid16), + p_data->char_id.uuid.uu.uuid16); +#endif + break; + } + } + else + { +#if BTA_HH_DEBUG == TRUE + APPL_TRACE_ERROR("read uuid %s[0x%04x] error: %d", + bta_hh_uuid_to_str(p_data->char_id.uuid.uu.uuid16), + p_data->char_id.uuid.uu.uuid16, + p_data->status); +#else + APPL_TRACE_ERROR("read uuid [0x%04x] error: %d", p_data->char_id.uuid.uu.uuid16, p_data->status); +#endif + } + bta_hh_le_search_hid_chars(p_dev_cb); + } + +} + +/******************************************************************************* +** +** Function bta_hh_le_read_char_cmpl +** +** Description a characteristic value is received. +** +** Parameters: +** +*******************************************************************************/ +void bta_hh_le_read_char_cmpl (tBTA_HH_DEV_CB *p_dev_cb, tBTA_HH_DATA *p_buf) +{ + tBTA_GATTC_READ * p_data = (tBTA_GATTC_READ *)p_buf; + + switch (p_data->char_id.uuid.uu.uuid16) + { + /* GET_REPORT */ + case GATT_UUID_HID_REPORT: + case GATT_UUID_HID_BT_KB_INPUT: + case GATT_UUID_HID_BT_KB_OUTPUT: + case GATT_UUID_HID_BT_MOUSE_INPUT: + case GATT_UUID_BATTERY_LEVEL: /* read battery level */ + bta_hh_le_proc_get_rpt_cmpl(p_dev_cb, p_data); + break; + + case GATT_UUID_HID_PROTO_MODE: + bta_hh_le_proc_read_proto_mode(p_dev_cb, p_data); + break; + + default: + APPL_TRACE_ERROR("Unexpected Read UUID: 0x%04x", p_data->char_id.uuid.uu.uuid16); + break; + } + +} + +/******************************************************************************* +** +** Function bta_hh_le_read_descr_cmpl +** +** Description read characteristic descriptor is completed in CONN st. +** +** Parameters: +** +*******************************************************************************/ +void bta_hh_le_read_descr_cmpl(tBTA_HH_DEV_CB *p_dev_cb, tBTA_HH_DATA *p_buf) +{ + tBTA_HH_LE_RPT *p_rpt; + tBTA_GATTC_READ * p_data = (tBTA_GATTC_READ *)p_buf; + UINT8 *pp; + + /* if a report client configuration */ + if (p_data->descr_type.uuid.uu.uuid16 == GATT_UUID_CHAR_CLIENT_CONFIG) + { + if ((p_rpt = bta_hh_le_find_report_entry(p_dev_cb, + BTA_HH_LE_SRVC_DEF, + p_data->char_id.uuid.uu.uuid16, + p_data->char_id.inst_id)) != NULL) + { + pp = p_data->p_value->unformat.p_value; + STREAM_TO_UINT16(p_rpt->client_cfg_value, pp); + + APPL_TRACE_DEBUG("Read Client Configuration: 0x%04x", p_rpt->client_cfg_value); + } + } +} + +/******************************************************************************* +** +** Function bta_hh_le_read_battery_level_descr_cmpl +** +** Description Process report reference descriptor for battery level is completed +** +** Parameters: +** +*******************************************************************************/ +void bta_hh_le_read_battery_level_descr_cmpl(tBTA_HH_DEV_CB *p_dev_cb, tBTA_GATTC_READ * p_data) +{ + tBTA_HH_LE_RPT *p_rpt; + UINT16 descr_uuid = p_data->descr_type.uuid.uu.uuid16; + + /* read report reference descriptor for battery level is completed */ + if (descr_uuid == GATT_UUID_RPT_REF_DESCR) + { + if ((p_rpt = bta_hh_le_find_report_entry(p_dev_cb, + p_data->srvc_id.id.inst_id, + GATT_UUID_BATTERY_LEVEL, + p_data->char_id.inst_id)) == NULL) + { + bta_hh_le_search_hid_chars(p_dev_cb); + } + else + bta_hh_le_save_rpt_ref(p_dev_cb, p_rpt, p_data); + } +} + +/******************************************************************************* +** +** Function bta_hh_w4_le_read_descr_cmpl +** +** Description read characteristic descriptor is completed in W4_CONN st. +** +** Parameters: +** +*******************************************************************************/ +void bta_hh_w4_le_read_descr_cmpl(tBTA_HH_DEV_CB *p_dev_cb, tBTA_HH_DATA *p_buf) +{ + tBTA_HH_LE_RPT *p_rpt; + tBTA_GATTC_READ * p_data = (tBTA_GATTC_READ *)p_buf; + UINT16 char_uuid16; + + if (p_data == NULL) + return; + + char_uuid16 = p_data->char_id.uuid.uu.uuid16; + +#if BTA_HH_DEBUG == TRUE + APPL_TRACE_DEBUG("bta_hh_w4_le_read_descr_cmpl uuid: %s(0x%04x)", + bta_hh_uuid_to_str(p_data->descr_type.uuid.uu.uuid16), + p_data->descr_type.uuid.uu.uuid16); +#endif + switch (char_uuid16) + { + case GATT_UUID_HID_REPORT: + if ((p_rpt = bta_hh_le_find_report_entry(p_dev_cb, + p_data->srvc_id.id.inst_id, + GATT_UUID_HID_REPORT, + p_data->char_id.inst_id)) == NULL) + { + bta_hh_le_search_hid_chars(p_dev_cb); + } + else + bta_hh_le_save_rpt_ref(p_dev_cb, p_rpt, p_data); + break; + + case GATT_UUID_HID_REPORT_MAP: + bta_hh_le_save_ext_rpt_ref(p_dev_cb, p_data); + break; + + case GATT_UUID_BATTERY_LEVEL: + bta_hh_le_read_battery_level_descr_cmpl(p_dev_cb, p_data); + break; + + default: + APPL_TRACE_ERROR("unknown descriptor read complete for uuid: 0x%04x", char_uuid16); + break; + } +} + +/******************************************************************************* +** +** Function bta_hh_w4_le_write_cmpl +** +** Description Write charactersitic complete event at W4_CONN st. +** +** Parameters: +** +*******************************************************************************/ +void bta_hh_w4_le_write_cmpl(tBTA_HH_DEV_CB *p_dev_cb, tBTA_HH_DATA *p_buf) +{ + tBTA_GATTC_WRITE *p_data = (tBTA_GATTC_WRITE *)p_buf; + + if (p_data == NULL) + return; + + if (p_data->char_id.uuid.uu.uuid16 == GATT_UUID_HID_PROTO_MODE) + { + p_dev_cb->status = (p_data->status == BTA_GATT_OK) ? BTA_HH_OK : BTA_HH_ERR_PROTO; + + if ((p_dev_cb->disc_active & BTA_HH_LE_DISC_HIDS) != 0) + { + bta_hh_le_search_hid_chars(p_dev_cb); + } + else + { + bta_hh_le_open_cmpl(p_dev_cb); + } + } +} + +/******************************************************************************* +** +** Function bta_hh_le_write_cmpl +** +** Description Write charactersitic complete event at CONN st. +** +** Parameters: +** +*******************************************************************************/ +void bta_hh_le_write_cmpl(tBTA_HH_DEV_CB *p_dev_cb, tBTA_HH_DATA *p_buf) +{ + tBTA_GATTC_WRITE *p_data = (tBTA_GATTC_WRITE *)p_buf; + tBTA_HH_CBDATA cback_data ; + UINT16 cb_evt = p_dev_cb->w4_evt; + + if (p_data == NULL || cb_evt == 0) + return; + +#if BTA_HH_DEBUG + APPL_TRACE_DEBUG("bta_hh_le_write_cmpl w4_evt: %d", p_dev_cb->w4_evt); +#endif + switch (p_data->char_id.uuid.uu.uuid16) + { + /* Set protocol finished */ + case GATT_UUID_HID_PROTO_MODE: + cback_data.handle = p_dev_cb->hid_handle; + if (p_data->status == BTA_GATT_OK) + { + bta_hh_le_register_input_notif(p_dev_cb, p_data->srvc_id.id.inst_id, p_dev_cb->mode, FALSE); + cback_data.status = BTA_HH_OK; + } + else + cback_data.status = BTA_HH_ERR; + p_dev_cb->w4_evt = 0; + (* bta_hh_cb.p_cback)(cb_evt, (tBTA_HH *)&cback_data); + break; + + /* Set Report finished */ + case GATT_UUID_HID_REPORT: + case GATT_UUID_HID_BT_KB_INPUT: + case GATT_UUID_HID_BT_MOUSE_INPUT: + case GATT_UUID_HID_BT_KB_OUTPUT: + cback_data.handle = p_dev_cb->hid_handle; + cback_data.status = (p_data->status == BTA_GATT_OK)? BTA_HH_OK : BTA_HH_ERR; + p_dev_cb->w4_evt = 0; + (* bta_hh_cb.p_cback)(cb_evt, (tBTA_HH *)&cback_data); + break; + + case GATT_UUID_SCAN_INT_WINDOW: + bta_hh_le_register_scpp_notif(p_dev_cb, p_data->status); + break; + + + default: + break; + } + +} + +/******************************************************************************* +** +** Function bta_hh_le_write_char_descr_cmpl +** +** Description Write charactersitic descriptor complete event +** +** Parameters: +** +*******************************************************************************/ +void bta_hh_le_write_char_descr_cmpl(tBTA_HH_DEV_CB *p_dev_cb, tBTA_HH_DATA *p_buf) +{ + tBTA_GATTC_WRITE *p_data = (tBTA_GATTC_WRITE *)p_buf; + UINT8 srvc_inst_id, hid_inst_id; + + /* only write client configuration possible */ + if (p_data->descr_type.uuid.uu.uuid16 == GATT_UUID_CHAR_CLIENT_CONFIG) + { + srvc_inst_id = p_data->srvc_id.id.inst_id; + hid_inst_id = srvc_inst_id; + switch (p_data->char_id.uuid.uu.uuid16) + { + case GATT_UUID_BATTERY_LEVEL: /* battery level clt cfg registered */ + hid_inst_id = bta_hh_le_find_service_inst_by_battery_inst_id(p_dev_cb, srvc_inst_id); + /* fall through */ + case GATT_UUID_HID_BT_KB_INPUT: + case GATT_UUID_HID_BT_MOUSE_INPUT: + case GATT_UUID_HID_REPORT: + if (p_data->status == BTA_GATT_OK) + p_dev_cb->hid_srvc[hid_inst_id].report[p_dev_cb->clt_cfg_idx].client_cfg_value = + BTA_GATT_CLT_CONFIG_NOTIFICATION; + p_dev_cb->clt_cfg_idx ++; + bta_hh_le_write_rpt_clt_cfg(p_dev_cb, hid_inst_id); + + break; + + case GATT_UUID_SCAN_REFRESH: + bta_hh_le_register_scpp_notif_cmpl(p_dev_cb, p_data->status); + break; + + default: + APPL_TRACE_ERROR("Unknown char ID clt cfg: 0x%04x", p_data->char_id.uuid.uu.uuid16); + } + } + else + { +#if BTA_HH_DEBUG == TRUE + APPL_TRACE_ERROR("Unexpected write to %s(0x%04x)", + bta_hh_uuid_to_str(p_data->descr_type.uuid.uu.uuid16), + p_data->descr_type.uuid.uu.uuid16); +#else + APPL_TRACE_ERROR("Unexpected write to (0x%04x)", + p_data->descr_type.uuid.uu.uuid16); +#endif + } + +} + +/******************************************************************************* +** +** Function bta_hh_le_input_rpt_notify +** +** Description process the notificaton event, most likely for input report. +** +** Parameters: +** +*******************************************************************************/ +void bta_hh_le_input_rpt_notify(tBTA_GATTC_NOTIFY *p_data) +{ + tBTA_HH_DEV_CB *p_dev_cb = bta_hh_le_find_dev_cb_by_conn_id(p_data->conn_id); + UINT8 app_id; + UINT8 *p_buf; + tBTA_HH_LE_RPT *p_rpt; + + if (p_dev_cb == NULL) + { + APPL_TRACE_ERROR("notification received from Unknown device"); + return; + } + app_id= p_dev_cb->app_id; + + p_rpt = bta_hh_le_find_report_entry(p_dev_cb, + BTA_HH_LE_SRVC_DEF, + p_data->char_id.char_id.uuid.uu.uuid16, + p_data->char_id.char_id.inst_id); + if (p_rpt == NULL) + { + APPL_TRACE_ERROR("notification received for Unknown Report"); + return; + } + + if (p_data->char_id.char_id.uuid.uu.uuid16 == GATT_UUID_HID_BT_MOUSE_INPUT) + app_id = BTA_HH_APP_ID_MI; + else if (p_data->char_id.char_id.uuid.uu.uuid16 == GATT_UUID_HID_BT_KB_INPUT) + app_id = BTA_HH_APP_ID_KB; + + APPL_TRACE_DEBUG("Notification received on report ID: %d", p_rpt->rpt_id); + + /* need to append report ID to the head of data */ + if (p_rpt->rpt_id != 0) + { + if ((p_buf = (UINT8 *)GKI_getbuf((UINT16)(p_data->len + 1))) == NULL) + { + APPL_TRACE_ERROR("No resources to send report data"); + return; + } + + p_buf[0] = p_rpt->rpt_id; + memcpy(&p_buf[1], p_data->value, p_data->len); + ++p_data->len; + } else { + p_buf = p_data->value; + } + + bta_hh_co_data((UINT8)p_dev_cb->hid_handle, + p_buf, + p_data->len, + p_dev_cb->mode, + 0 , /* no sub class*/ + p_dev_cb->dscp_info.ctry_code, + p_dev_cb->addr, + app_id); + + if (p_buf != p_data->value) + GKI_freebuf(p_buf); +} + +/******************************************************************************* +** +** Function bta_hh_gatt_open_fail +** +** Description action function to process the open fail +** +** Returns void +** +*******************************************************************************/ +void bta_hh_le_open_fail(tBTA_HH_DEV_CB *p_cb, tBTA_HH_DATA *p_data) +{ + tBTA_HH_CONN conn_dat ; + + /* open failure in the middle of service discovery, clear all services */ + if (p_cb->disc_active & BTA_HH_LE_DISC_HIDS) + { + bta_hh_clear_service_cache(p_cb); + } + + p_cb->disc_active = BTA_HH_LE_DISC_NONE; + /* Failure in opening connection or GATT discovery failure */ + conn_dat.handle = p_cb->hid_handle; + memcpy(conn_dat.bda, p_cb->addr, BD_ADDR_LEN); + conn_dat.le_hid = TRUE; + conn_dat.scps_supported = p_cb->scps_supported; + + if (p_cb->status == BTA_HH_OK) + conn_dat.status = (p_data->le_close.reason == BTA_GATT_CONN_UNKNOWN) ? p_cb->status : BTA_HH_ERR; + else + conn_dat.status = p_cb->status; + + /* Report OPEN fail event */ + (*bta_hh_cb.p_cback)(BTA_HH_OPEN_EVT, (tBTA_HH *)&conn_dat); + +} + +/******************************************************************************* +** +** Function bta_hh_gatt_close +** +** Description action function to process the GATT close int he state machine. +** +** Returns void +** +*******************************************************************************/ +void bta_hh_gatt_close(tBTA_HH_DEV_CB *p_cb, tBTA_HH_DATA *p_data) +{ + tBTA_HH_CBDATA disc_dat = {BTA_HH_OK, 0}; + + /* finaliza device driver */ + bta_hh_co_close(p_cb->hid_handle, p_cb->app_id); + /* update total conn number */ + bta_hh_cb.cnt_num --; + + disc_dat.handle = p_cb->hid_handle; + disc_dat.status = p_cb->status; + + (*bta_hh_cb.p_cback)(BTA_HH_CLOSE_EVT, (tBTA_HH *)&disc_dat); + + /* if no connection is active and HH disable is signaled, disable service */ + if (bta_hh_cb.cnt_num == 0 && bta_hh_cb.w4_disable) + { + bta_hh_disc_cmpl(); + } + else + { +#if (BTA_HH_LE_RECONN == TRUE) + if (p_data->le_close.reason == BTA_GATT_CONN_TIMEOUT) + { + bta_hh_le_add_dev_bg_conn(p_cb, FALSE); + } +#endif + } + + return; + +} + +/******************************************************************************* +** +** Function bta_hh_le_api_disc_act +** +** Description initaite a Close API to a remote HID device +** +** Returns void +** +*******************************************************************************/ +void bta_hh_le_api_disc_act(tBTA_HH_DEV_CB *p_cb) +{ + if (p_cb->conn_id != BTA_GATT_INVALID_CONN_ID) + { + BTA_GATTC_Close(p_cb->conn_id); + /* remove device from background connection if intended to disconnect, + do not allow reconnection */ + bta_hh_le_remove_dev_bg_conn(p_cb); + } +} + +/******************************************************************************* +** +** Function bta_hh_le_get_rpt +** +** Description GET_REPORT on a LE HID Report +** +** Returns void +** +*******************************************************************************/ +void bta_hh_le_get_rpt(tBTA_HH_DEV_CB *p_cb, UINT8 srvc_inst, tBTA_HH_RPT_TYPE r_type, UINT8 rpt_id) +{ + tBTA_HH_LE_RPT *p_rpt = bta_hh_le_find_rpt_by_idtype(p_cb->hid_srvc[srvc_inst].report, p_cb->mode, r_type, rpt_id); + tBTA_GATTC_CHAR_ID char_id; + UINT16 srvc_uuid = UUID_SERVCLASS_LE_HID; + + if (p_rpt == NULL) + { + APPL_TRACE_ERROR("bta_hh_le_get_rpt: no matching report"); + return; + } + if (p_rpt->uuid == GATT_UUID_BATTERY_LEVEL) + srvc_uuid = UUID_SERVCLASS_BATTERY; + + p_cb->w4_evt = BTA_HH_GET_RPT_EVT; + + bta_hh_le_fill_16bits_srvc_id(TRUE, srvc_inst, srvc_uuid, &char_id.srvc_id); + bta_hh_le_fill_16bits_char_id(p_rpt->inst_id, p_rpt->uuid, &char_id.char_id); + + BTA_GATTC_ReadCharacteristic(p_cb->conn_id, + &char_id, + BTA_GATT_AUTH_REQ_NONE); +} + +/******************************************************************************* +** +** Function bta_hh_le_write_rpt +** +** Description SET_REPORT/or DATA output on a LE HID Report +** +** Returns void +** +*******************************************************************************/ +void bta_hh_le_write_rpt(tBTA_HH_DEV_CB *p_cb, UINT8 srvc_inst, + tBTA_GATTC_WRITE_TYPE write_type, + tBTA_HH_RPT_TYPE r_type, + BT_HDR *p_buf, UINT16 w4_evt ) +{ + tBTA_HH_LE_RPT *p_rpt; + tBTA_GATTC_CHAR_ID char_id; + UINT8 *p_value, rpt_id; + + if (p_buf == NULL || p_buf->len == 0) + { + APPL_TRACE_ERROR("bta_hh_le_write_rpt: Illegal data"); + return; + } + + /* strip report ID from the data */ + p_value = (UINT8 *)(p_buf + 1) + p_buf->offset; + STREAM_TO_UINT8(rpt_id, p_value); + p_buf->len -= 1; + + p_rpt = bta_hh_le_find_rpt_by_idtype(p_cb->hid_srvc[srvc_inst].report, p_cb->mode, r_type, rpt_id); + + if (p_rpt == NULL) + { + APPL_TRACE_ERROR("bta_hh_le_write_rpt: no matching report"); + GKI_freebuf(p_buf); + return; + } + + APPL_TRACE_ERROR("bta_hh_le_write_rpt: ReportID: 0x%02x Data Len: %d", rpt_id, p_buf->len); + + p_cb->w4_evt = w4_evt; + + bta_hh_le_fill_16bits_srvc_id(TRUE, srvc_inst, UUID_SERVCLASS_LE_HID, &char_id.srvc_id); + bta_hh_le_fill_16bits_char_id(p_rpt->inst_id, p_rpt->uuid, &char_id.char_id); + + BTA_GATTC_WriteCharValue(p_cb->conn_id, + &char_id, + write_type, /* default to use write request */ + p_buf->len, + p_value, + BTA_GATT_AUTH_REQ_NONE); + +} + +/******************************************************************************* +** +** Function bta_hh_le_suspend +** +** Description send LE suspend or exit suspend mode to remote device. +** +** Returns void +** +*******************************************************************************/ +void bta_hh_le_suspend(tBTA_HH_DEV_CB *p_cb, tBTA_HH_TRANS_CTRL_TYPE ctrl_type) +{ + UINT8 i; + tBTA_GATTC_CHAR_ID char_id; + + ctrl_type -= BTA_HH_CTRL_SUSPEND; + + for (i = 0; i < BTA_HH_LE_HID_SRVC_MAX; i ++) + { + bta_hh_le_fill_16bits_srvc_id(TRUE, i, UUID_SERVCLASS_LE_HID, &char_id.srvc_id); + bta_hh_le_fill_16bits_char_id(0, GATT_UUID_HID_CONTROL_POINT, &char_id.char_id); + + BTA_GATTC_WriteCharValue(p_cb->conn_id, + &char_id, + BTA_GATTC_TYPE_WRITE_NO_RSP, /* default to use write request */ + 1, + &ctrl_type, + BTA_GATT_AUTH_REQ_NONE); + } +} + +/******************************************************************************* +** +** Function bta_hh_le_write_dev_act +** +** Description Write LE device action. can be SET/GET/DATA transaction. +** +** Returns void +** +*******************************************************************************/ +void bta_hh_le_write_dev_act(tBTA_HH_DEV_CB *p_cb, tBTA_HH_DATA *p_data) +{ + switch(p_data->api_sndcmd.t_type) + { + case HID_TRANS_SET_PROTOCOL: + p_cb->w4_evt = BTA_HH_SET_PROTO_EVT; + bta_hh_le_set_protocol_mode(p_cb, p_data->api_sndcmd.param); + break; + + case HID_TRANS_GET_PROTOCOL: + bta_hh_le_get_protocol_mode(p_cb); + break; + + case HID_TRANS_GET_REPORT: + bta_hh_le_get_rpt(p_cb, + BTA_HH_LE_SRVC_DEF, + p_data->api_sndcmd.param, + p_data->api_sndcmd.rpt_id); + break; + + case HID_TRANS_SET_REPORT: + bta_hh_le_write_rpt(p_cb, + BTA_HH_LE_SRVC_DEF, + BTA_GATTC_TYPE_WRITE, + p_data->api_sndcmd.param, + p_data->api_sndcmd.p_data, + BTA_HH_SET_RPT_EVT); + break; + + case HID_TRANS_DATA: /* output report */ + + bta_hh_le_write_rpt(p_cb, + BTA_HH_LE_SRVC_DEF, + BTA_GATTC_TYPE_WRITE_NO_RSP, + p_data->api_sndcmd.param, + p_data->api_sndcmd.p_data, + BTA_HH_DATA_EVT); + break; + + case HID_TRANS_CONTROL: + /* no handshake event will be generated */ + /* if VC_UNPLUG is issued, set flag */ + if (p_data->api_sndcmd.param == BTA_HH_CTRL_SUSPEND || + p_data->api_sndcmd.param == BTA_HH_CTRL_EXIT_SUSPEND) + { + bta_hh_le_suspend(p_cb, p_data->api_sndcmd.param); + } + break; + + default: + APPL_TRACE_ERROR("%s unsupported transaction for BLE HID device: %d", + __func__, p_data->api_sndcmd.t_type); + break; + } +} + +/******************************************************************************* +** +** Function bta_hh_le_get_dscp_act +** +** Description Send ReportDescriptor to application for all HID services. +** +** Returns void +** +*******************************************************************************/ +void bta_hh_le_get_dscp_act(tBTA_HH_DEV_CB *p_cb) +{ + UINT8 i; + + for (i = 0 ;i < BTA_HH_LE_HID_SRVC_MAX; i ++) + { + if (p_cb->hid_srvc[i].in_use) + { + p_cb->dscp_info.descriptor.dl_len = p_cb->hid_srvc[i].descriptor.dl_len; + p_cb->dscp_info.descriptor.dsc_list = p_cb->hid_srvc[i].descriptor.dsc_list; + + (*bta_hh_cb.p_cback)(BTA_HH_GET_DSCP_EVT, (tBTA_HH *)&p_cb->dscp_info); + } + else + break; + } +} + +/******************************************************************************* +** +** Function bta_hh_le_add_dev_bg_conn +** +** Description Remove a LE HID device from back ground connection procedure. +** +** Returns void +** +*******************************************************************************/ +static void bta_hh_le_add_dev_bg_conn(tBTA_HH_DEV_CB *p_cb, BOOLEAN check_bond) +{ + UINT8 sec_flag=0; + BOOLEAN to_add = TRUE; + + if (check_bond) + { + /* start reconnection if remote is a bonded device */ + /* verify bond */ + BTM_GetSecurityFlagsByTransport(p_cb->addr, &sec_flag, BT_TRANSPORT_LE); + + if ((sec_flag & BTM_SEC_FLAG_LKEY_KNOWN) == 0) + to_add = FALSE; + } + + if (/*p_cb->dscp_info.flag & BTA_HH_LE_NORMAL_CONN &&*/ + !p_cb->in_bg_conn && to_add) + { + /* add device into BG connection to accept remote initiated connection */ + BTA_GATTC_Open(bta_hh_cb.gatt_if, p_cb->addr, FALSE, BTA_GATT_TRANSPORT_LE); + p_cb->in_bg_conn = TRUE; + + BTA_DmBleSetBgConnType(BTA_DM_BLE_CONN_AUTO, NULL); + } + return; +} + +/******************************************************************************* +** +** Function bta_hh_le_add_device +** +** Description Add a LE HID device as a known device, and also add the address +** into back ground connection WL for incoming connection. +** +** Returns void +** +*******************************************************************************/ +UINT8 bta_hh_le_add_device(tBTA_HH_DEV_CB *p_cb, tBTA_HH_MAINT_DEV *p_dev_info) +{ + p_cb->hid_handle = BTA_HH_GET_LE_DEV_HDL(p_cb->index); + bta_hh_cb.le_cb_index[BTA_HH_GET_LE_CB_IDX(p_cb->hid_handle)] = p_cb->index; + + /* update DI information */ + bta_hh_update_di_info(p_cb, + p_dev_info->dscp_info.vendor_id, + p_dev_info->dscp_info.product_id, + p_dev_info->dscp_info.version, + p_dev_info->dscp_info.flag); + + /* add to BTA device list */ + bta_hh_add_device_to_list(p_cb, p_cb->hid_handle, + p_dev_info->attr_mask, + &p_dev_info->dscp_info.descriptor, + p_dev_info->sub_class, + p_dev_info->dscp_info.ssr_max_latency, + p_dev_info->dscp_info.ssr_min_tout, + p_dev_info->app_id); + + bta_hh_le_add_dev_bg_conn(p_cb, FALSE); + + return p_cb->hid_handle; +} + +/******************************************************************************* +** +** Function bta_hh_le_remove_dev_bg_conn +** +** Description Remove a LE HID device from back ground connection procedure. +** +** Returns void +** +*******************************************************************************/ +void bta_hh_le_remove_dev_bg_conn(tBTA_HH_DEV_CB *p_dev_cb) +{ + if (p_dev_cb->in_bg_conn) + { + p_dev_cb->in_bg_conn = FALSE; + + BTA_GATTC_CancelOpen(bta_hh_cb.gatt_if, p_dev_cb->addr, FALSE); + } +} + +/******************************************************************************* +** +** Function bta_hh_le_update_scpp +** +** Description action function to update the scan parameters on remote HID +** device +** +** Parameters: +** +*******************************************************************************/ +void bta_hh_le_update_scpp(tBTA_HH_DEV_CB *p_dev_cb, tBTA_HH_DATA *p_buf) +{ + tBTA_GATTC_CHAR_ID char_id; + UINT8 value[4], *p = value; + tBTA_HH_CBDATA cback_data ; + + if (!p_dev_cb->is_le_device || + p_dev_cb->mode != BTA_HH_PROTO_RPT_MODE || + p_dev_cb->scps_supported == FALSE) + { + APPL_TRACE_ERROR("Can not set ScPP scan paramter as boot host, or remote does not support ScPP "); + + cback_data.handle = p_dev_cb->hid_handle; + cback_data.status = BTA_HH_ERR; + (* bta_hh_cb.p_cback)(BTA_HH_UPDATE_SCPP_EVT, (tBTA_HH *)&cback_data); + + return; + } + + p_dev_cb->w4_evt = BTA_HH_UPDATE_SCPP_EVT; + + UINT16_TO_STREAM(p, p_buf->le_scpp_update.scan_int); + UINT16_TO_STREAM(p, p_buf->le_scpp_update.scan_win); + + bta_hh_le_fill_16bits_srvc_id(TRUE, BTA_HH_SCPP_INST_DEF, UUID_SERVCLASS_SCAN_PARAM, &char_id.srvc_id); + bta_hh_le_fill_16bits_char_id(BTA_HH_SCPP_INST_DEF, GATT_UUID_SCAN_INT_WINDOW, &char_id.char_id); + + BTA_GATTC_WriteCharValue(p_dev_cb->conn_id, + &char_id, + BTA_GATTC_TYPE_WRITE_NO_RSP, + 2, + value, + BTA_GATT_AUTH_REQ_NONE); + +} + +/******************************************************************************* +** +** Function bta_hh_gattc_callback +** +** Description This is GATT client callback function used in BTA HH. +** +** Parameters: +** +*******************************************************************************/ +static void bta_hh_gattc_callback(tBTA_GATTC_EVT event, tBTA_GATTC *p_data) +{ + tBTA_HH_DEV_CB *p_dev_cb; + UINT16 evt; +#if BTA_HH_DEBUG + APPL_TRACE_DEBUG("bta_hh_gattc_callback event = %d", event); +#endif + if (p_data == NULL) + return; + + switch (event) + { + case BTA_GATTC_REG_EVT: /* 0 */ + bta_hh_le_register_cmpl(&p_data->reg_oper); + break; + + case BTA_GATTC_DEREG_EVT: /* 1 */ + bta_hh_cleanup_disable(p_data->reg_oper.status); + break; + + case BTA_GATTC_OPEN_EVT: /* 2 */ + p_dev_cb = bta_hh_le_find_dev_cb_by_bda(p_data->open.remote_bda); + if (p_dev_cb) { + bta_hh_sm_execute(p_dev_cb, BTA_HH_GATT_OPEN_EVT, (tBTA_HH_DATA *)&p_data->open); + } + break; + + case BTA_GATTC_READ_CHAR_EVT: /* 3 */ + case BTA_GATTC_READ_DESCR_EVT: /* 8 */ + p_dev_cb = bta_hh_le_find_dev_cb_by_conn_id(p_data->read.conn_id); + if (event == BTA_GATTC_READ_CHAR_EVT) + evt = BTA_HH_GATT_READ_CHAR_CMPL_EVT; + else + evt = BTA_HH_GATT_READ_DESCR_CMPL_EVT; + + bta_hh_sm_execute(p_dev_cb, evt, (tBTA_HH_DATA *)&p_data->read); + break; + + case BTA_GATTC_WRITE_DESCR_EVT: /* 9 */ + case BTA_GATTC_WRITE_CHAR_EVT: /* 4 */ + p_dev_cb = bta_hh_le_find_dev_cb_by_conn_id(p_data->write.conn_id); + if (event == BTA_GATTC_WRITE_CHAR_EVT) + evt = BTA_HH_GATT_WRITE_CHAR_CMPL_EVT; + else + evt = BTA_HH_GATT_WRITE_DESCR_CMPL_EVT; + + bta_hh_sm_execute(p_dev_cb, evt, (tBTA_HH_DATA *)&p_data->write); + break; + + case BTA_GATTC_CLOSE_EVT: /* 5 */ + bta_hh_le_close(&p_data->close); + break; + + case BTA_GATTC_SEARCH_CMPL_EVT: /* 6 */ + bta_hh_le_srvc_search_cmpl(&p_data->search_cmpl); + break; + + case BTA_GATTC_SEARCH_RES_EVT: /* 7 */ + bta_hh_le_search_result(&p_data->srvc_res); + break; + + + + case BTA_GATTC_NOTIF_EVT: /* 10 */ + bta_hh_le_input_rpt_notify(&p_data->notify); + break; + + case BTA_GATTC_ENC_CMPL_CB_EVT: /* 17 */ + p_dev_cb = bta_hh_le_find_dev_cb_by_bda(p_data->enc_cmpl.remote_bda); + if (p_dev_cb) { + bta_hh_sm_execute(p_dev_cb, BTA_HH_GATT_ENC_CMPL_EVT, + (tBTA_HH_DATA *)&p_data->enc_cmpl); + } + break; + + default: + break; + } +} + +/******************************************************************************* +** +** Function bta_hh_le_hid_read_rpt_clt_cfg +** +** Description a test command to read report descriptor client configuration +** +** Returns void +** +*******************************************************************************/ +void bta_hh_le_hid_read_rpt_clt_cfg(BD_ADDR bd_addr, UINT8 rpt_id) +{ + tBTA_HH_DEV_CB *p_cb = NULL; + tBTA_HH_LE_RPT *p_rpt ; + UINT8 index = BTA_HH_IDX_INVALID; + + index = bta_hh_find_cb(bd_addr); + if ((index = bta_hh_find_cb(bd_addr))== BTA_HH_IDX_INVALID) + { + APPL_TRACE_ERROR("unknown device"); + return; + } + + p_cb = &bta_hh_cb.kdev[index]; + + p_rpt = bta_hh_le_find_rpt_by_idtype(p_cb->hid_srvc[BTA_HH_LE_SRVC_DEF].report, p_cb->mode, BTA_HH_RPTT_INPUT, rpt_id); + + if (p_rpt == NULL) + { + APPL_TRACE_ERROR("bta_hh_le_write_rpt: no matching report"); + return; + } + + bta_hh_le_read_char_dscrpt(p_cb, + UUID_SERVCLASS_LE_HID, + BTA_HH_LE_SRVC_DEF, + p_rpt->uuid, + p_rpt->inst_id, + GATT_UUID_CHAR_CLIENT_CONFIG); + + + + return; +} + +/******************************************************************************* +** +** Function bta_hh_le_search_scps +** +** Description discovery scan parameter service if act as report host, otherwise +** finish LE connection. +** +** Parameters: +** +*******************************************************************************/ +static void bta_hh_le_search_scps(tBTA_HH_DEV_CB *p_cb) +{ + tBT_UUID pri_srvc; + + if ( p_cb->mode == BTA_HH_PROTO_RPT_MODE) + { + p_cb->disc_active |= BTA_HH_LE_DISC_SCPS; + /* start service discovery for Scan Parameter service */ + pri_srvc.len = LEN_UUID_16; + pri_srvc.uu.uuid16 = UUID_SERVCLASS_SCAN_PARAM; + + BTA_GATTC_ServiceSearchRequest(p_cb->conn_id, &pri_srvc); + } + else + bta_hh_le_open_cmpl(p_cb); +} + +/******************************************************************************* +** +** Function bta_hh_le_search_scps_chars +** +** Description find ScPS optional characteristics scan refresh +** +** Parameters: +** +*******************************************************************************/ +static void bta_hh_le_search_scps_chars(tBTA_HH_DEV_CB *p_cb) +{ + tBTA_GATT_SRVC_ID srvc_id; + tBT_UUID char_cond; + tBTA_GATTC_CHAR_ID char_result; + tBTA_GATT_CHAR_PROP prop; + + p_cb->scps_supported = TRUE; + bta_hh_le_fill_16bits_srvc_id(TRUE, 0, UUID_SERVCLASS_SCAN_PARAM, &srvc_id); + + char_cond.len = LEN_UUID_16; + char_cond.uu.uuid16 = GATT_UUID_SCAN_REFRESH; + + /* look for scan refresh */ + if (BTA_GATTC_GetFirstChar( p_cb->conn_id, + &srvc_id, + &char_cond, + &char_result, + &prop) == BTA_GATT_OK) + { + if (prop & BTA_GATT_CHAR_PROP_BIT_NOTIFY) + p_cb->scps_notify |= BTA_HH_LE_SCPS_NOTIFY_SPT; + else + p_cb->scps_notify = BTA_HH_LE_SCPS_NOTIFY_NONE; + + } +} + +/******************************************************************************* +** +** Function bta_hh_le_register_scpp_notif +** +** Description register scan parameter refresh notitication complete +** +** +** Parameters: +** +*******************************************************************************/ +static void bta_hh_le_register_scpp_notif(tBTA_HH_DEV_CB *p_dev_cb, tBTA_GATT_STATUS status) +{ + UINT8 sec_flag=0; + tBTA_GATTC_CHAR_ID char_id; + + /* if write scan parameter sucessful */ + /* if bonded and notification is not enabled, configure the client configuration */ + if (status == BTA_GATT_OK && + (p_dev_cb->scps_notify & BTA_HH_LE_SCPS_NOTIFY_SPT) != 0 && + (p_dev_cb->scps_notify & BTA_HH_LE_SCPS_NOTIFY_ENB) == 0) + { + BTM_GetSecurityFlagsByTransport(p_dev_cb->addr, &sec_flag, BT_TRANSPORT_LE); + if ((sec_flag & BTM_SEC_FLAG_LKEY_KNOWN)) + { + if (bta_hh_le_write_char_clt_cfg (p_dev_cb, + BTA_HH_SCPP_INST_DEF, + UUID_SERVCLASS_SCAN_PARAM, + BTA_HH_SCPP_INST_DEF, + GATT_UUID_SCAN_REFRESH, + BTA_GATT_CLT_CONFIG_NOTIFICATION)) + { + bta_hh_le_fill_16bits_srvc_id(TRUE, BTA_HH_SCPP_INST_DEF, UUID_SERVCLASS_SCAN_PARAM, &char_id.srvc_id); + bta_hh_le_fill_16bits_char_id(BTA_HH_SCPP_INST_DEF, GATT_UUID_SCAN_REFRESH, &char_id.char_id); + + BTA_GATTC_RegisterForNotifications(bta_hh_cb.gatt_if, + p_dev_cb->addr, + &char_id); + return; + } + } + } + bta_hh_le_register_scpp_notif_cmpl(p_dev_cb, status); +} + +/******************************************************************************* +** +** Function bta_hh_le_register_scpp_notif_cmpl +** +** Description action function to register scan parameter refresh notitication +** +** Parameters: +** +*******************************************************************************/ +static void bta_hh_le_register_scpp_notif_cmpl(tBTA_HH_DEV_CB *p_dev_cb, tBTA_GATT_STATUS status) +{ + tBTA_HH_CBDATA cback_data ; + UINT16 cb_evt = p_dev_cb->w4_evt; + + if (status == BTA_GATT_OK) + p_dev_cb->scps_notify = (BTA_HH_LE_SCPS_NOTIFY_ENB | BTA_HH_LE_SCPS_NOTIFY_SPT); + + cback_data.handle = p_dev_cb->hid_handle; + cback_data.status = (status == BTA_GATT_OK)? BTA_HH_OK : BTA_HH_ERR; + p_dev_cb->w4_evt = 0; + (* bta_hh_cb.p_cback)(cb_evt, (tBTA_HH *)&cback_data); + + +} + +/******************************************************************************* +** +** Function bta_hh_process_cache_rpt +** +** Description Process the cached reports +** +** Parameters: +** +*******************************************************************************/ +static void bta_hh_process_cache_rpt (tBTA_HH_DEV_CB *p_cb, + tBTA_HH_RPT_CACHE_ENTRY *p_rpt_cache, + UINT8 num_rpt) +{ + UINT8 i = 0; + tBTA_HH_LE_RPT *p_rpt; + + if (num_rpt != 0) /* no cache is found */ + { + p_cb->hid_srvc[BTA_HH_LE_RPT_GET_SRVC_INST_ID(p_rpt_cache->inst_id)].in_use = TRUE; + + /* set the descriptor info */ + p_cb->hid_srvc[BTA_HH_LE_RPT_GET_SRVC_INST_ID(p_rpt_cache->inst_id)].descriptor.dl_len = + p_cb->dscp_info.descriptor.dl_len; + p_cb->hid_srvc[BTA_HH_LE_RPT_GET_SRVC_INST_ID(p_rpt_cache->inst_id)].descriptor.dsc_list = + p_cb->dscp_info.descriptor.dsc_list; + + for (; i inst_id), + p_rpt_cache->rpt_uuid, + BTA_HH_LE_RPT_GET_RPT_INST_ID(p_rpt_cache->inst_id), + p_rpt_cache->prop)) == NULL) + { + APPL_TRACE_ERROR("bta_hh_process_cache_rpt: allocation report entry failure"); + break; + } + else + { + p_rpt->rpt_type = p_rpt_cache->rpt_type; + p_rpt->rpt_id = p_rpt_cache->rpt_id; + + if(p_rpt->uuid == GATT_UUID_HID_BT_KB_INPUT || + p_rpt->uuid == GATT_UUID_HID_BT_MOUSE_INPUT || + (p_rpt->uuid == GATT_UUID_HID_REPORT && p_rpt->rpt_type == BTA_HH_RPTT_INPUT)) + { + p_rpt->client_cfg_value = BTA_GATT_CLT_CONFIG_NOTIFICATION; + } + } + } + } +} + +#endif + + + + diff --git a/components/bt/bluedroid/bta/hh/bta_hh_main.c b/components/bt/bluedroid/bta/hh/bta_hh_main.c new file mode 100644 index 0000000000..e5c353d624 --- /dev/null +++ b/components/bt/bluedroid/bta/hh/bta_hh_main.c @@ -0,0 +1,593 @@ +/****************************************************************************** + * + * Copyright (C) 2005-2012 Broadcom Corporation + * + * 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 HID host main functions and state machine. + * + ******************************************************************************/ + +#include "bt_target.h" + +#if defined(BTA_HH_INCLUDED) && (BTA_HH_INCLUDED == TRUE) + +#include + +#include "bta_hh_api.h" +#include "bta_hh_int.h" +#include "gki.h" + +/***************************************************************************** +** Constants and types +*****************************************************************************/ + +/* state machine action enumeration list */ +enum +{ + BTA_HH_API_DISC_ACT, /* HID host process API close action */ + BTA_HH_OPEN_ACT, /* HID host process BTA_HH_EVT_OPEN */ + BTA_HH_CLOSE_ACT, /* HID host process BTA_HH_EVT_CLOSE */ + BTA_HH_DATA_ACT, /* HID host receive data report */ + BTA_HH_CTRL_DAT_ACT, + BTA_HH_HANDSK_ACT, + BTA_HH_START_SDP, /* HID host inquery */ + BTA_HH_SDP_CMPL, + BTA_HH_WRITE_DEV_ACT, + BTA_HH_GET_DSCP_ACT, + BTA_HH_MAINT_DEV_ACT, + BTA_HH_OPEN_CMPL_ACT, + BTA_HH_OPEN_FAILURE, +#if (defined BTA_HH_LE_INCLUDED && BTA_HH_LE_INCLUDED == TRUE) + BTA_HH_GATT_CLOSE, + BTA_HH_LE_OPEN_FAIL, + BTA_HH_GATT_OPEN, + BTA_HH_W4_LE_READ_CHAR, + BTA_HH_LE_READ_CHAR, + BTA_HH_W4_LE_READ_DESCR, + BTA_HH_LE_READ_DESCR, + BTA_HH_W4_LE_WRITE, + BTA_HH_LE_WRITE, + BTA_HH_WRITE_DESCR, + BTA_HH_START_SEC, + BTA_HH_SEC_CMPL, + BTA_HH_LE_UPDATE_SCPP, + BTA_HH_GATT_ENC_CMPL, +#endif + BTA_HH_NUM_ACTIONS +}; + +#define BTA_HH_IGNORE BTA_HH_NUM_ACTIONS + +/* type for action functions */ +typedef void (*tBTA_HH_ACTION)(tBTA_HH_DEV_CB *p_cb, tBTA_HH_DATA *p_data); + +/* action functions */ +const tBTA_HH_ACTION bta_hh_action[] = +{ + bta_hh_api_disc_act, + bta_hh_open_act, + bta_hh_close_act, + bta_hh_data_act, + bta_hh_ctrl_dat_act, + bta_hh_handsk_act, + bta_hh_start_sdp, + bta_hh_sdp_cmpl, + bta_hh_write_dev_act, + bta_hh_get_dscp_act, + bta_hh_maint_dev_act, + bta_hh_open_cmpl_act, + bta_hh_open_failure +#if (defined BTA_HH_LE_INCLUDED && BTA_HH_LE_INCLUDED == TRUE) + ,bta_hh_gatt_close + ,bta_hh_le_open_fail + ,bta_hh_gatt_open + ,bta_hh_w4_le_read_char_cmpl + ,bta_hh_le_read_char_cmpl + ,bta_hh_w4_le_read_descr_cmpl + ,bta_hh_le_read_descr_cmpl + ,bta_hh_w4_le_write_cmpl + ,bta_hh_le_write_cmpl + ,bta_hh_le_write_char_descr_cmpl + ,bta_hh_start_security + ,bta_hh_security_cmpl + ,bta_hh_le_update_scpp + ,bta_hh_le_notify_enc_cmpl +#endif +}; + +/* state table information */ +#define BTA_HH_ACTION 0 /* position of action */ +#define BTA_HH_NEXT_STATE 1 /* position of next state */ +#define BTA_HH_NUM_COLS 2 /* number of columns */ + +/* state table for idle state */ +const UINT8 bta_hh_st_idle[][BTA_HH_NUM_COLS] = +{ +/* Event Action Next state */ +/* BTA_HH_API_OPEN_EVT */ {BTA_HH_START_SDP, BTA_HH_W4_CONN_ST }, +/* BTA_HH_API_CLOSE_EVT */ {BTA_HH_IGNORE, BTA_HH_IDLE_ST }, +/* BTA_HH_INT_OPEN_EVT */ {BTA_HH_OPEN_ACT, BTA_HH_W4_CONN_ST }, +/* BTA_HH_INT_CLOSE_EVT */ {BTA_HH_CLOSE_ACT, BTA_HH_IDLE_ST }, +/* BTA_HH_INT_DATA_EVT */ {BTA_HH_IGNORE, BTA_HH_IDLE_ST }, +/* BTA_HH_INT_CTRL_DATA */ {BTA_HH_IGNORE, BTA_HH_IDLE_ST }, +/* BTA_HH_INT_HANDSK_EVT */ {BTA_HH_IGNORE, BTA_HH_IDLE_ST }, +/* BTA_HH_SDP_CMPL_EVT */ {BTA_HH_IGNORE, BTA_HH_IDLE_ST }, +/* BTA_HH_API_WRITE_DEV_EVT */ {BTA_HH_IGNORE, BTA_HH_IDLE_ST }, +/* BTA_HH_API_GET_DSCP_EVT */ {BTA_HH_IGNORE, BTA_HH_IDLE_ST }, +/* BTA_HH_API_MAINT_DEV_EVT */ {BTA_HH_MAINT_DEV_ACT, BTA_HH_IDLE_ST }, +/* BTA_HH_OPEN_CMPL_EVT */ {BTA_HH_OPEN_CMPL_ACT, BTA_HH_CONN_ST } +#if (defined BTA_HH_LE_INCLUDED && BTA_HH_LE_INCLUDED == TRUE) +/* BTA_HH_GATT_CLOSE_EVT */ ,{BTA_HH_IGNORE, BTA_HH_IDLE_ST } +/* BTA_HH_GATT_OPEN_EVT */ ,{BTA_HH_GATT_OPEN, BTA_HH_W4_CONN_ST } +/* BTA_HH_START_ENC_EVT */ ,{BTA_HH_IGNORE, BTA_HH_IDLE_ST } +/* BTA_HH_ENC_CMPL_EVT */ ,{BTA_HH_IGNORE, BTA_HH_IDLE_ST } +/* READ_CHAR_CMPL_EVT */ ,{BTA_HH_IGNORE, BTA_HH_IDLE_ST } +/* BTA_HH_GATT_WRITE_CMPL_EVT*/ ,{BTA_HH_IGNORE, BTA_HH_IDLE_ST } +/* READ_DESCR_CMPL_EVT */ ,{BTA_HH_IGNORE, BTA_HH_IDLE_ST } +/* WRITE_DESCR_CMPL_EVT */ ,{BTA_HH_IGNORE, BTA_HH_IDLE_ST } +/* SCPP_UPDATE_EVT */ ,{BTA_HH_IGNORE, BTA_HH_IDLE_ST } +/* BTA_HH_GATT_ENC_CMPL_EVT */ ,{BTA_HH_IGNORE, BTA_HH_IDLE_ST } +#endif + +}; + + +const UINT8 bta_hh_st_w4_conn[][BTA_HH_NUM_COLS] = +{ +/* Event Action Next state */ +/* BTA_HH_API_OPEN_EVT */ {BTA_HH_IGNORE, BTA_HH_W4_CONN_ST }, +/* BTA_HH_API_CLOSE_EVT */ {BTA_HH_IGNORE, BTA_HH_IDLE_ST }, +/* BTA_HH_INT_OPEN_EVT */ {BTA_HH_OPEN_ACT, BTA_HH_W4_CONN_ST }, +/* BTA_HH_INT_CLOSE_EVT */ {BTA_HH_OPEN_FAILURE, BTA_HH_IDLE_ST }, +/* BTA_HH_INT_DATA_EVT */ {BTA_HH_IGNORE, BTA_HH_W4_CONN_ST }, +/* BTA_HH_INT_CTRL_DATA */ {BTA_HH_IGNORE, BTA_HH_W4_CONN_ST }, +/* BTA_HH_INT_HANDSK_EVT */ {BTA_HH_IGNORE, BTA_HH_W4_CONN_ST }, +/* BTA_HH_SDP_CMPL_EVT */ {BTA_HH_SDP_CMPL, BTA_HH_W4_CONN_ST }, +/* BTA_HH_API_WRITE_DEV_EVT */ {BTA_HH_WRITE_DEV_ACT, BTA_HH_W4_CONN_ST }, +/* BTA_HH_API_GET_DSCP_EVT */ {BTA_HH_IGNORE, BTA_HH_W4_CONN_ST }, +/* BTA_HH_API_MAINT_DEV_EVT */ {BTA_HH_MAINT_DEV_ACT, BTA_HH_IDLE_ST }, +/* BTA_HH_OPEN_CMPL_EVT */ {BTA_HH_OPEN_CMPL_ACT, BTA_HH_CONN_ST } +#if (defined BTA_HH_LE_INCLUDED && BTA_HH_LE_INCLUDED == TRUE) +/* BTA_HH_GATT_CLOSE_EVT */ ,{BTA_HH_LE_OPEN_FAIL, BTA_HH_IDLE_ST } +/* BTA_HH_GATT_OPEN_EVT */ ,{BTA_HH_GATT_OPEN, BTA_HH_W4_CONN_ST } +/* BTA_HH_START_ENC_EVT */ ,{BTA_HH_START_SEC, BTA_HH_W4_SEC } +/* BTA_HH_ENC_CMPL_EVT */ ,{BTA_HH_IGNORE, BTA_HH_W4_CONN_ST } +/* READ_CHAR_CMPL_EVT */ ,{BTA_HH_W4_LE_READ_CHAR, BTA_HH_W4_CONN_ST } +/* BTA_HH_GATT_WRITE_CMPL_EVT*/ ,{BTA_HH_W4_LE_WRITE, BTA_HH_W4_CONN_ST } +/* READ_DESCR_CMPL_EVT */ ,{BTA_HH_W4_LE_READ_DESCR, BTA_HH_W4_CONN_ST } +/* WRITE_DESCR_CMPL_EVT */ ,{BTA_HH_WRITE_DESCR, BTA_HH_W4_CONN_ST } +/* SCPP_UPDATE_EVT */ ,{BTA_HH_IGNORE, BTA_HH_W4_CONN_ST } +/* BTA_HH_GATT_ENC_CMPL_EVT */ ,{BTA_HH_IGNORE, BTA_HH_W4_CONN_ST } +#endif +}; + + +const UINT8 bta_hh_st_connected[][BTA_HH_NUM_COLS] = +{ +/* Event Action Next state */ +/* BTA_HH_API_OPEN_EVT */ {BTA_HH_IGNORE, BTA_HH_CONN_ST }, +/* BTA_HH_API_CLOSE_EVT */ {BTA_HH_API_DISC_ACT, BTA_HH_CONN_ST }, +/* BTA_HH_INT_OPEN_EVT */ {BTA_HH_OPEN_ACT, BTA_HH_CONN_ST }, +/* BTA_HH_INT_CLOSE_EVT */ {BTA_HH_CLOSE_ACT, BTA_HH_IDLE_ST }, +/* BTA_HH_INT_DATA_EVT */ {BTA_HH_DATA_ACT, BTA_HH_CONN_ST }, +/* BTA_HH_INT_CTRL_DATA */ {BTA_HH_CTRL_DAT_ACT, BTA_HH_CONN_ST }, +/* BTA_HH_INT_HANDSK_EVT */ {BTA_HH_HANDSK_ACT, BTA_HH_CONN_ST }, +/* BTA_HH_SDP_CMPL_EVT */ {BTA_HH_IGNORE, BTA_HH_CONN_ST }, +/* BTA_HH_API_WRITE_DEV_EVT */ {BTA_HH_WRITE_DEV_ACT, BTA_HH_CONN_ST }, +/* BTA_HH_API_GET_DSCP_EVT */ {BTA_HH_GET_DSCP_ACT, BTA_HH_CONN_ST }, +/* BTA_HH_API_MAINT_DEV_EVT */ {BTA_HH_MAINT_DEV_ACT, BTA_HH_CONN_ST }, +/* BTA_HH_OPEN_CMPL_EVT */ {BTA_HH_IGNORE, BTA_HH_CONN_ST } +#if (defined BTA_HH_LE_INCLUDED && BTA_HH_LE_INCLUDED == TRUE) +/* BTA_HH_GATT_CLOSE_EVT */ ,{BTA_HH_GATT_CLOSE, BTA_HH_IDLE_ST } +/* BTA_HH_GATT_OPEN_EVT */ ,{BTA_HH_IGNORE, BTA_HH_CONN_ST } +/* BTA_HH_START_ENC_EVT */ ,{BTA_HH_IGNORE, BTA_HH_CONN_ST } +/* BTA_HH_ENC_CMPL_EVT */ ,{BTA_HH_IGNORE, BTA_HH_CONN_ST } +/* READ_CHAR_CMPL_EVT */ ,{BTA_HH_LE_READ_CHAR, BTA_HH_CONN_ST } +/* WRITE_CHAR_CMPL_EVT*/ ,{BTA_HH_LE_WRITE, BTA_HH_CONN_ST } +/* READ_DESCR_CMPL_EVT */ ,{BTA_HH_LE_READ_DESCR, BTA_HH_CONN_ST } /* do not currently read any descr when connection up */ +/* WRITE_DESCR_CMPL_EVT */ ,{BTA_HH_WRITE_DESCR, BTA_HH_CONN_ST } /* do not currently write any descr when connection up */ +/* SCPP_UPDATE_EVT */ ,{BTA_HH_LE_UPDATE_SCPP, BTA_HH_CONN_ST } +/* BTA_HH_GATT_ENC_CMPL_EVT */ ,{BTA_HH_IGNORE, BTA_HH_CONN_ST } +#endif +}; +#if (defined BTA_HH_LE_INCLUDED && BTA_HH_LE_INCLUDED == TRUE) +const UINT8 bta_hh_st_w4_sec[][BTA_HH_NUM_COLS] = +{ +/* Event Action Next state */ +/* BTA_HH_API_OPEN_EVT */ {BTA_HH_IGNORE, BTA_HH_W4_SEC }, +/* BTA_HH_API_CLOSE_EVT */ {BTA_HH_API_DISC_ACT, BTA_HH_W4_SEC }, +/* BTA_HH_INT_OPEN_EVT */ {BTA_HH_IGNORE, BTA_HH_W4_SEC }, +/* BTA_HH_INT_CLOSE_EVT */ {BTA_HH_OPEN_FAILURE, BTA_HH_IDLE_ST }, +/* BTA_HH_INT_DATA_EVT */ {BTA_HH_IGNORE, BTA_HH_W4_SEC }, +/* BTA_HH_INT_CTRL_DATA */ {BTA_HH_IGNORE, BTA_HH_W4_SEC }, +/* BTA_HH_INT_HANDSK_EVT */ {BTA_HH_IGNORE, BTA_HH_W4_SEC }, +/* BTA_HH_SDP_CMPL_EVT */ {BTA_HH_IGNORE, BTA_HH_W4_SEC }, +/* BTA_HH_API_WRITE_DEV_EVT */ {BTA_HH_IGNORE , BTA_HH_W4_SEC }, +/* BTA_HH_API_GET_DSCP_EVT */ {BTA_HH_IGNORE, BTA_HH_W4_SEC }, +/* BTA_HH_API_MAINT_DEV_EVT */ {BTA_HH_MAINT_DEV_ACT, BTA_HH_W4_SEC }, +/* BTA_HH_OPEN_CMPL_EVT */ {BTA_HH_IGNORE, BTA_HH_W4_SEC }, +/* BTA_HH_GATT_CLOSE_EVT */ {BTA_HH_LE_OPEN_FAIL, BTA_HH_IDLE_ST }, +/* BTA_HH_GATT_OPEN_EVT */ {BTA_HH_IGNORE, BTA_HH_W4_SEC }, +/* BTA_HH_START_ENC_EVT */ {BTA_HH_IGNORE, BTA_HH_W4_SEC }, +/* BTA_HH_ENC_CMPL_EVT */ {BTA_HH_SEC_CMPL, BTA_HH_W4_CONN_ST }, +/* READ_CHAR_CMPL_EVT */ {BTA_HH_IGNORE, BTA_HH_W4_SEC }, +/* BTA_HH_GATT_WRITE_CMPL_EVT*/ {BTA_HH_IGNORE, BTA_HH_W4_SEC }, +/* READ_DESCR_CMPL_EVT */ {BTA_HH_IGNORE, BTA_HH_W4_SEC }, +/* WRITE_DESCR_CMPL_EVT */ {BTA_HH_IGNORE, BTA_HH_W4_SEC } +/* SCPP_UPDATE_EVT */ ,{BTA_HH_IGNORE, BTA_HH_W4_SEC } +/* BTA_HH_GATT_ENC_CMPL_EVT */ ,{BTA_HH_GATT_ENC_CMPL, BTA_HH_W4_SEC } +}; +#endif + +/* type for state table */ +typedef const UINT8 (*tBTA_HH_ST_TBL)[BTA_HH_NUM_COLS]; + +/* state table */ +const tBTA_HH_ST_TBL bta_hh_st_tbl[] = +{ + bta_hh_st_idle, + bta_hh_st_w4_conn, + bta_hh_st_connected +#if (defined BTA_HH_LE_INCLUDED && BTA_HH_LE_INCLUDED == TRUE) + ,bta_hh_st_w4_sec +#endif +}; + +/***************************************************************************** +** Global data +*****************************************************************************/ +#if BTA_DYNAMIC_MEMORY == FALSE +tBTA_HH_CB bta_hh_cb; +#endif +/***************************************************************************** +** Static functions +*****************************************************************************/ +#if BTA_HH_DEBUG == TRUE +static char *bta_hh_evt_code(tBTA_HH_INT_EVT evt_code); +static char *bta_hh_state_code(tBTA_HH_STATE state_code); +#endif + +/******************************************************************************* +** +** Function bta_hh_sm_execute +** +** Description State machine event handling function for HID Host +** +** +** Returns void +** +*******************************************************************************/ +void bta_hh_sm_execute(tBTA_HH_DEV_CB *p_cb, UINT16 event, tBTA_HH_DATA * p_data) +{ + tBTA_HH_ST_TBL state_table; + UINT8 action; + tBTA_HH cback_data; + tBTA_HH_EVT cback_event = 0; +#if BTA_HH_DEBUG == TRUE + tBTA_HH_STATE in_state ; + UINT16 debug_event = event; +#endif + + memset(&cback_data, 0, sizeof(tBTA_HH)); + + /* handle exception, no valid control block was found */ + if (!p_cb) + { + /* BTA HH enabled already? otherwise ignore the event although it's bad*/ + if (bta_hh_cb.p_cback != NULL) + { + switch (event) + { + /* no control block available for new connection */ + case BTA_HH_API_OPEN_EVT: + cback_event = BTA_HH_OPEN_EVT; + /* build cback data */ + bdcpy(cback_data.conn.bda, ((tBTA_HH_API_CONN *)p_data)->bd_addr); + cback_data.conn.status = BTA_HH_ERR_DB_FULL; + cback_data.conn.handle = BTA_HH_INVALID_HANDLE; + break; + /* DB full, BTA_HhAddDev */ + case BTA_HH_API_MAINT_DEV_EVT: + cback_event = p_data->api_maintdev.sub_event; + + if (p_data->api_maintdev.sub_event == BTA_HH_ADD_DEV_EVT) + { + bdcpy(cback_data.dev_info.bda, p_data->api_maintdev.bda); + cback_data.dev_info.status = BTA_HH_ERR_DB_FULL; + cback_data.dev_info.handle = BTA_HH_INVALID_HANDLE; + } + else + { + cback_data.dev_info.status = BTA_HH_ERR_HDL; + cback_data.dev_info.handle = (UINT8)p_data->api_maintdev.hdr.layer_specific; + } + break; + case BTA_HH_API_WRITE_DEV_EVT: + cback_event = (p_data->api_sndcmd.t_type - BTA_HH_FST_BTE_TRANS_EVT) + + BTA_HH_FST_TRANS_CB_EVT; + if (p_data->api_sndcmd.p_data != NULL) + { + GKI_freebuf(p_data->api_sndcmd.p_data); + } + if (p_data->api_sndcmd.t_type == HID_TRANS_SET_PROTOCOL || + p_data->api_sndcmd.t_type == HID_TRANS_SET_REPORT || + p_data->api_sndcmd.t_type == HID_TRANS_SET_IDLE) + { + cback_data.dev_status.status = BTA_HH_ERR_HDL; + cback_data.dev_status.handle = (UINT8)p_data->api_sndcmd.hdr.layer_specific; + } + else if (p_data->api_sndcmd.t_type != HID_TRANS_DATA && + p_data->api_sndcmd.t_type != HID_TRANS_CONTROL) + { + cback_data.hs_data.handle = (UINT8)p_data->api_sndcmd.hdr.layer_specific; + cback_data.hs_data.status = BTA_HH_ERR_HDL; + /* hs_data.rsp_data will be all zero, which is not valid value */ + } + else if (p_data->api_sndcmd.t_type == HID_TRANS_CONTROL && + p_data->api_sndcmd.param == BTA_HH_CTRL_VIRTUAL_CABLE_UNPLUG) + { + cback_data.status = BTA_HH_ERR_HDL; + cback_event = BTA_HH_VC_UNPLUG_EVT; + } + else + cback_event = 0; + break; + + case BTA_HH_API_CLOSE_EVT: + cback_event = BTA_HH_CLOSE_EVT; + + cback_data.dev_status.status = BTA_HH_ERR_HDL; + cback_data.dev_status.handle = (UINT8)p_data->api_sndcmd.hdr.layer_specific; + break; + + default: + /* invalid handle, call bad API event */ + APPL_TRACE_ERROR("wrong device handle: [%d]", p_data->hdr.layer_specific); + /* Free the callback buffer now */ + if (p_data != NULL && p_data->hid_cback.p_data != NULL) + { + GKI_freebuf(p_data->hid_cback.p_data); + p_data->hid_cback.p_data = NULL; + } + break; + } + if (cback_event) + (* bta_hh_cb.p_cback)(cback_event, &cback_data); + } + } + /* corresponding CB is found, go to state machine */ + else + { +#if BTA_HH_DEBUG == TRUE + in_state = p_cb->state; + APPL_TRACE_EVENT("bta_hh_sm_execute: State 0x%02x [%s], Event [%s]", + in_state, bta_hh_state_code(in_state), + bta_hh_evt_code(debug_event)); +#endif + + if ((p_cb->state == BTA_HH_NULL_ST) || (p_cb->state >= BTA_HH_INVALID_ST)) + { + APPL_TRACE_ERROR("bta_hh_sm_execute: Invalid state State = 0x%x, Event = %d", + p_cb->state,event); + return; + } + state_table = bta_hh_st_tbl[p_cb->state - 1]; + + event &= 0xff; + + p_cb->state = state_table[event][BTA_HH_NEXT_STATE] ; + + if ((action = state_table[event][BTA_HH_ACTION]) != BTA_HH_IGNORE) + { + (*bta_hh_action[action])(p_cb, p_data); + } + +#if BTA_HH_DEBUG == TRUE + if (in_state != p_cb->state) + { + APPL_TRACE_DEBUG("HH State Change: [%s] -> [%s] after Event [%s]", + bta_hh_state_code(in_state), + bta_hh_state_code(p_cb->state), + bta_hh_evt_code(debug_event)); + } +#endif + } + + return; +} +/******************************************************************************* +** +** Function bta_hh_hdl_event +** +** Description HID host main event handling function. +** +** +** Returns void +** +*******************************************************************************/ +BOOLEAN bta_hh_hdl_event(BT_HDR *p_msg) +{ + UINT8 index = BTA_HH_IDX_INVALID; + tBTA_HH_DEV_CB *p_cb = NULL; + + switch (p_msg->event) + { + case BTA_HH_API_ENABLE_EVT: + bta_hh_api_enable((tBTA_HH_DATA *) p_msg); + break; + + case BTA_HH_API_DISABLE_EVT: + bta_hh_api_disable(); + break; + + case BTA_HH_DISC_CMPL_EVT: /* disable complete */ + bta_hh_disc_cmpl(); + break; + + default: + /* all events processed in state machine need to find corresponding + CB before proceed */ + if (p_msg->event == BTA_HH_API_OPEN_EVT) + { + index = bta_hh_find_cb(((tBTA_HH_API_CONN *)p_msg)->bd_addr); + } + else if (p_msg->event == BTA_HH_API_MAINT_DEV_EVT) + { + /* if add device */ + if (((tBTA_HH_MAINT_DEV *)p_msg)->sub_event == BTA_HH_ADD_DEV_EVT) + { + index = bta_hh_find_cb(((tBTA_HH_MAINT_DEV *)p_msg)->bda); + } + else /* else remove device by handle */ + { + index = bta_hh_dev_handle_to_cb_idx((UINT8)p_msg->layer_specific); +// btla-specific ++ + /* If BT disable is done while the HID device is connected and Link_Key uses unauthenticated combination + * then we can get into a situation where remove_bonding is called with the index set to 0 (without getting + * cleaned up). Only when VIRTUAL_UNPLUG is called do we cleanup the index and make it MAX_KNOWN. + * So if REMOVE_DEVICE is called and in_use is FALSE then we should treat this as a NULL p_cb. Hence we + * force the index to be IDX_INVALID + */ + if ((index != BTA_HH_IDX_INVALID) && + (bta_hh_cb.kdev[index].in_use == FALSE)) { + index = BTA_HH_IDX_INVALID; + } +// btla-specific -- + } + } + else if (p_msg->event == BTA_HH_INT_OPEN_EVT) + { + index = bta_hh_find_cb(((tBTA_HH_CBACK_DATA *)p_msg)->addr); + } + else + index = bta_hh_dev_handle_to_cb_idx((UINT8)p_msg->layer_specific); + + if (index != BTA_HH_IDX_INVALID) + p_cb = &bta_hh_cb.kdev[index]; + +#if BTA_HH_DEBUG + APPL_TRACE_DEBUG("bta_hh_hdl_event:: handle = %d dev_cb[%d] ", p_msg->layer_specific, index); +#endif + bta_hh_sm_execute(p_cb, p_msg->event, (tBTA_HH_DATA *) p_msg); + } + return (TRUE); +} + +/***************************************************************************** +** Debug Functions +*****************************************************************************/ +#if BTA_HH_DEBUG +/******************************************************************************* +** +** Function bta_hh_evt_code +** +** Description +** +** Returns void +** +*******************************************************************************/ +static char *bta_hh_evt_code(tBTA_HH_INT_EVT evt_code) +{ + switch(evt_code) + { + case BTA_HH_API_DISABLE_EVT: + return "BTA_HH_API_DISABLE_EVT"; + case BTA_HH_API_ENABLE_EVT: + return "BTA_HH_API_ENABLE_EVT"; + case BTA_HH_API_OPEN_EVT: + return "BTA_HH_API_OPEN_EVT"; + case BTA_HH_API_CLOSE_EVT: + return "BTA_HH_API_CLOSE_EVT"; + case BTA_HH_INT_OPEN_EVT: + return "BTA_HH_INT_OPEN_EVT"; + case BTA_HH_INT_CLOSE_EVT: + return "BTA_HH_INT_CLOSE_EVT"; + case BTA_HH_INT_HANDSK_EVT: + return "BTA_HH_INT_HANDSK_EVT"; + case BTA_HH_INT_DATA_EVT: + return "BTA_HH_INT_DATA_EVT"; + case BTA_HH_INT_CTRL_DATA: + return "BTA_HH_INT_CTRL_DATA"; + case BTA_HH_API_WRITE_DEV_EVT: + return "BTA_HH_API_WRITE_DEV_EVT"; + case BTA_HH_SDP_CMPL_EVT: + return "BTA_HH_SDP_CMPL_EVT"; + case BTA_HH_DISC_CMPL_EVT: + return "BTA_HH_DISC_CMPL_EVT"; + case BTA_HH_API_MAINT_DEV_EVT: + return "BTA_HH_API_MAINT_DEV_EVT"; + case BTA_HH_API_GET_DSCP_EVT: + return "BTA_HH_API_GET_DSCP_EVT"; + case BTA_HH_OPEN_CMPL_EVT: + return "BTA_HH_OPEN_CMPL_EVT"; +#if (defined BTA_HH_LE_INCLUDED && BTA_HH_LE_INCLUDED == TRUE) + case BTA_HH_GATT_CLOSE_EVT: + return "BTA_HH_GATT_CLOSE_EVT"; + case BTA_HH_GATT_OPEN_EVT: + return "BTA_HH_GATT_OPEN_EVT"; + case BTA_HH_START_ENC_EVT: + return "BTA_HH_START_ENC_EVT"; + case BTA_HH_ENC_CMPL_EVT: + return "BTA_HH_ENC_CMPL_EVT"; + case BTA_HH_GATT_READ_CHAR_CMPL_EVT: + return "BTA_HH_GATT_READ_CHAR_CMPL_EVT"; + case BTA_HH_GATT_WRITE_CHAR_CMPL_EVT: + return "BTA_HH_GATT_WRITE_CHAR_CMPL_EVT"; + case BTA_HH_GATT_READ_DESCR_CMPL_EVT: + return "BTA_HH_GATT_READ_DESCR_CMPL_EVT"; + case BTA_HH_GATT_WRITE_DESCR_CMPL_EVT: + return "BTA_HH_GATT_WRITE_DESCR_CMPL_EVT"; +#endif + default: + return "unknown HID Host event code"; + } +} + +/******************************************************************************* +** +** Function bta_hh_state_code +** +** Description get string representation of HID host state code. +** +** Returns void +** +*******************************************************************************/ +static char *bta_hh_state_code(tBTA_HH_STATE state_code) +{ + switch (state_code) + { + case BTA_HH_NULL_ST: + return"BTA_HH_NULL_ST"; + case BTA_HH_IDLE_ST: + return "BTA_HH_IDLE_ST"; + case BTA_HH_W4_CONN_ST: + return "BTA_HH_W4_CONN_ST"; + case BTA_HH_CONN_ST: + return "BTA_HH_CONN_ST"; +#if (defined BTA_HH_LE_INCLUDED && BTA_HH_LE_INCLUDED == TRUE) + case BTA_HH_W4_SEC: + return "BTA_HH_W4_SEC"; +#endif + default: + return "unknown HID Host state"; + } +} + +#endif /* Debug Functions */ + +#endif /* BTA_HH_INCLUDED */ diff --git a/components/bt/bluedroid/bta/hh/bta_hh_utils.c b/components/bt/bluedroid/bta/hh/bta_hh_utils.c new file mode 100644 index 0000000000..dc20a0d4ab --- /dev/null +++ b/components/bt/bluedroid/bta/hh/bta_hh_utils.c @@ -0,0 +1,539 @@ +/****************************************************************************** + * + * Copyright (C) 2005-2012 Broadcom Corporation + * + * 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. + * + ******************************************************************************/ +#include + +#include "bt_target.h" +#if defined(BTA_HH_INCLUDED) && (BTA_HH_INCLUDED == TRUE) + + +#include "bta_hh_int.h" + +/* if SSR max latency is not defined by remote device, set the default value + as half of the link supervision timeout */ +#define BTA_HH_GET_DEF_SSR_MAX_LAT(x) ((x)>> 1) + +/***************************************************************************** +** Constants +*****************************************************************************/ +#define BTA_HH_KB_CTRL_MASK 0x11 +#define BTA_HH_KB_SHIFT_MASK 0x22 +#define BTA_HH_KB_ALT_MASK 0x44 +#define BTA_HH_KB_GUI_MASK 0x88 + +#define BTA_HH_KB_CAPS_LOCK 0x39 /* caps lock */ +#define BTA_HH_KB_NUM_LOCK 0x53 /* num lock */ + + +#define BTA_HH_MAX_RPT_CHARS 8 + +static const UINT8 bta_hh_mod_key_mask[BTA_HH_MOD_MAX_KEY] = +{ + BTA_HH_KB_CTRL_MASK, + BTA_HH_KB_SHIFT_MASK, + BTA_HH_KB_ALT_MASK, + BTA_HH_KB_GUI_MASK +}; + + +/******************************************************************************* +** +** Function bta_hh_find_cb +** +** Description Find best available control block according to BD address. +** +** +** Returns void +** +*******************************************************************************/ +UINT8 bta_hh_find_cb(BD_ADDR bda) +{ + UINT8 xx; + + /* See how many active devices there are. */ + for (xx = 0; xx < BTA_HH_MAX_DEVICE; xx++) + { + /* check if any active/known devices is a match */ + if ((!bdcmp (bda, bta_hh_cb.kdev[xx].addr) && + bdcmp(bda, bd_addr_null) != 0) ) + { +#if BTA_HH_DEBUG + APPL_TRACE_DEBUG("found kdev_cb[%d] hid_handle = %d ", xx, + bta_hh_cb.kdev[xx].hid_handle) +#endif + return xx; + } +#if BTA_HH_DEBUG + else + APPL_TRACE_DEBUG("in_use ? [%d] kdev[%d].hid_handle = %d state = [%d]", + bta_hh_cb.kdev[xx].in_use, xx, + bta_hh_cb.kdev[xx].hid_handle, + bta_hh_cb.kdev[xx].state); +#endif + } + + /* if no active device match, find a spot for it */ + for (xx = 0; xx < BTA_HH_MAX_DEVICE; xx++) + { + if (!bta_hh_cb.kdev[xx].in_use) + { + bdcpy(bta_hh_cb.kdev[xx].addr, bda); + break; + } + } + /* If device list full, report BTA_HH_IDX_INVALID */ +#if BTA_HH_DEBUG + APPL_TRACE_DEBUG("bta_hh_find_cb:: index = %d while max = %d", + xx, BTA_HH_MAX_DEVICE); +#endif + + if (xx == BTA_HH_MAX_DEVICE) + xx = BTA_HH_IDX_INVALID; + + return xx; +} + +/******************************************************************************* +** +** Function bta_hh_clean_up_kdev +** +** Description Clean up device control block when device is removed from +** manitainace list, and update control block index map. +** +** Returns void +** +*******************************************************************************/ +void bta_hh_clean_up_kdev(tBTA_HH_DEV_CB *p_cb) +{ + UINT8 index; + + if (p_cb->hid_handle != BTA_HH_INVALID_HANDLE ) + { +#if BTA_HH_LE_INCLUDED == TRUE + if (p_cb->is_le_device) + bta_hh_cb.le_cb_index[BTA_HH_GET_LE_CB_IDX(p_cb->hid_handle)] = BTA_HH_IDX_INVALID; + else +#endif + bta_hh_cb.cb_index[p_cb->hid_handle] = BTA_HH_IDX_INVALID; + } + + /* reset device control block */ + index = p_cb->index; /* Preserve index for this control block */ + + /* Free buffer for report descriptor info */ + utl_freebuf((void **)&p_cb->dscp_info.descriptor.dsc_list); + + memset(p_cb, 0, sizeof (tBTA_HH_DEV_CB)); /* Reset control block */ + + p_cb->index = index; /* Restore index for this control block */ + p_cb->state = BTA_HH_IDLE_ST; + p_cb->hid_handle = BTA_HH_INVALID_HANDLE; + +} +/******************************************************************************* +** +** Function bta_hh_update_di_info +** +** Description Maintain a known device list for BTA HH. +** +** Returns void +** +*******************************************************************************/ +void bta_hh_update_di_info(tBTA_HH_DEV_CB *p_cb, UINT16 vendor_id, UINT16 product_id, + UINT16 version, UINT8 flag) +{ +#if BTA_HH_DEBUG + APPL_TRACE_DEBUG("vendor_id = 0x%2x product_id = 0x%2x version = 0x%2x", + vendor_id, product_id, version); +#endif + p_cb->dscp_info.vendor_id = vendor_id; + p_cb->dscp_info.product_id = product_id; + p_cb->dscp_info.version = version; +#if (defined BTA_HH_LE_INCLUDED && BTA_HH_LE_INCLUDED == TRUE) + p_cb->dscp_info.flag = flag; +#else + UNUSED(flag); +#endif +} +/******************************************************************************* +** +** Function bta_hh_add_device_to_list +** +** Description Maintain a known device list for BTA HH. +** +** Returns void +** +*******************************************************************************/ +void bta_hh_add_device_to_list(tBTA_HH_DEV_CB *p_cb, UINT8 handle, + UINT16 attr_mask, + tHID_DEV_DSCP_INFO *p_dscp_info, + UINT8 sub_class, + UINT16 ssr_max_latency, + UINT16 ssr_min_tout, + UINT8 app_id) +{ +#if BTA_HH_DEBUG + APPL_TRACE_DEBUG("subclass = 0x%2x", sub_class); +#endif + + p_cb->hid_handle = handle; + p_cb->in_use = TRUE; + p_cb->attr_mask = attr_mask; + + p_cb->sub_class = sub_class; + p_cb->app_id = app_id; + + p_cb->dscp_info.ssr_max_latency = ssr_max_latency; + p_cb->dscp_info.ssr_min_tout = ssr_min_tout; + + /* store report descriptor info */ + if ( p_dscp_info) + { + utl_freebuf((void **)&p_cb->dscp_info.descriptor.dsc_list); + + if (p_dscp_info->dl_len && + (p_cb->dscp_info.descriptor.dsc_list = + (UINT8 *)GKI_getbuf(p_dscp_info->dl_len)) != NULL) + { + p_cb->dscp_info.descriptor.dl_len = p_dscp_info->dl_len; + memcpy(p_cb->dscp_info.descriptor.dsc_list, p_dscp_info->dsc_list, + p_dscp_info->dl_len); + } + } + return; +} + +/******************************************************************************* +** +** Function bta_hh_tod_spt +** +** Description Check to see if this type of device is supported +** +** Returns +** +*******************************************************************************/ +BOOLEAN bta_hh_tod_spt(tBTA_HH_DEV_CB *p_cb,UINT8 sub_class) +{ + UINT8 xx; + UINT8 cod = (sub_class >> 2); /* lower two bits are reserved */ + + for (xx = 0 ; xx < p_bta_hh_cfg->max_devt_spt; xx ++) + { + if (cod == (UINT8) p_bta_hh_cfg->p_devt_list[xx].tod) + { + p_cb->app_id = p_bta_hh_cfg->p_devt_list[xx].app_id; +#if BTA_HH_DEBUG + APPL_TRACE_EVENT("bta_hh_tod_spt sub_class:0x%x supported", sub_class); +#endif + return TRUE; + } + } +#if BTA_HH_DEBUG + APPL_TRACE_EVENT("bta_hh_tod_spt sub_class:0x%x NOT supported", sub_class); +#endif + return FALSE; +} + + +/******************************************************************************* +** +** Function bta_hh_parse_keybd_rpt +** +** Description This utility function parse a boot mode keyboard report. +** +** Returns void +** +*******************************************************************************/ +void bta_hh_parse_keybd_rpt(tBTA_HH_BOOT_RPT *p_kb_data, UINT8 *p_report, + UINT16 report_len) +{ + tBTA_HH_KB_CB *p_kb = &bta_hh_cb.kb_cb; + tBTA_HH_KEYBD_RPT *p_data = &p_kb_data->data_rpt.keybd_rpt; + + UINT8 this_char, ctl_shift; + UINT16 xx, yy, key_idx = 0; + UINT8 this_report[BTA_HH_MAX_RPT_CHARS]; + +#if BTA_HH_DEBUG + APPL_TRACE_DEBUG("bta_hh_parse_keybd_rpt: (report=%p, report_len=%d) called", + p_report, report_len); +#endif + + if (report_len < 2) + return; + + ctl_shift = *p_report++; + report_len--; + + if (report_len > BTA_HH_MAX_RPT_CHARS) + report_len = BTA_HH_MAX_RPT_CHARS; + + memset (this_report, 0, BTA_HH_MAX_RPT_CHARS); + memset (p_data, 0, sizeof(tBTA_HH_KEYBD_RPT)); + memcpy (this_report, p_report, report_len); + + /* Take care of shift, control, GUI and alt, modifier keys */ + for (xx = 0; xx < BTA_HH_MOD_MAX_KEY; xx ++ ) + { + if (ctl_shift & bta_hh_mod_key_mask[xx]) + { + APPL_TRACE_DEBUG("Mod Key[%02x] pressed", bta_hh_mod_key_mask[xx] ); + p_kb->mod_key[xx] = TRUE; + } + else if (p_kb->mod_key[xx]) + { + p_kb->mod_key[xx] = FALSE; + } + /* control key flag is set */ + p_data->mod_key[xx] = p_kb->mod_key[xx]; + } + + /***************************************************************************/ + /* First step is to remove all characters we saw in the last report */ + /***************************************************************************/ + for (xx = 0; xx < report_len; xx++) + { + for (yy = 0; yy < BTA_HH_MAX_RPT_CHARS; yy++) + { + if (this_report[xx] == p_kb->last_report[yy]) + { + this_report[xx] = 0; + } + } + } + /***************************************************************************/ + /* Now, process all the characters in the report, up to 6 keycodes */ + /***************************************************************************/ + for (xx = 0; xx < report_len; xx++) + { +#if BTA_HH_DEBUG + APPL_TRACE_DEBUG("this_char = %02x", this_report[xx]); +#endif + if ((this_char = this_report[xx]) == 0) + continue; + /* take the key code as the report data */ + if (this_report[xx] == BTA_HH_KB_CAPS_LOCK) + p_kb->caps_lock = p_kb->caps_lock ? FALSE : TRUE; + else if (this_report[xx] == BTA_HH_KB_NUM_LOCK) + p_kb->num_lock = p_kb->num_lock ? FALSE : TRUE; + else + p_data->this_char[key_idx ++] = this_char; + +#if BTA_HH_DEBUG + APPL_TRACE_DEBUG("found keycode %02x ", this_report[xx]); +#endif + p_data->caps_lock = p_kb->caps_lock; + p_data->num_lock = p_kb->num_lock; + } + + memset (p_kb->last_report, 0, BTA_HH_MAX_RPT_CHARS); + memcpy (p_kb->last_report, p_report, report_len); + + return; +} + +/******************************************************************************* +** +** Function bta_hh_parse_mice_rpt +** +** Description This utility function parse a boot mode mouse report. +** +** Returns void +** +*******************************************************************************/ +void bta_hh_parse_mice_rpt(tBTA_HH_BOOT_RPT *p_mice_data, UINT8 *p_report, + UINT16 report_len) +{ + tBTA_HH_MICE_RPT *p_data = &p_mice_data->data_rpt.mice_rpt; +#if BTA_HH_DEBUG + UINT8 xx; + + APPL_TRACE_DEBUG("bta_hh_parse_mice_rpt: bta_keybd_rpt_rcvd(report=%p, \ + report_len=%d) called", p_report, report_len); +#endif + + if (report_len < 3) + return; + + if (report_len > BTA_HH_MAX_RPT_CHARS) + report_len = BTA_HH_MAX_RPT_CHARS; + +#if BTA_HH_DEBUG + for (xx = 0; xx < report_len; xx++) + { + APPL_TRACE_DEBUG("this_char = %02x", p_report[xx]); + } +#endif + + /* only first bytes lower 3 bits valid */ + p_data->mouse_button = (p_report[0] & 0x07); + + /* x displacement */ + p_data->delta_x = p_report[1]; + + /* y displacement */ + p_data->delta_y = p_report[2]; + +#if BTA_HH_DEBUG + APPL_TRACE_DEBUG("mice button: 0x%2x", p_data->mouse_button); + APPL_TRACE_DEBUG("mice move: x = %d y = %d", p_data->delta_x, + p_data->delta_y ); +#endif + + return; + +} + +/******************************************************************************* +** +** Function bta_hh_read_ssr_param +** +** Description Read the SSR Parameter for the remote device +** +** Returns tBTA_HH_STATUS operation status +** +*******************************************************************************/ +tBTA_HH_STATUS bta_hh_read_ssr_param(BD_ADDR bd_addr, UINT16 *p_max_ssr_lat, UINT16 *p_min_ssr_tout) +{ + tBTA_HH_STATUS status = BTA_HH_ERR; + tBTA_HH_CB *p_cb = &bta_hh_cb; + UINT8 i; + UINT16 ssr_max_latency; + for (i = 0; i < BTA_HH_MAX_KNOWN; i ++) + { + if (memcmp(p_cb->kdev[i].addr, bd_addr, BD_ADDR_LEN) == 0) + { + + /* if remote device does not have HIDSSRHostMaxLatency attribute in SDP, + set SSR max latency default value here. */ + if (p_cb->kdev[i].dscp_info.ssr_max_latency == HID_SSR_PARAM_INVALID) + { + /* The default is calculated as half of link supervision timeout.*/ + + BTM_GetLinkSuperTout(p_cb->kdev[i].addr, &ssr_max_latency) ; + ssr_max_latency = BTA_HH_GET_DEF_SSR_MAX_LAT(ssr_max_latency); + + /* per 1.1 spec, if the newly calculated max latency is greater than + BTA_HH_SSR_MAX_LATENCY_DEF which is 500ms, use BTA_HH_SSR_MAX_LATENCY_DEF */ + if (ssr_max_latency > BTA_HH_SSR_MAX_LATENCY_DEF) + ssr_max_latency = BTA_HH_SSR_MAX_LATENCY_DEF; + + * p_max_ssr_lat = ssr_max_latency; + } + else + * p_max_ssr_lat = p_cb->kdev[i].dscp_info.ssr_max_latency; + + if (p_cb->kdev[i].dscp_info.ssr_min_tout == HID_SSR_PARAM_INVALID) + * p_min_ssr_tout = BTA_HH_SSR_MIN_TOUT_DEF; + else + * p_min_ssr_tout = p_cb->kdev[i].dscp_info.ssr_min_tout; + + status = BTA_HH_OK; + + break; + } + } + + return status; +} + +/******************************************************************************* +** +** Function bta_hh_cleanup_disable +** +** Description when disable finished, cleanup control block and send callback +** +** +** Returns void +** +*******************************************************************************/ +void bta_hh_cleanup_disable(tBTA_HH_STATUS status) +{ + UINT8 xx; + /* free buffer in CB holding report descriptors */ + for(xx = 0; xx < BTA_HH_MAX_DEVICE; xx ++) + { + utl_freebuf((void **)&bta_hh_cb.kdev[xx].dscp_info.descriptor.dsc_list); + } + utl_freebuf((void **)&bta_hh_cb.p_disc_db); + + (* bta_hh_cb.p_cback)(BTA_HH_DISABLE_EVT, (tBTA_HH *)&status); + /* all connections are down, no waiting for diconnect */ + memset(&bta_hh_cb, 0, sizeof(tBTA_HH_CB)); +} + +/******************************************************************************* +** +** Function bta_hh_dev_handle_to_cb_idx +** +** Description convert a HID device handle to the device control block index. +** +** +** Returns UINT8: index of the device control block. +** +*******************************************************************************/ +UINT8 bta_hh_dev_handle_to_cb_idx(UINT8 dev_handle) +{ + UINT8 index = BTA_HH_IDX_INVALID; + +#if BTA_HH_LE_INCLUDED == TRUE + if (BTA_HH_IS_LE_DEV_HDL(dev_handle)) + { + if (BTA_HH_IS_LE_DEV_HDL_VALID(dev_handle)) + index = bta_hh_cb.le_cb_index[BTA_HH_GET_LE_CB_IDX(dev_handle)]; +#if BTA_HH_DEBUG == TRUE + APPL_TRACE_DEBUG("bta_hh_dev_handle_to_cb_idx dev_handle = %d index = %d", dev_handle, index); +#endif + } + else +#endif + /* regular HID device checking */ + if (dev_handle < BTA_HH_MAX_KNOWN ) + index = bta_hh_cb.cb_index[dev_handle]; + + return index; + +} +#if BTA_HH_DEBUG +/******************************************************************************* +** +** Function bta_hh_trace_dev_db +** +** Description Check to see if this type of device is supported +** +** Returns +** +*******************************************************************************/ +void bta_hh_trace_dev_db(void) +{ + UINT8 xx; + + APPL_TRACE_DEBUG("bta_hh_trace_dev_db:: Device DB list********************"); + + for (xx = 0; xx < BTA_HH_MAX_DEVICE; xx++) + { + APPL_TRACE_DEBUG("kdev[%d] in_use[%d] handle[%d] ",xx, + bta_hh_cb.kdev[xx].in_use, bta_hh_cb.kdev[xx].hid_handle); + + APPL_TRACE_DEBUG("\t\t\t attr_mask[%04x] state [%d] sub_class[%02x] index = %d", + bta_hh_cb.kdev[xx].attr_mask, bta_hh_cb.kdev[xx].state, + bta_hh_cb.kdev[xx].sub_class, bta_hh_cb.kdev[xx].index); + } + APPL_TRACE_DEBUG("*********************************************************"); +} +#endif +#endif /* HL_INCLUDED */ diff --git a/components/bt/bluedroid/bta/include/bta_api.h b/components/bt/bluedroid/bta/include/bta_api.h new file mode 100755 index 0000000000..4776d5954e --- /dev/null +++ b/components/bt/bluedroid/bta/include/bta_api.h @@ -0,0 +1,2389 @@ +/****************************************************************************** + * + * Copyright (C) 2003-2014 Broadcom Corporation + * + * 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 is the public interface file for BTA, Broadcom's Bluetooth + * application layer for mobile phones. + * + ******************************************************************************/ +#ifndef BTA_API_H +#define BTA_API_H + +#include "bt_target.h" +#include "bt_types.h" +#include "btm_api.h" +// #include "uipc_msg.h" + +#if BLE_INCLUDED == TRUE +#include "btm_ble_api.h" +#endif + +/***************************************************************************** +** Constants and data types +*****************************************************************************/ + +/* Status Return Value */ +#define BTA_SUCCESS 0 /* Successful operation. */ +#define BTA_FAILURE 1 /* Generic failure. */ +#define BTA_PENDING 2 /* API cannot be completed right now */ +#define BTA_BUSY 3 +#define BTA_NO_RESOURCES 4 +#define BTA_WRONG_MODE 5 + +typedef UINT8 tBTA_STATUS; + +/* + * Service ID + * + * NOTES: When you add a new Service ID for BTA AND require to change the value of BTA_MAX_SERVICE_ID, + * make sure that the correct security ID of the new service from Security service definitions (btm_api.h) + * should be added to bta_service_id_to_btm_srv_id_lkup_tbl table in bta_dm_act.c. + */ + +#define BTA_RES_SERVICE_ID 0 /* Reserved */ +#define BTA_SPP_SERVICE_ID 1 /* Serial port profile. */ +#define BTA_DUN_SERVICE_ID 2 /* Dial-up networking profile. */ +#define BTA_A2DP_SOURCE_SERVICE_ID 3 /* A2DP Source profile. */ +#define BTA_LAP_SERVICE_ID 4 /* LAN access profile. */ +#define BTA_HSP_SERVICE_ID 5 /* Headset profile. */ +#define BTA_HFP_SERVICE_ID 6 /* Hands-free profile. */ +#define BTA_OPP_SERVICE_ID 7 /* Object push */ +#define BTA_FTP_SERVICE_ID 8 /* File transfer */ +#define BTA_CTP_SERVICE_ID 9 /* Cordless Terminal */ +#define BTA_ICP_SERVICE_ID 10 /* Intercom Terminal */ +#define BTA_SYNC_SERVICE_ID 11 /* Synchronization */ +#define BTA_BPP_SERVICE_ID 12 /* Basic printing profile */ +#define BTA_BIP_SERVICE_ID 13 /* Basic Imaging profile */ +#define BTA_PANU_SERVICE_ID 14 /* PAN User */ +#define BTA_NAP_SERVICE_ID 15 /* PAN Network access point */ +#define BTA_GN_SERVICE_ID 16 /* PAN Group Ad-hoc networks */ +#define BTA_SAP_SERVICE_ID 17 /* SIM Access profile */ +#define BTA_A2DP_SINK_SERVICE_ID 18 /* A2DP Sink */ +#define BTA_AVRCP_SERVICE_ID 19 /* A/V remote control */ +#define BTA_HID_SERVICE_ID 20 /* HID */ +#define BTA_VDP_SERVICE_ID 21 /* Video distribution */ +#define BTA_PBAP_SERVICE_ID 22 /* PhoneBook Access Server*/ +#define BTA_HSP_HS_SERVICE_ID 23 /* HFP HS role */ +#define BTA_HFP_HS_SERVICE_ID 24 /* HSP HS role */ +#define BTA_MAP_SERVICE_ID 25 /* Message Access Profile */ +#define BTA_MN_SERVICE_ID 26 /* Message Notification Service */ +#define BTA_HDP_SERVICE_ID 27 /* Health Device Profile */ +#define BTA_PCE_SERVICE_ID 28 /* PhoneBook Access Client*/ +#define BTA_SDP_SERVICE_ID 29 /* SDP Search*/ +#if BLE_INCLUDED == TRUE && BTA_GATT_INCLUDED == TRUE +/* BLE profile service ID */ +#define BTA_BLE_SERVICE_ID 30 /* GATT profile */ + +// btla-specific ++ +#define BTA_USER_SERVICE_ID 31 /* User requested UUID */ + +#define BTA_MAX_SERVICE_ID 32 +// btla-specific -- +#else +#define BTA_USER_SERVICE_ID 30 /* User requested UUID */ +#define BTA_MAX_SERVICE_ID 31 +#endif +/* service IDs (BTM_SEC_SERVICE_FIRST_EMPTY + 1) to (BTM_SEC_MAX_SERVICES - 1) + * are used by BTA JV */ +#define BTA_FIRST_JV_SERVICE_ID (BTM_SEC_SERVICE_FIRST_EMPTY + 1) +#define BTA_LAST_JV_SERVICE_ID (BTM_SEC_MAX_SERVICES - 1) + +typedef UINT8 tBTA_SERVICE_ID; + +/* Service ID Mask */ +#define BTA_RES_SERVICE_MASK 0x00000001 /* Reserved */ +#define BTA_SPP_SERVICE_MASK 0x00000002 /* Serial port profile. */ +#define BTA_DUN_SERVICE_MASK 0x00000004 /* Dial-up networking profile. */ +#define BTA_FAX_SERVICE_MASK 0x00000008 /* Fax profile. */ +#define BTA_LAP_SERVICE_MASK 0x00000010 /* LAN access profile. */ +#define BTA_HSP_SERVICE_MASK 0x00000020 /* HSP AG role. */ +#define BTA_HFP_SERVICE_MASK 0x00000040 /* HFP AG role */ +#define BTA_OPP_SERVICE_MASK 0x00000080 /* Object push */ +#define BTA_FTP_SERVICE_MASK 0x00000100 /* File transfer */ +#define BTA_CTP_SERVICE_MASK 0x00000200 /* Cordless Terminal */ +#define BTA_ICP_SERVICE_MASK 0x00000400 /* Intercom Terminal */ +#define BTA_SYNC_SERVICE_MASK 0x00000800 /* Synchronization */ +#define BTA_BPP_SERVICE_MASK 0x00001000 /* Print server */ +#define BTA_BIP_SERVICE_MASK 0x00002000 /* Basic Imaging */ +#define BTA_PANU_SERVICE_MASK 0x00004000 /* PAN User */ +#define BTA_NAP_SERVICE_MASK 0x00008000 /* PAN Network access point */ +#define BTA_GN_SERVICE_MASK 0x00010000 /* PAN Group Ad-hoc networks */ +#define BTA_SAP_SERVICE_MASK 0x00020000 /* PAN Group Ad-hoc networks */ +#define BTA_A2DP_SERVICE_MASK 0x00040000 /* Advanced audio distribution */ +#define BTA_AVRCP_SERVICE_MASK 0x00080000 /* A/V remote control */ +#define BTA_HID_SERVICE_MASK 0x00100000 /* HID */ +#define BTA_VDP_SERVICE_MASK 0x00200000 /* Video distribution */ +#define BTA_PBAP_SERVICE_MASK 0x00400000 /* Phone Book Server */ +#define BTA_HSP_HS_SERVICE_MASK 0x00800000 /* HFP HS role */ +#define BTA_HFP_HS_SERVICE_MASK 0x01000000 /* HSP HS role */ +#define BTA_MAS_SERVICE_MASK 0x02000000 /* Message Access Profile */ +#define BTA_MN_SERVICE_MASK 0x04000000 /* Message Notification Profile */ +#define BTA_HL_SERVICE_MASK 0x08000000 /* Health Device Profile */ +#define BTA_PCE_SERVICE_MASK 0x10000000 /* Phone Book Client */ + +#if BLE_INCLUDED == TRUE && BTA_GATT_INCLUDED == TRUE +#define BTA_BLE_SERVICE_MASK 0x20000000 /* GATT based service */ +// btla-specific ++ +#define BTA_USER_SERVICE_MASK 0x40000000 /* Message Notification Profile */ +// btla-specific -- +#else +// btla-specific ++ +#define BTA_USER_SERVICE_MASK 0x20000000 /* Message Notification Profile */ +// btla-specific -- +#endif + +#if BLE_INCLUDED == TRUE && BTA_GATT_INCLUDED == TRUE +#define BTA_ALL_SERVICE_MASK 0x3FFFFFFF /* All services supported by BTA. */ +#else +#define BTA_ALL_SERVICE_MASK 0x1FFFFFFF /* All services supported by BTA. */ +#endif + +typedef UINT32 tBTA_SERVICE_MASK; + +/* extended service mask, including mask with one or more GATT UUID */ +typedef struct +{ + tBTA_SERVICE_MASK srvc_mask; + UINT8 num_uuid; + tBT_UUID *p_uuid; +}tBTA_SERVICE_MASK_EXT; + +/* Security Setting Mask */ +#define BTA_SEC_NONE BTM_SEC_NONE /* No security. */ +#define BTA_SEC_AUTHORIZE (BTM_SEC_IN_AUTHORIZE ) /* Authorization required (only needed for out going connection )*/ +#define BTA_SEC_AUTHENTICATE (BTM_SEC_IN_AUTHENTICATE | BTM_SEC_OUT_AUTHENTICATE) /* Authentication required. */ +#define BTA_SEC_ENCRYPT (BTM_SEC_IN_ENCRYPT | BTM_SEC_OUT_ENCRYPT) /* Encryption required. */ +#define BTA_SEC_MODE4_LEVEL4 (BTM_SEC_MODE4_LEVEL4) /* Mode 4 level 4 service, i.e. incoming/outgoing MITM and P-256 encryption */ +#define BTA_SEC_MITM (BTM_SEC_IN_MITM | BTM_SEC_OUT_MITM) /* Man-In-The_Middle protection */ +#define BTA_SEC_IN_16_DIGITS (BTM_SEC_IN_MIN_16_DIGIT_PIN) /* Min 16 digit for pin code */ + +typedef UINT16 tBTA_SEC; + +/* Ignore for Discoverable, Connectable, Pairable and Connectable Paired only device modes */ +#define BTA_DM_IGNORE 0x00FF + +/* Ignore for Discoverable, Connectable only for LE modes */ +#define BTA_DM_LE_IGNORE 0xFF00 + +#define BTA_APP_ID_PAN_MULTI 0xFE /* app id for pan multiple connection */ +#define BTA_ALL_APP_ID 0xFF + +/* Discoverable Modes */ +#define BTA_DM_NON_DISC BTM_NON_DISCOVERABLE /* Device is not discoverable. */ +#define BTA_DM_GENERAL_DISC BTM_GENERAL_DISCOVERABLE /* General discoverable. */ +#define BTA_DM_LIMITED_DISC BTM_LIMITED_DISCOVERABLE /* Limited discoverable. */ +#if ((defined BLE_INCLUDED) && (BLE_INCLUDED == TRUE)) +#define BTA_DM_BLE_NON_DISCOVERABLE BTM_BLE_NON_DISCOVERABLE /* Device is not LE discoverable */ +#define BTA_DM_BLE_GENERAL_DISCOVERABLE BTM_BLE_GENERAL_DISCOVERABLE /* Device is LE General discoverable */ +#define BTA_DM_BLE_LIMITED_DISCOVERABLE BTM_BLE_LIMITED_DISCOVERABLE /* Device is LE Limited discoverable */ +#endif +typedef UINT16 tBTA_DM_DISC; /* this discoverability mode is a bit mask among BR mode and LE mode */ + +/* Connectable Modes */ +#define BTA_DM_NON_CONN BTM_NON_CONNECTABLE /* Device is not connectable. */ +#define BTA_DM_CONN BTM_CONNECTABLE /* Device is connectable. */ +#if ((defined BLE_INCLUDED) && (BLE_INCLUDED == TRUE)) +#define BTA_DM_BLE_NON_CONNECTABLE BTM_BLE_NON_CONNECTABLE /* Device is LE non-connectable. */ +#define BTA_DM_BLE_CONNECTABLE BTM_BLE_CONNECTABLE /* Device is LE connectable. */ +#endif + +// btla-specific ++ +typedef UINT16 tBTA_DM_CONN; + +#define BTA_TRANSPORT_UNKNOWN 0 +#define BTA_TRANSPORT_BR_EDR BT_TRANSPORT_BR_EDR +#define BTA_TRANSPORT_LE BT_TRANSPORT_LE +typedef tBT_TRANSPORT tBTA_TRANSPORT; + +/* Pairable Modes */ +#define BTA_DM_PAIRABLE 1 +#define BTA_DM_NON_PAIRABLE 0 + +/* Connectable Paired Only Mode */ +#define BTA_DM_CONN_ALL 0 +#define BTA_DM_CONN_PAIRED 1 + +/* Inquiry Modes */ +#define BTA_DM_INQUIRY_NONE BTM_INQUIRY_NONE /*No BR inquiry. */ +#define BTA_DM_GENERAL_INQUIRY BTM_GENERAL_INQUIRY /* Perform general inquiry. */ +#define BTA_DM_LIMITED_INQUIRY BTM_LIMITED_INQUIRY /* Perform limited inquiry. */ + +#if ((defined BLE_INCLUDED) && (BLE_INCLUDED == TRUE)) +#define BTA_BLE_INQUIRY_NONE BTM_BLE_INQUIRY_NONE +#define BTA_BLE_GENERAL_INQUIRY BTM_BLE_GENERAL_INQUIRY /* Perform LE general inquiry. */ +#define BTA_BLE_LIMITED_INQUIRY BTM_BLE_LIMITED_INQUIRY /* Perform LE limited inquiry. */ +#endif +typedef UINT8 tBTA_DM_INQ_MODE; + +/* Inquiry Filter Type */ +#define BTA_DM_INQ_CLR BTM_CLR_INQUIRY_FILTER /* Clear inquiry filter. */ +#define BTA_DM_INQ_DEV_CLASS BTM_FILTER_COND_DEVICE_CLASS /* Filter on device class. */ +#define BTA_DM_INQ_BD_ADDR BTM_FILTER_COND_BD_ADDR /* Filter on a specific BD address. */ + +typedef UINT8 tBTA_DM_INQ_FILT; + +/* Authorize Response */ +#define BTA_DM_AUTH_PERM 0 /* Authorized for future connections to the service */ +#define BTA_DM_AUTH_TEMP 1 /* Authorized for current connection only */ +#define BTA_DM_NOT_AUTH 2 /* Not authorized for the service */ + +typedef UINT8 tBTA_AUTH_RESP; + +/* M/S preferred roles */ +#define BTA_ANY_ROLE 0x00 +#define BTA_MASTER_ROLE_PREF 0x01 +#define BTA_MASTER_ROLE_ONLY 0x02 +#define BTA_SLAVE_ROLE_ONLY 0x03 /* Used for PANU only, skip role switch to master */ + +typedef UINT8 tBTA_PREF_ROLES; + +enum +{ + + BTA_DM_NO_SCATTERNET, /* Device doesn't support scatternet, it might + support "role switch during connection" for + an incoming connection, when it already has + another connection in master role */ + BTA_DM_PARTIAL_SCATTERNET, /* Device supports partial scatternet. It can have + simulateous connection in Master and Slave roles + for short period of time */ + BTA_DM_FULL_SCATTERNET /* Device can have simultaneous connection in master + and slave roles */ + +}; + + +/* Inquiry filter device class condition */ +typedef struct +{ + DEV_CLASS dev_class; /* device class of interest */ + DEV_CLASS dev_class_mask; /* mask to determine the bits of device class of interest */ +} tBTA_DM_COD_COND; + + +/* Inquiry Filter Condition */ +typedef union +{ + BD_ADDR bd_addr; /* BD address of device to filter. */ + tBTA_DM_COD_COND dev_class_cond; /* Device class filter condition */ +} tBTA_DM_INQ_COND; + +/* Inquiry Parameters */ +typedef struct +{ + tBTA_DM_INQ_MODE mode; /* Inquiry mode, limited or general. */ + UINT8 duration; /* Inquiry duration in 1.28 sec units. */ + UINT8 max_resps; /* Maximum inquiry responses. Set to zero for unlimited responses. */ + BOOLEAN report_dup; /* report duplicated inquiry response with higher RSSI value */ + tBTA_DM_INQ_FILT filter_type; /* Filter condition type. */ + tBTA_DM_INQ_COND filter_cond; /* Filter condition data. */ +#if (defined(BTA_HOST_INTERLEAVE_SEARCH) && BTA_HOST_INTERLEAVE_SEARCH == TRUE) + UINT8 intl_duration[4];/*duration array storing the interleave scan's time portions*/ +#endif +} tBTA_DM_INQ; + +typedef struct +{ + UINT8 bta_dm_eir_min_name_len; /* minimum length of local name when it is shortened */ +#if (BTA_EIR_CANNED_UUID_LIST == TRUE) + UINT8 bta_dm_eir_uuid16_len; /* length of 16-bit UUIDs */ + UINT8 *bta_dm_eir_uuid16; /* 16-bit UUIDs */ +#else + UINT32 uuid_mask[BTM_EIR_SERVICE_ARRAY_SIZE]; /* mask of UUID list in EIR */ +#endif + INT8 *bta_dm_eir_inq_tx_power; /* Inquiry TX power */ + UINT8 bta_dm_eir_flag_len; /* length of flags in bytes */ + UINT8 *bta_dm_eir_flags; /* flags for EIR */ + UINT8 bta_dm_eir_manufac_spec_len; /* length of manufacturer specific in bytes */ + UINT8 *bta_dm_eir_manufac_spec; /* manufacturer specific */ + UINT8 bta_dm_eir_additional_len; /* length of additional data in bytes */ + UINT8 *bta_dm_eir_additional; /* additional data */ +} tBTA_DM_EIR_CONF; + +#if BLE_INCLUDED == TRUE +/* ADV data flag bit definition used for BTM_BLE_AD_TYPE_FLAG */ +#define BTA_BLE_LIMIT_DISC_FLAG BTM_BLE_LIMIT_DISC_FLAG +#define BTA_BLE_GEN_DISC_FLAG BTM_BLE_GEN_DISC_FLAG +#define BTA_BLE_BREDR_NOT_SPT BTM_BLE_BREDR_NOT_SPT +#define BTA_BLE_DMT_CONTROLLER_SPT BTM_BLE_DMT_CONTROLLER_SPT +#define BTA_BLE_DMT_HOST_SPT BTM_BLE_DMT_HOST_SPT +#define BTA_BLE_NON_LIMIT_DISC_FLAG BTM_BLE_NON_LIMIT_DISC_FLAG +#define BTA_BLE_ADV_FLAG_MASK BTM_BLE_ADV_FLAG_MASK +#define BTA_BLE_LIMIT_DISC_MASK BTM_BLE_LIMIT_DISC_MASK + +/* ADV data bit mask */ +#define BTA_BLE_AD_BIT_DEV_NAME BTM_BLE_AD_BIT_DEV_NAME +#define BTA_BLE_AD_BIT_FLAGS BTM_BLE_AD_BIT_FLAGS +#define BTA_BLE_AD_BIT_MANU BTM_BLE_AD_BIT_MANU +#define BTA_BLE_AD_BIT_TX_PWR BTM_BLE_AD_BIT_TX_PWR +#define BTA_BLE_AD_BIT_INT_RANGE BTM_BLE_AD_BIT_INT_RANGE +#define BTA_BLE_AD_BIT_SERVICE BTM_BLE_AD_BIT_SERVICE +#define BTA_BLE_AD_BIT_APPEARANCE BTM_BLE_AD_BIT_APPEARANCE +#define BTA_BLE_AD_BIT_PROPRIETARY BTM_BLE_AD_BIT_PROPRIETARY +#define BTA_DM_BLE_AD_BIT_SERVICE_SOL BTM_BLE_AD_BIT_SERVICE_SOL +#define BTA_DM_BLE_AD_BIT_SERVICE_DATA BTM_BLE_AD_BIT_SERVICE_DATA +#define BTA_DM_BLE_AD_BIT_SIGN_DATA BTM_BLE_AD_BIT_SIGN_DATA +#define BTA_DM_BLE_AD_BIT_SERVICE_128SOL BTM_BLE_AD_BIT_SERVICE_128SOL +#define BTA_DM_BLE_AD_BIT_PUBLIC_ADDR BTM_BLE_AD_BIT_PUBLIC_ADDR +#define BTA_DM_BLE_AD_BIT_RANDOM_ADDR BTM_BLE_AD_BIT_RANDOM_ADDR +#define BTA_DM_BLE_AD_BIT_SERVICE_128 BTM_BLE_AD_BIT_SERVICE_128 /*128-bit Service UUIDs*/ + +typedef tBTM_BLE_AD_MASK tBTA_BLE_AD_MASK; + +/* slave preferred connection interval range */ +typedef struct +{ + UINT16 low; + UINT16 hi; + +}tBTA_BLE_INT_RANGE; + +/* Service tag supported in the device */ +typedef struct +{ + UINT8 num_service; + BOOLEAN list_cmpl; + UINT16 *p_uuid; +}tBTA_BLE_SERVICE; + + +typedef struct +{ + UINT8 len; + UINT8 *p_val; +}tBTA_BLE_MANU; + +typedef struct +{ + UINT8 adv_type; + UINT8 len; + UINT8 *p_val; /* number of len byte */ +}tBTA_BLE_PROP_ELEM; + +/* vendor proprietary adv type */ +typedef struct +{ + UINT8 num_elem; + tBTA_BLE_PROP_ELEM *p_elem; +}tBTA_BLE_PROPRIETARY; + +typedef struct +{ + tBT_UUID service_uuid; + UINT8 len; + UINT8 *p_val; +}tBTA_BLE_SERVICE_DATA; + +typedef tBTM_BLE_128SERVICE tBTA_BLE_128SERVICE; +typedef tBTM_BLE_32SERVICE tBTA_BLE_32SERVICE; + +typedef struct +{ + tBTA_BLE_INT_RANGE int_range; /* slave prefered conn interval range */ + tBTA_BLE_MANU *p_manu; /* manufacturer data */ + tBTA_BLE_SERVICE *p_services; /* 16 bits services */ + tBTA_BLE_128SERVICE *p_services_128b; /* 128 bits service */ + tBTA_BLE_32SERVICE *p_service_32b; /* 32 bits Service UUID */ + tBTA_BLE_SERVICE *p_sol_services; /* 16 bits services Solicitation UUIDs */ + tBTA_BLE_32SERVICE *p_sol_service_32b; /* List of 32 bit Service Solicitation UUIDs */ + tBTA_BLE_128SERVICE *p_sol_service_128b;/* List of 128 bit Service Solicitation UUIDs */ + tBTA_BLE_PROPRIETARY *p_proprietary; /* proprietary data */ + tBTA_BLE_SERVICE_DATA *p_service_data; /* service data */ + UINT16 appearance; /* appearance data */ + UINT8 flag; + UINT8 tx_power; +}tBTA_BLE_ADV_DATA; + +typedef void (tBTA_SET_ADV_DATA_CMPL_CBACK) (tBTA_STATUS status); + +/* advertising channel map */ +#define BTA_BLE_ADV_CHNL_37 BTM_BLE_ADV_CHNL_37 +#define BTA_BLE_ADV_CHNL_38 BTM_BLE_ADV_CHNL_38 +#define BTA_BLE_ADV_CHNL_39 BTM_BLE_ADV_CHNL_39 +typedef tBTM_BLE_ADV_CHNL_MAP tBTA_BLE_ADV_CHNL_MAP; /* use as a bit mask */ + +/* advertising filter policy */ +typedef tBTM_BLE_AFP tBTA_BLE_AFP; + +/* adv event type */ +#define BTA_BLE_CONNECT_EVT BTM_BLE_CONNECT_EVT /* Connectable undirected advertising */ +#define BTA_BLE_CONNECT_DIR_EVT BTM_BLE_CONNECT_DIR_EVT /* Connectable directed advertising */ +#define BTA_BLE_DISCOVER_EVT BTM_BLE_DISCOVER_EVT /* Scannable undirected advertising */ +#define BTA_BLE_NON_CONNECT_EVT BTM_BLE_NON_CONNECT_EVT /* Non connectable undirected advertising */ +typedef UINT8 tBTA_BLE_ADV_EVT; + +/* adv tx power level */ +#define BTA_BLE_ADV_TX_POWER_MIN 0 /* minimum tx power */ +#define BTA_BLE_ADV_TX_POWER_LOW 1 /* low tx power */ +#define BTA_BLE_ADV_TX_POWER_MID 2 /* middle tx power */ +#define BTA_BLE_ADV_TX_POWER_UPPER 3 /* upper tx power */ +#define BTA_BLE_ADV_TX_POWER_MAX 4 /* maximum tx power */ +typedef UINT8 tBTA_BLE_ADV_TX_POWER; + +/* advertising instance parameters */ +typedef struct +{ + UINT16 adv_int_min; /* minimum adv interval */ + UINT16 adv_int_max; /* maximum adv interval */ + tBTA_BLE_ADV_EVT adv_type; /* adv event type */ + tBTA_BLE_ADV_CHNL_MAP channel_map; /* adv channel map */ + tBTA_BLE_AFP adv_filter_policy; /* advertising filter policy */ + tBTA_BLE_ADV_TX_POWER tx_power; /* adv tx power */ +}tBTA_BLE_ADV_PARAMS; + +/* These are the fields returned in each device adv packet. It +** is returned in the results callback if registered. +*/ +typedef struct +{ + UINT8 conn_mode; + tBTA_BLE_AD_MASK ad_mask; /* mask of the valid adv data field */ + UINT8 flag; + UINT8 tx_power_level; + UINT8 remote_name_len; + UINT8 *p_remote_name; + tBTA_BLE_SERVICE service; +} tBTA_BLE_INQ_DATA; + +enum +{ + BTA_BLE_BATCH_SCAN_MODE_PASS = 1, + BTA_BLE_BATCH_SCAN_MODE_ACTI = 2, + BTA_BLE_BATCH_SCAN_MODE_PASS_ACTI = 3 +}; +typedef UINT8 tBTA_BLE_BATCH_SCAN_MODE; + +enum +{ + BTA_BLE_DISCARD_OLD_ITEMS=0, + BTA_BLE_DISCARD_LOWER_RSSI_ITEMS=1 +}; +typedef UINT8 tBTA_BLE_DISCARD_RULE; + +enum +{ + BTA_BLE_ADV_SEEN_FIRST_TIME=0, + BTA_BLE_ADV_TRACKING_TIMEOUT=1 +}; +typedef UINT8 tBTA_BLE_ADV_CHANGE_REASON; + +enum +{ + BTA_BLE_BATCH_SCAN_ENB_EVT = 1, + BTA_BLE_BATCH_SCAN_CFG_STRG_EVT = 2, + BTA_BLE_BATCH_SCAN_DATA_EVT = 3, + BTA_BLE_BATCH_SCAN_THRES_EVT = 4, + BTA_BLE_BATCH_SCAN_PARAM_EVT = 5, + BTA_BLE_BATCH_SCAN_DIS_EVT = 6 +}; +typedef tBTM_BLE_BATCH_SCAN_EVT tBTA_BLE_BATCH_SCAN_EVT; + +typedef tBTM_BLE_TRACK_ADV_ACTION tBTA_BLE_TRACK_ADV_ACTION; +#endif + +/* BLE customer specific feature function type definitions */ +/* data type used on customer specific feature for RSSI monitoring */ +#define BTA_BLE_RSSI_ALERT_HI 0 +#define BTA_BLE_RSSI_ALERT_RANGE 1 +#define BTA_BLE_RSSI_ALERT_LO 2 +typedef UINT8 tBTA_DM_BLE_RSSI_ALERT_TYPE; + +#define BTA_BLE_RSSI_ALERT_NONE BTM_BLE_RSSI_ALERT_NONE /* (0) */ +#define BTA_BLE_RSSI_ALERT_HI_BIT BTM_BLE_RSSI_ALERT_HI_BIT /* (1) */ +#define BTA_BLE_RSSI_ALERT_RANGE_BIT BTM_BLE_RSSI_ALERT_RANGE_BIT /* (1 << 1) */ +#define BTA_BLE_RSSI_ALERT_LO_BIT BTM_BLE_RSSI_ALERT_LO_BIT /* (1 << 2) */ +typedef UINT8 tBTA_DM_BLE_RSSI_ALERT_MASK; + + +typedef void (tBTA_DM_BLE_RSSI_CBACK) (BD_ADDR bd_addr, tBTA_DM_BLE_RSSI_ALERT_TYPE alert_type, INT8 rssi); + +/* max number of filter spot for different filter type */ +#define BTA_DM_BLE_MAX_UUID_FILTER BTM_BLE_MAX_UUID_FILTER /* 8 */ +#define BTA_DM_BLE_MAX_ADDR_FILTER BTM_BLE_MAX_ADDR_FILTER /* 8 */ +#define BTA_DM_BLE_PF_STR_COND_MAX BTM_BLE_PF_STR_COND_MAX /* 4 apply to manu data , or local name */ +#define BTA_DM_BLE_PF_STR_LEN_MAX BTM_BLE_PF_STR_LEN_MAX /* match for first 20 bytes */ + +#define BTA_DM_BLE_PF_LOGIC_OR 0 +#define BTA_DM_BLE_PF_LOGIC_AND 1 +typedef UINT8 tBTA_DM_BLE_PF_LOGIC_TYPE; + +enum +{ + BTA_DM_BLE_SCAN_COND_ADD, + BTA_DM_BLE_SCAN_COND_DELETE, + BTA_DM_BLE_SCAN_COND_CLEAR = 2 +}; +typedef UINT8 tBTA_DM_BLE_SCAN_COND_OP; + +/* ADV payload filtering vendor specific call event */ +enum +{ + BTA_BLE_SCAN_PF_ENABLE_EVT = 7, + BTA_BLE_SCAN_PF_COND_EVT +}; + +/* filter selection bit index */ +#define BTA_DM_BLE_PF_ADDR_FILTER BTM_BLE_PF_ADDR_FILTER +#define BTA_DM_BLE_PF_SRVC_DATA BTM_BLE_PF_SRVC_DATA +#define BTA_DM_BLE_PF_SRVC_UUID BTM_BLE_PF_SRVC_UUID +#define BTA_DM_BLE_PF_SRVC_SOL_UUID BTM_BLE_PF_SRVC_SOL_UUID +#define BTA_DM_BLE_PF_LOCAL_NAME BTM_BLE_PF_LOCAL_NAME +#define BTA_DM_BLE_PF_MANU_DATA BTM_BLE_PF_MANU_DATA +#define BTA_DM_BLE_PF_SRVC_DATA_PATTERN BTM_BLE_PF_SRVC_DATA_PATTERN +#define BTA_DM_BLE_PF_TYPE_ALL BTM_BLE_PF_TYPE_ALL +#define BTA_DM_BLE_PF_TYPE_MAX BTM_BLE_PF_TYPE_MAX +typedef UINT8 tBTA_DM_BLE_PF_COND_TYPE; + +typedef union +{ + UINT16 uuid16_mask; + UINT32 uuid32_mask; + UINT8 uuid128_mask[LEN_UUID_128]; +}tBTA_DM_BLE_PF_COND_MASK; + +typedef struct +{ + tBLE_BD_ADDR *p_target_addr; /* target address, if NULL, generic UUID filter */ + tBT_UUID uuid; /* UUID condition */ + tBTA_DM_BLE_PF_LOGIC_TYPE cond_logic; /* AND/OR */ + tBTA_DM_BLE_PF_COND_MASK *p_uuid_mask; /* UUID condition mask, if NULL, match exact as UUID condition */ +}tBTA_DM_BLE_PF_UUID_COND; + +typedef struct +{ + UINT8 data_len; /* <= 20 bytes */ + UINT8 *p_data; +}tBTA_DM_BLE_PF_LOCAL_NAME_COND; + +typedef struct +{ + UINT16 company_id; /* company ID */ + UINT8 data_len; /* <= 20 bytes */ + UINT8 *p_pattern; + UINT16 company_id_mask; /* UUID value mask */ + UINT8 *p_pattern_mask; /* Manufacturer data matching mask, same length + as data pattern, set to all 0xff, match exact data */ +}tBTA_DM_BLE_PF_MANU_COND; + +typedef struct +{ + UINT16 uuid; /* service ID */ + UINT8 data_len; /* <= 20 bytes */ + UINT8 *p_pattern; + UINT8 *p_pattern_mask; /* Service data matching mask, same length + as data pattern, set to all 0xff, match exact data */ +}tBTA_DM_BLE_PF_SRVC_PATTERN_COND; + +typedef union +{ + tBLE_BD_ADDR target_addr; + tBTA_DM_BLE_PF_LOCAL_NAME_COND local_name; /* lcoal name filtering */ + tBTA_DM_BLE_PF_MANU_COND manu_data; /* manufactuer data filtering */ + tBTA_DM_BLE_PF_UUID_COND srvc_uuid; /* service UUID filtering */ + tBTA_DM_BLE_PF_UUID_COND solicitate_uuid; /* solicitated service UUID filtering */ + tBTA_DM_BLE_PF_SRVC_PATTERN_COND srvc_data; /* service data pattern */ +}tBTA_DM_BLE_PF_COND_PARAM; + +typedef UINT8 tBTA_DM_BLE_PF_FILT_INDEX; +typedef UINT8 tBTA_DM_BLE_PF_AVBL_SPACE; + +typedef INT8 tBTA_DM_RSSI_VALUE; +typedef UINT8 tBTA_DM_LINK_QUALITY_VALUE; + + +typedef UINT8 tBTA_SIG_STRENGTH_MASK; + + +/* Security Callback Events */ +#define BTA_DM_ENABLE_EVT 0 /* Enable Event */ +#define BTA_DM_DISABLE_EVT 1 /* Disable Event */ +#define BTA_DM_PIN_REQ_EVT 2 /* PIN request. */ +#define BTA_DM_AUTH_CMPL_EVT 3 /* Authentication complete indication. */ +#define BTA_DM_AUTHORIZE_EVT 4 /* Authorization request. */ +#define BTA_DM_LINK_UP_EVT 5 /* Connection UP event */ +#define BTA_DM_LINK_DOWN_EVT 6 /* Connection DOWN event */ +#define BTA_DM_SIG_STRENGTH_EVT 7 /* Signal strength for bluetooth connection */ +#define BTA_DM_BUSY_LEVEL_EVT 8 /* System busy level */ +#define BTA_DM_BOND_CANCEL_CMPL_EVT 9 /* Bond cancel complete indication */ +#define BTA_DM_SP_CFM_REQ_EVT 10 /* Simple Pairing User Confirmation request. */ +#define BTA_DM_SP_KEY_NOTIF_EVT 11 /* Simple Pairing Passkey Notification */ +#define BTA_DM_SP_RMT_OOB_EVT 12 /* Simple Pairing Remote OOB Data request. */ +#define BTA_DM_SP_KEYPRESS_EVT 13 /* Key press notification event. */ +#define BTA_DM_ROLE_CHG_EVT 14 /* Role Change event. */ +#define BTA_DM_BLE_KEY_EVT 15 /* BLE SMP key event for peer device keys */ +#define BTA_DM_BLE_SEC_REQ_EVT 16 /* BLE SMP security request */ +#define BTA_DM_BLE_PASSKEY_NOTIF_EVT 17 /* SMP passkey notification event */ +#define BTA_DM_BLE_PASSKEY_REQ_EVT 18 /* SMP passkey request event */ +#define BTA_DM_BLE_OOB_REQ_EVT 19 /* SMP OOB request event */ +#define BTA_DM_BLE_LOCAL_IR_EVT 20 /* BLE local IR event */ +#define BTA_DM_BLE_LOCAL_ER_EVT 21 /* BLE local ER event */ +#define BTA_DM_BLE_NC_REQ_EVT 22 /* SMP Numeric Comparison request event */ +// btla-specific ++ +#define BTA_DM_SP_RMT_OOB_EXT_EVT 23 /* Simple Pairing Remote OOB Extended Data request. */ +#define BTA_DM_BLE_AUTH_CMPL_EVT 24 /* BLE Auth complete */ +// btla-specific -- +#define BTA_DM_DEV_UNPAIRED_EVT 25 +#define BTA_DM_HW_ERROR_EVT 26 /* BT Chip H/W error */ +#define BTA_DM_LE_FEATURES_READ 27 /* Cotroller specific LE features are read */ +#define BTA_DM_ENER_INFO_READ 28 /* Energy info read */ +typedef UINT8 tBTA_DM_SEC_EVT; + +/* Structure associated with BTA_DM_ENABLE_EVT */ +typedef struct +{ + tBTA_STATUS status; +} tBTA_DM_ENABLE; + +/* Structure associated with BTA_DM_PIN_REQ_EVT */ +typedef struct +{ + /* Note: First 3 data members must be, bd_addr, dev_class, and bd_name in order */ + BD_ADDR bd_addr; /* BD address peer device. */ + DEV_CLASS dev_class; /* Class of Device */ + BD_NAME bd_name; /* Name of peer device. */ + BOOLEAN min_16_digit; /* TRUE if the pin returned must be at least 16 digits */ +} tBTA_DM_PIN_REQ; + +/* BLE related definition */ + +#define BTA_DM_AUTH_FAIL_BASE (HCI_ERR_MAX_ERR + 10) +#define BTA_DM_AUTH_CONVERT_SMP_CODE(x) (BTA_DM_AUTH_FAIL_BASE + (x)) +#define BTA_DM_AUTH_SMP_PASSKEY_FAIL BTA_DM_AUTH_CONVERT_SMP_CODE (SMP_PASSKEY_ENTRY_FAIL) +#define BTA_DM_AUTH_SMP_OOB_FAIL (BTA_DM_AUTH_FAIL_BASE + SMP_OOB_FAIL) +#define BTA_DM_AUTH_SMP_PAIR_AUTH_FAIL (BTA_DM_AUTH_FAIL_BASE + SMP_PAIR_AUTH_FAIL) +#define BTA_DM_AUTH_SMP_CONFIRM_VALUE_FAIL (BTA_DM_AUTH_FAIL_BASE + SMP_CONFIRM_VALUE_ERR) +#define BTA_DM_AUTH_SMP_PAIR_NOT_SUPPORT (BTA_DM_AUTH_FAIL_BASE + SMP_PAIR_NOT_SUPPORT) +#define BTA_DM_AUTH_SMP_ENC_KEY_SIZE (BTA_DM_AUTH_FAIL_BASE + SMP_ENC_KEY_SIZE) +#define BTA_DM_AUTH_SMP_INVALID_CMD (BTA_DM_AUTH_FAIL_BASE + SMP_INVALID_CMD) +#define BTA_DM_AUTH_SMP_UNKNOWN_ERR (BTA_DM_AUTH_FAIL_BASE + SMP_PAIR_FAIL_UNKNOWN) +#define BTA_DM_AUTH_SMP_REPEATED_ATTEMPT (BTA_DM_AUTH_FAIL_BASE + SMP_REPEATED_ATTEMPTS) +#define BTA_DM_AUTH_SMP_INVALID_PARAMETERS (BTA_DM_AUTH_FAIL_BASE + SMP_INVALID_PARAMETERS) +#define BTA_DM_AUTH_SMP_INTERNAL_ERR (BTA_DM_AUTH_FAIL_BASE + SMP_PAIR_INTERNAL_ERR) +#define BTA_DM_AUTH_SMP_UNKNOWN_IO (BTA_DM_AUTH_FAIL_BASE + SMP_UNKNOWN_IO_CAP) +#define BTA_DM_AUTH_SMP_INIT_FAIL (BTA_DM_AUTH_FAIL_BASE + SMP_INIT_FAIL) +#define BTA_DM_AUTH_SMP_CONFIRM_FAIL (BTA_DM_AUTH_FAIL_BASE + SMP_CONFIRM_FAIL) +#define BTA_DM_AUTH_SMP_BUSY (BTA_DM_AUTH_FAIL_BASE + SMP_BUSY) +#define BTA_DM_AUTH_SMP_ENC_FAIL (BTA_DM_AUTH_FAIL_BASE + SMP_ENC_FAIL) +#define BTA_DM_AUTH_SMP_RSP_TIMEOUT (BTA_DM_AUTH_FAIL_BASE + SMP_RSP_TIMEOUT) + +/* connection parameter boundary value and dummy value */ +#define BTA_DM_BLE_SCAN_INT_MIN BTM_BLE_SCAN_INT_MIN +#define BTA_DM_BLE_SCAN_INT_MAX BTM_BLE_SCAN_INT_MAX +#define BTA_DM_BLE_SCAN_WIN_MIN BTM_BLE_SCAN_WIN_MIN +#define BTA_DM_BLE_SCAN_WIN_MAX BTM_BLE_SCAN_WIN_MAX +#define BTA_DM_BLE_CONN_INT_MIN BTM_BLE_CONN_INT_MIN +#define BTA_DM_BLE_CONN_INT_MAX BTM_BLE_CONN_INT_MAX +#define BTA_DM_BLE_CONN_LATENCY_MAX BTM_BLE_CONN_LATENCY_MAX +#define BTA_DM_BLE_CONN_SUP_TOUT_MIN BTM_BLE_CONN_SUP_TOUT_MIN +#define BTA_DM_BLE_CONN_SUP_TOUT_MAX BTM_BLE_CONN_SUP_TOUT_MAX +#define BTA_DM_BLE_CONN_PARAM_UNDEF BTM_BLE_CONN_PARAM_UNDEF /* use this value when a specific value not to be overwritten */ + + +#define BTA_LE_KEY_PENC BTM_LE_KEY_PENC /* encryption information of peer device */ +#define BTA_LE_KEY_PID BTM_LE_KEY_PID /* identity key of the peer device */ +#define BTA_LE_KEY_PCSRK BTM_LE_KEY_PCSRK /* peer SRK */ +#define BTA_LE_KEY_LENC BTM_LE_KEY_LENC /* master role security information:div */ +#define BTA_LE_KEY_LID BTM_LE_KEY_LID /* master device ID key */ +#define BTA_LE_KEY_LCSRK BTM_LE_KEY_LCSRK /* local CSRK has been deliver to peer */ +typedef UINT8 tBTA_LE_KEY_TYPE; /* can be used as a bit mask */ + + +typedef tBTM_LE_PENC_KEYS tBTA_LE_PENC_KEYS ; +typedef tBTM_LE_PCSRK_KEYS tBTA_LE_PCSRK_KEYS; +typedef tBTM_LE_LENC_KEYS tBTA_LE_LENC_KEYS ; +typedef tBTM_LE_LCSRK_KEYS tBTA_LE_LCSRK_KEYS ; +typedef tBTM_LE_PID_KEYS tBTA_LE_PID_KEYS ; + +typedef union +{ + tBTA_LE_PENC_KEYS penc_key; /* received peer encryption key */ + tBTA_LE_PCSRK_KEYS psrk_key; /* received peer device SRK */ + tBTA_LE_PID_KEYS pid_key; /* peer device ID key */ + tBTA_LE_LENC_KEYS lenc_key; /* local encryption reproduction keys LTK = = d1(ER,DIV,0)*/ + tBTA_LE_LCSRK_KEYS lcsrk_key; /* local device CSRK = d1(ER,DIV,1)*/ + tBTA_LE_PID_KEYS lid_key; /* local device ID key for the particular remote */ +}tBTA_LE_KEY_VALUE; + +#define BTA_BLE_LOCAL_KEY_TYPE_ID 1 +#define BTA_BLE_LOCAL_KEY_TYPE_ER 2 +typedef UINT8 tBTA_DM_BLE_LOCAL_KEY_MASK; + +typedef struct +{ + BT_OCTET16 ir; + BT_OCTET16 irk; + BT_OCTET16 dhk; +}tBTA_BLE_LOCAL_ID_KEYS; + +#define BTA_DM_SEC_GRANTED BTA_SUCCESS +#define BTA_DM_SEC_PAIR_NOT_SPT BTA_DM_AUTH_SMP_PAIR_NOT_SUPPORT +#define BTA_DM_SEC_REP_ATTEMPTS BTA_DM_AUTH_SMP_REPEATED_ATTEMPT +typedef UINT8 tBTA_DM_BLE_SEC_GRANT; + + +#define BTA_DM_BLE_ONN_NONE BTM_BLE_CONN_NONE +#define BTA_DM_BLE_CONN_AUTO BTM_BLE_CONN_AUTO +#define BTA_DM_BLE_CONN_SELECTIVE BTM_BLE_CONN_SELECTIVE +typedef UINT8 tBTA_DM_BLE_CONN_TYPE; + +typedef BOOLEAN (tBTA_DM_BLE_SEL_CBACK)(BD_ADDR random_bda, UINT8 *p_remote_name); + +/* Structure associated with BTA_DM_BLE_SEC_REQ_EVT */ +typedef struct +{ + BD_ADDR bd_addr; /* peer address */ + BD_NAME bd_name; /* peer device name */ +} tBTA_DM_BLE_SEC_REQ; + +typedef struct +{ + BD_ADDR bd_addr; /* peer address */ + tBTM_LE_KEY_TYPE key_type; + tBTM_LE_KEY_VALUE *p_key_value; +}tBTA_DM_BLE_KEY; + +/* Structure associated with BTA_DM_AUTH_CMPL_EVT */ +typedef struct +{ + BD_ADDR bd_addr; /* BD address peer device. */ + BD_NAME bd_name; /* Name of peer device. */ + BOOLEAN key_present; /* Valid link key value in key element */ + LINK_KEY key; /* Link key associated with peer device. */ + UINT8 key_type; /* The type of Link Key */ + BOOLEAN success; /* TRUE of authentication succeeded, FALSE if failed. */ + UINT8 fail_reason; /* The HCI reason/error code for when success=FALSE */ + tBLE_ADDR_TYPE addr_type; /* Peer device address type */ + tBT_DEVICE_TYPE dev_type; +} tBTA_DM_AUTH_CMPL; + + +/* Structure associated with BTA_DM_AUTHORIZE_EVT */ +typedef struct +{ + BD_ADDR bd_addr; /* BD address peer device. */ + BD_NAME bd_name; /* Name of peer device. */ + tBTA_SERVICE_ID service; /* Service ID to authorize. */ +// btla-specific ++ + DEV_CLASS dev_class; +// btla-specific -- +} tBTA_DM_AUTHORIZE; + +/* Structure associated with BTA_DM_LINK_UP_EVT */ +typedef struct +{ + BD_ADDR bd_addr; /* BD address peer device. */ +#if BLE_INCLUDED == TRUE + tBTA_TRANSPORT link_type; +#endif +} tBTA_DM_LINK_UP; + +/* Structure associated with BTA_DM_LINK_DOWN_EVT */ +typedef struct +{ + BD_ADDR bd_addr; /* BD address peer device. */ + UINT8 status; /* connection open/closed */ + BOOLEAN is_removed; /* TRUE if device is removed when link is down */ +#if BLE_INCLUDED == TRUE + tBTA_TRANSPORT link_type; +#endif +} tBTA_DM_LINK_DOWN; + +/* Structure associated with BTA_DM_ROLE_CHG_EVT */ +typedef struct +{ + BD_ADDR bd_addr; /* BD address peer device. */ + UINT8 new_role; /* the new connection role */ +} tBTA_DM_ROLE_CHG; + +/* Structure associated with BTA_DM_BUSY_LEVEL_EVT */ +typedef struct +{ + UINT8 level; /* when paging or inquiring, level is 10. + Otherwise, the number of ACL links */ + UINT8 level_flags; /* indicates individual flags */ +} tBTA_DM_BUSY_LEVEL; + +#define BTA_IO_CAP_OUT BTM_IO_CAP_OUT /* 0 DisplayOnly */ +#define BTA_IO_CAP_IO BTM_IO_CAP_IO /* 1 DisplayYesNo */ +#define BTA_IO_CAP_IN BTM_IO_CAP_IN /* 2 KeyboardOnly */ +#define BTA_IO_CAP_NONE BTM_IO_CAP_NONE /* 3 NoInputNoOutput */ +#if BLE_INCLUDED == TRUE && SMP_INCLUDED == TRUE +#define BTA_IO_CAP_KBDISP BTM_IO_CAP_KBDISP /* 4 Keyboard display */ +#endif +typedef tBTM_IO_CAP tBTA_IO_CAP; + +#define BTA_AUTH_SP_NO BTM_AUTH_SP_NO /* 0 MITM Protection Not Required - Single Profile/non-bonding + Numeric comparison with automatic accept allowed */ +#define BTA_AUTH_SP_YES BTM_AUTH_SP_YES /* 1 MITM Protection Required - Single Profile/non-bonding + Use IO Capabilities to determine authentication procedure */ +#define BTA_AUTH_AP_NO BTM_AUTH_AP_NO /* 2 MITM Protection Not Required - All Profiles/dedicated bonding + Numeric comparison with automatic accept allowed */ +#define BTA_AUTH_AP_YES BTM_AUTH_AP_YES /* 3 MITM Protection Required - All Profiles/dedicated bonding + Use IO Capabilities to determine authentication procedure */ +#define BTA_AUTH_SPGB_NO BTM_AUTH_SPGB_NO /* 4 MITM Protection Not Required - Single Profiles/general bonding + Numeric comparison with automatic accept allowed */ +#define BTA_AUTH_SPGB_YES BTM_AUTH_SPGB_YES /* 5 MITM Protection Required - Single Profiles/general bonding + Use IO Capabilities to determine authentication procedure */ +typedef tBTM_AUTH_REQ tBTA_AUTH_REQ; + +#define BTA_AUTH_DD_BOND BTM_AUTH_DD_BOND /* 2 this bit is set for dedicated bonding */ +#define BTA_AUTH_GEN_BOND BTM_AUTH_SPGB_NO /* 4 this bit is set for general bonding */ +#define BTA_AUTH_BONDS BTM_AUTH_BONDS /* 6 the general/dedicated bonding bits */ + +#define BTA_LE_AUTH_NO_BOND BTM_LE_AUTH_REQ_NO_BOND /* 0*/ +#define BTA_LE_AUTH_BOND BTM_LE_AUTH_REQ_BOND /* 1 << 0 */ +#define BTA_LE_AUTH_REQ_MITM BTM_LE_AUTH_REQ_MITM /* 1 << 2 */ + +#define BTA_LE_AUTH_REQ_SC_ONLY BTM_LE_AUTH_REQ_SC_ONLY /* 1 << 3 */ +#define BTA_LE_AUTH_REQ_SC_BOND BTM_LE_AUTH_REQ_SC_BOND /* 1001 */ +#define BTA_LE_AUTH_REQ_SC_MITM BTM_LE_AUTH_REQ_SC_MITM /* 1100 */ +#define BTA_LE_AUTH_REQ_SC_MITM_BOND BTM_LE_AUTH_REQ_SC_MITM_BOND /* 1101 */ +typedef tBTM_LE_AUTH_REQ tBTA_LE_AUTH_REQ; /* combination of the above bit pattern */ + +#define BTA_OOB_NONE BTM_OOB_NONE +#define BTA_OOB_PRESENT BTM_OOB_PRESENT +#if BTM_OOB_INCLUDED == TRUE +#define BTA_OOB_UNKNOWN BTM_OOB_UNKNOWN +#endif +typedef tBTM_OOB_DATA tBTA_OOB_DATA; + +/* Structure associated with BTA_DM_SP_CFM_REQ_EVT */ +typedef struct +{ + /* Note: First 3 data members must be, bd_addr, dev_class, and bd_name in order */ + BD_ADDR bd_addr; /* peer address */ + DEV_CLASS dev_class; /* peer CoD */ + BD_NAME bd_name; /* peer device name */ + UINT32 num_val; /* the numeric value for comparison. If just_works, do not show this number to UI */ + BOOLEAN just_works; /* TRUE, if "Just Works" association model */ + tBTA_AUTH_REQ loc_auth_req; /* Authentication required for local device */ + tBTA_AUTH_REQ rmt_auth_req; /* Authentication required for peer device */ + tBTA_IO_CAP loc_io_caps; /* IO Capabilities of local device */ + tBTA_AUTH_REQ rmt_io_caps; /* IO Capabilities of remote device */ +} tBTA_DM_SP_CFM_REQ; + +enum +{ + BTA_SP_KEY_STARTED, /* passkey entry started */ + BTA_SP_KEY_ENTERED, /* passkey digit entered */ + BTA_SP_KEY_ERASED, /* passkey digit erased */ + BTA_SP_KEY_CLEARED, /* passkey cleared */ + BTA_SP_KEY_COMPLT /* passkey entry completed */ +}; +typedef UINT8 tBTA_SP_KEY_TYPE; + +/* Structure associated with BTA_DM_SP_KEYPRESS_EVT */ +typedef struct +{ + BD_ADDR bd_addr; /* peer address */ + tBTA_SP_KEY_TYPE notif_type; +}tBTA_DM_SP_KEY_PRESS; + +/* Structure associated with BTA_DM_SP_KEY_NOTIF_EVT */ +typedef struct +{ + /* Note: First 3 data members must be, bd_addr, dev_class, and bd_name in order */ + BD_ADDR bd_addr; /* peer address */ + DEV_CLASS dev_class; /* peer CoD */ + BD_NAME bd_name; /* peer device name */ + UINT32 passkey; /* the numeric value for comparison. If just_works, do not show this number to UI */ +} tBTA_DM_SP_KEY_NOTIF; + +/* Structure associated with BTA_DM_SP_RMT_OOB_EVT */ +typedef struct +{ + /* Note: First 3 data members must be, bd_addr, dev_class, and bd_name in order */ + BD_ADDR bd_addr; /* peer address */ + DEV_CLASS dev_class; /* peer CoD */ + BD_NAME bd_name; /* peer device name */ +} tBTA_DM_SP_RMT_OOB; + +/* Structure associated with BTA_DM_BOND_CANCEL_CMPL_EVT */ +typedef struct +{ + tBTA_STATUS result; /* TRUE of bond cancel succeeded, FALSE if failed. */ +} tBTA_DM_BOND_CANCEL_CMPL; + +/* Union of all security callback structures */ +typedef union +{ + tBTA_DM_ENABLE enable; /* BTA enabled */ + tBTA_DM_PIN_REQ pin_req; /* PIN request. */ + tBTA_DM_AUTH_CMPL auth_cmpl; /* Authentication complete indication. */ + tBTA_DM_AUTHORIZE authorize; /* Authorization request. */ + tBTA_DM_LINK_UP link_up; /* ACL connection down event */ + tBTA_DM_LINK_DOWN link_down; /* ACL connection down event */ + tBTA_DM_BUSY_LEVEL busy_level; /* System busy level */ + tBTA_DM_SP_CFM_REQ cfm_req; /* user confirm request */ + tBTA_DM_SP_KEY_NOTIF key_notif; /* passkey notification */ + tBTA_DM_SP_RMT_OOB rmt_oob; /* remote oob */ + tBTA_DM_BOND_CANCEL_CMPL bond_cancel_cmpl; /* Bond Cancel Complete indication */ + tBTA_DM_SP_KEY_PRESS key_press; /* key press notification event */ + tBTA_DM_ROLE_CHG role_chg; /* role change event */ + tBTA_DM_BLE_SEC_REQ ble_req; /* BLE SMP related request */ + tBTA_DM_BLE_KEY ble_key; /* BLE SMP keys used when pairing */ + tBTA_BLE_LOCAL_ID_KEYS ble_id_keys; /* IR event */ + BT_OCTET16 ble_er; /* ER event data */ +} tBTA_DM_SEC; + +/* Security callback */ +typedef void (tBTA_DM_SEC_CBACK)(tBTA_DM_SEC_EVT event, tBTA_DM_SEC *p_data); + +#define BTA_BLE_MULTI_ADV_ILLEGAL 0 + +/* multi adv callback event */ +#define BTA_BLE_MULTI_ADV_ENB_EVT 1 +#define BTA_BLE_MULTI_ADV_DISABLE_EVT 2 +#define BTA_BLE_MULTI_ADV_PARAM_EVT 3 +#define BTA_BLE_MULTI_ADV_DATA_EVT 4 + +typedef UINT8 tBTA_BLE_MULTI_ADV_EVT; + +/* multi adv callback */ +typedef void (tBTA_BLE_MULTI_ADV_CBACK)(tBTA_BLE_MULTI_ADV_EVT event, + UINT8 inst_id, void *p_ref, tBTA_STATUS status); +typedef UINT32 tBTA_DM_BLE_REF_VALUE; + +#define BTA_DM_BLE_PF_ENABLE_EVT BTM_BLE_PF_ENABLE +#define BTA_DM_BLE_PF_CONFIG_EVT BTM_BLE_PF_CONFIG +typedef UINT8 tBTA_DM_BLE_PF_EVT; + +#define BTA_DM_BLE_PF_ENABLE 1 +#define BTA_DM_BLE_PF_CONFIG 2 +typedef UINT8 tBTA_DM_BLE_PF_ACTION; + +/* Config callback */ +typedef void (tBTA_DM_BLE_PF_CFG_CBACK) (tBTA_DM_BLE_PF_ACTION action, + tBTA_DM_BLE_PF_COND_TYPE cfg_cond, + tBTA_DM_BLE_PF_AVBL_SPACE avbl_space, tBTA_STATUS status, + tBTA_DM_BLE_REF_VALUE ref_value); +/* Param callback */ +typedef void (tBTA_DM_BLE_PF_PARAM_CBACK) (UINT8 action_type, tBTA_DM_BLE_PF_AVBL_SPACE avbl_space, + tBTA_DM_BLE_REF_VALUE ref_value, tBTA_STATUS status); + +/* Status callback */ +typedef void (tBTA_DM_BLE_PF_STATUS_CBACK) (UINT8 action, tBTA_STATUS status, + tBTA_DM_BLE_REF_VALUE ref_value); + + +#define BTA_DM_BLE_PF_BRDCAST_ADDR_FILT 1 +#define BTA_DM_BLE_PF_SERV_DATA_CHG_FILT 2 +#define BTA_DM_BLE_PF_SERV_UUID 4 +#define BTA_DM_BLE_PF_SERV_SOLC_UUID 8 +#define BTA_DM_BLE_PF_LOC_NAME_CHECK 16 +#define BTA_DM_BLE_PF_MANUF_NAME_CHECK 32 +#define BTA_DM_BLE_PF_SERV_DATA_CHECK 64 +typedef UINT16 tBTA_DM_BLE_PF_FEAT_SEL; + +#define BTA_DM_BLE_PF_LIST_LOGIC_OR 1 +#define BTA_DM_BLE_PF_LIST_LOGIC_AND 2 +typedef UINT16 tBTA_DM_BLE_PF_LIST_LOGIC_TYPE; + +#define BTA_DM_BLE_PF_FILT_LOGIC_OR 0 +#define BTA_DM_BLE_PF_FILT_LOGIC_AND 1 +typedef UINT16 tBTA_DM_BLE_PF_FILT_LOGIC_TYPE; + +typedef UINT8 tBTA_DM_BLE_PF_RSSI_THRESHOLD; +typedef UINT8 tBTA_DM_BLE_PF_DELIVERY_MODE; +typedef UINT16 tBTA_DM_BLE_PF_TIMEOUT; +typedef UINT8 tBTA_DM_BLE_PF_TIMEOUT_CNT; +typedef UINT16 tBTA_DM_BLE_PF_ADV_TRACK_ENTRIES; + +typedef struct +{ + tBTA_DM_BLE_PF_FEAT_SEL feat_seln; + tBTA_DM_BLE_PF_LIST_LOGIC_TYPE list_logic_type; + tBTA_DM_BLE_PF_FILT_LOGIC_TYPE filt_logic_type; + tBTA_DM_BLE_PF_RSSI_THRESHOLD rssi_high_thres; + tBTA_DM_BLE_PF_RSSI_THRESHOLD rssi_low_thres; + tBTA_DM_BLE_PF_DELIVERY_MODE dely_mode; + tBTA_DM_BLE_PF_TIMEOUT found_timeout; + tBTA_DM_BLE_PF_TIMEOUT lost_timeout; + tBTA_DM_BLE_PF_TIMEOUT_CNT found_timeout_cnt; + tBTA_DM_BLE_PF_ADV_TRACK_ENTRIES num_of_tracking_entries; +} tBTA_DM_BLE_PF_FILT_PARAMS; + +/* Search callback events */ +#define BTA_DM_INQ_RES_EVT 0 /* Inquiry result for a peer device. */ +#define BTA_DM_INQ_CMPL_EVT 1 /* Inquiry complete. */ +#define BTA_DM_DISC_RES_EVT 2 /* Discovery result for a peer device. */ +#define BTA_DM_DISC_BLE_RES_EVT 3 /* Discovery result for BLE GATT based servoce on a peer device. */ +#define BTA_DM_DISC_CMPL_EVT 4 /* Discovery complete. */ +#define BTA_DM_DI_DISC_CMPL_EVT 5 /* Discovery complete. */ +#define BTA_DM_SEARCH_CANCEL_CMPL_EVT 6 /* Search cancelled */ + +typedef UINT8 tBTA_DM_SEARCH_EVT; + +#define BTA_DM_INQ_RES_IGNORE_RSSI BTM_INQ_RES_IGNORE_RSSI /* 0x7f RSSI value not supplied (ignore it) */ + +/* Structure associated with BTA_DM_INQ_RES_EVT */ +typedef struct +{ + BD_ADDR bd_addr; /* BD address peer device. */ + DEV_CLASS dev_class; /* Device class of peer device. */ + BOOLEAN remt_name_not_required; /* Application sets this flag if it already knows the name of the device */ + /* If the device name is known to application BTA skips the remote name request */ + BOOLEAN is_limited; /* TRUE, if the limited inquiry bit is set in the CoD */ + INT8 rssi; /* The rssi value */ + UINT8 *p_eir; /* received EIR */ +#if (BLE_INCLUDED == TRUE) + UINT8 inq_result_type; + UINT8 ble_addr_type; + tBTM_BLE_EVT_TYPE ble_evt_type; + tBT_DEVICE_TYPE device_type; + UINT8 flag; +#endif + +} tBTA_DM_INQ_RES; + +/* Structure associated with BTA_DM_INQ_CMPL_EVT */ +typedef struct +{ + UINT8 num_resps; /* Number of inquiry responses. */ +} tBTA_DM_INQ_CMPL; + +/* Structure associated with BTA_DM_DI_DISC_CMPL_EVT */ +typedef struct +{ + BD_ADDR bd_addr; /* BD address peer device. */ + UINT8 num_record; /* Number of DI record */ + tBTA_STATUS result; +} tBTA_DM_DI_DISC_CMPL; + +/* Structure associated with BTA_DM_DISC_RES_EVT */ +typedef struct +{ + BD_ADDR bd_addr; /* BD address peer device. */ + BD_NAME bd_name; /* Name of peer device. */ + tBTA_SERVICE_MASK services; /* Services found on peer device. */ +// btla-specific ++ + UINT8 * p_raw_data; /* Raw data for discovery DB */ + UINT32 raw_data_size; /* size of raw data */ + tBT_DEVICE_TYPE device_type; /* device type in case it is BLE device */ + UINT32 num_uuids; + UINT8 *p_uuid_list; +// btla-specific -- + tBTA_STATUS result; +} tBTA_DM_DISC_RES; + +/* Structure associated with tBTA_DM_DISC_BLE_RES */ +typedef struct +{ + BD_ADDR bd_addr; /* BD address peer device. */ + BD_NAME bd_name; /* Name of peer device. */ + tBT_UUID service; /* GATT based Services UUID found on peer device. */ +} tBTA_DM_DISC_BLE_RES; + + +/* Union of all search callback structures */ +typedef union +{ + tBTA_DM_INQ_RES inq_res; /* Inquiry result for a peer device. */ + tBTA_DM_INQ_CMPL inq_cmpl; /* Inquiry complete. */ + tBTA_DM_DISC_RES disc_res; /* Discovery result for a peer device. */ + tBTA_DM_DISC_BLE_RES disc_ble_res; /* discovery result for GATT based service */ + tBTA_DM_DI_DISC_CMPL di_disc; /* DI discovery result for a peer device */ + +} tBTA_DM_SEARCH; + +/* Search callback */ +typedef void (tBTA_DM_SEARCH_CBACK)(tBTA_DM_SEARCH_EVT event, tBTA_DM_SEARCH *p_data); + +/* Execute call back */ +typedef void (tBTA_DM_EXEC_CBACK) (void * p_param); + +/* Encryption callback*/ +typedef void (tBTA_DM_ENCRYPT_CBACK) (BD_ADDR bd_addr, tBTA_TRANSPORT transport, tBTA_STATUS result); + +#if BLE_INCLUDED == TRUE +#define BTA_DM_BLE_SEC_NONE BTM_BLE_SEC_NONE +#define BTA_DM_BLE_SEC_ENCRYPT BTM_BLE_SEC_ENCRYPT +#define BTA_DM_BLE_SEC_NO_MITM BTM_BLE_SEC_ENCRYPT_NO_MITM +#define BTA_DM_BLE_SEC_MITM BTM_BLE_SEC_ENCRYPT_MITM +typedef tBTM_BLE_SEC_ACT tBTA_DM_BLE_SEC_ACT; + +typedef tBTM_BLE_TX_TIME_MS tBTA_DM_BLE_TX_TIME_MS; +typedef tBTM_BLE_RX_TIME_MS tBTA_DM_BLE_RX_TIME_MS; +typedef tBTM_BLE_IDLE_TIME_MS tBTA_DM_BLE_IDLE_TIME_MS; +typedef tBTM_BLE_ENERGY_USED tBTA_DM_BLE_ENERGY_USED; + +#define BTA_DM_CONTRL_UNKNOWN 0 /* Unknown state */ +#define BTA_DM_CONTRL_ACTIVE 1 /* ACL link on, SCO link ongoing, sniff mode */ +#define BTA_DM_CONTRL_SCAN 2 /* Scan state - paging/inquiry/trying to connect*/ +#define BTA_DM_CONTRL_IDLE 3 /* Idle state - page scan, LE advt, inquiry scan */ + +typedef UINT8 tBTA_DM_CONTRL_STATE; + +typedef UINT8 tBTA_DM_BLE_ADV_STATE; +typedef UINT8 tBTA_DM_BLE_ADV_INFO_PRESENT; +typedef UINT8 tBTA_DM_BLE_RSSI_VALUE; +typedef UINT16 tBTA_DM_BLE_ADV_INFO_TIMESTAMP; + +typedef tBTM_BLE_TRACK_ADV_DATA tBTA_DM_BLE_TRACK_ADV_DATA; + +typedef void (tBTA_BLE_SCAN_THRESHOLD_CBACK)(tBTA_DM_BLE_REF_VALUE ref_value); + +typedef void (tBTA_BLE_SCAN_REP_CBACK) (tBTA_DM_BLE_REF_VALUE ref_value, UINT8 report_format, + UINT8 num_records, UINT16 data_len, + UINT8* p_rep_data, tBTA_STATUS status); + +typedef void (tBTA_BLE_SCAN_SETUP_CBACK) (tBTA_BLE_BATCH_SCAN_EVT evt, + tBTA_DM_BLE_REF_VALUE ref_value, + tBTA_STATUS status); + +typedef void (tBTA_BLE_TRACK_ADV_CMPL_CBACK)(int action, tBTA_STATUS status, + tBTA_DM_BLE_PF_AVBL_SPACE avbl_space, + tBTA_DM_BLE_REF_VALUE ref_value); + +typedef void (tBTA_BLE_TRACK_ADV_CBACK)(tBTA_DM_BLE_TRACK_ADV_DATA *p_adv_data); + +typedef void (tBTA_BLE_ENERGY_INFO_CBACK)(tBTA_DM_BLE_TX_TIME_MS tx_time, + tBTA_DM_BLE_RX_TIME_MS rx_time, + tBTA_DM_BLE_IDLE_TIME_MS idle_time, + tBTA_DM_BLE_ENERGY_USED energy_used, + tBTA_DM_CONTRL_STATE ctrl_state, + tBTA_STATUS status); + +#else +typedef UINT8 tBTA_DM_BLE_SEC_ACT; +#endif + +/* Maximum service name length */ +#define BTA_SERVICE_NAME_LEN 35 +#define BTA_SERVICE_DESP_LEN BTA_SERVICE_NAME_LEN +#define BTA_PROVIDER_NAME_LEN BTA_SERVICE_NAME_LEN + + +/* link policy masks */ +#define BTA_DM_LP_SWITCH HCI_ENABLE_MASTER_SLAVE_SWITCH +#define BTA_DM_LP_HOLD HCI_ENABLE_HOLD_MODE +#define BTA_DM_LP_SNIFF HCI_ENABLE_SNIFF_MODE +#define BTA_DM_LP_PARK HCI_ENABLE_PARK_MODE +typedef UINT16 tBTA_DM_LP_MASK; + +/* power mode actions */ +#define BTA_DM_PM_NO_ACTION 0x00 /* no change to the current pm setting */ +#define BTA_DM_PM_PARK 0x10 /* prefers park mode */ +#define BTA_DM_PM_SNIFF 0x20 /* prefers sniff mode */ +#define BTA_DM_PM_SNIFF1 0x21 /* prefers sniff1 mode */ +#define BTA_DM_PM_SNIFF2 0x22 /* prefers sniff2 mode */ +#define BTA_DM_PM_SNIFF3 0x23 /* prefers sniff3 mode */ +#define BTA_DM_PM_SNIFF4 0x24 /* prefers sniff4 mode */ +#define BTA_DM_PM_SNIFF5 0x25 /* prefers sniff5 mode */ +#define BTA_DM_PM_SNIFF6 0x26 /* prefers sniff6 mode */ +#define BTA_DM_PM_SNIFF7 0x27 /* prefers sniff7 mode */ +#define BTA_DM_PM_SNIFF_USER0 0x28 /* prefers user-defined sniff0 mode (testtool only) */ +#define BTA_DM_PM_SNIFF_USER1 0x29 /* prefers user-defined sniff1 mode (testtool only) */ +#define BTA_DM_PM_ACTIVE 0x40 /* prefers active mode */ +#define BTA_DM_PM_RETRY 0x80 /* retry power mode based on current settings */ +#define BTA_DM_PM_SUSPEND 0x04 /* prefers suspend mode */ +#define BTA_DM_PM_NO_PREF 0x01 /* service has no prefernce on power mode setting. eg. connection to service got closed */ + +typedef UINT8 tBTA_DM_PM_ACTION; + +/* index to bta_dm_ssr_spec */ +#define BTA_DM_PM_SSR0 0 +#define BTA_DM_PM_SSR1 1 /* BTA_DM_PM_SSR1 will be dedicated for + HH SSR setting entry, no other profile can use it */ +#define BTA_DM_PM_SSR2 2 +#define BTA_DM_PM_SSR3 3 +#define BTA_DM_PM_SSR4 4 +#define BTA_DM_PM_SSR5 5 +#define BTA_DM_PM_SSR6 6 + +#define BTA_DM_PM_NUM_EVTS 9 + +#ifndef BTA_DM_PM_PARK_IDX +#define BTA_DM_PM_PARK_IDX 5 /* the actual index to bta_dm_pm_md[] for PARK mode */ +#endif + +#ifndef BTA_DM_PM_SNIFF_A2DP_IDX +#define BTA_DM_PM_SNIFF_A2DP_IDX BTA_DM_PM_SNIFF +#endif + +#ifndef BTA_DM_PM_SNIFF_HD_IDLE_IDX +#define BTA_DM_PM_SNIFF_HD_IDLE_IDX BTA_DM_PM_SNIFF2 +#endif + +#ifndef BTA_DM_PM_SNIFF_SCO_OPEN_IDX +#define BTA_DM_PM_SNIFF_SCO_OPEN_IDX BTA_DM_PM_SNIFF3 +#endif + +#ifndef BTA_DM_PM_SNIFF_HD_ACTIVE_IDX +#define BTA_DM_PM_SNIFF_HD_ACTIVE_IDX BTA_DM_PM_SNIFF4 +#endif + +#ifndef BTA_DM_PM_SNIFF_HH_OPEN_IDX +#define BTA_DM_PM_SNIFF_HH_OPEN_IDX BTA_DM_PM_SNIFF2 +#endif + +#ifndef BTA_DM_PM_SNIFF_HH_ACTIVE_IDX +#define BTA_DM_PM_SNIFF_HH_ACTIVE_IDX BTA_DM_PM_SNIFF2 +#endif + +#ifndef BTA_DM_PM_SNIFF_HH_IDLE_IDX +#define BTA_DM_PM_SNIFF_HH_IDLE_IDX BTA_DM_PM_SNIFF2 +#endif + + +#ifndef BTA_DM_PM_HH_OPEN_DELAY +#define BTA_DM_PM_HH_OPEN_DELAY 30000 +#endif + +#ifndef BTA_DM_PM_HH_ACTIVE_DELAY +#define BTA_DM_PM_HH_ACTIVE_DELAY 30000 +#endif + +#ifndef BTA_DM_PM_HH_IDLE_DELAY +#define BTA_DM_PM_HH_IDLE_DELAY 30000 +#endif + +/* The Sniff Parameters defined below must be ordered from highest + * latency (biggest interval) to lowest latency. If there is a conflict + * among the connected services the setting with the lowest latency will + * be selected. If a device should override a sniff parameter then it + * must insure that order is maintained. + */ +#ifndef BTA_DM_PM_SNIFF_MAX +#define BTA_DM_PM_SNIFF_MAX 800 +#define BTA_DM_PM_SNIFF_MIN 400 +#define BTA_DM_PM_SNIFF_ATTEMPT 4 +#define BTA_DM_PM_SNIFF_TIMEOUT 1 +#endif + +#ifndef BTA_DM_PM_SNIFF1_MAX +#define BTA_DM_PM_SNIFF1_MAX 400 +#define BTA_DM_PM_SNIFF1_MIN 200 +#define BTA_DM_PM_SNIFF1_ATTEMPT 4 +#define BTA_DM_PM_SNIFF1_TIMEOUT 1 +#endif + +#ifndef BTA_DM_PM_SNIFF2_MAX +#define BTA_DM_PM_SNIFF2_MAX 180 +#define BTA_DM_PM_SNIFF2_MIN 150 +#define BTA_DM_PM_SNIFF2_ATTEMPT 4 +#define BTA_DM_PM_SNIFF2_TIMEOUT 1 +#endif + +#ifndef BTA_DM_PM_SNIFF3_MAX +#define BTA_DM_PM_SNIFF3_MAX 150 +#define BTA_DM_PM_SNIFF3_MIN 50 +#define BTA_DM_PM_SNIFF3_ATTEMPT 4 +#define BTA_DM_PM_SNIFF3_TIMEOUT 1 +#endif + +#ifndef BTA_DM_PM_SNIFF4_MAX +#define BTA_DM_PM_SNIFF4_MAX 54 +#define BTA_DM_PM_SNIFF4_MIN 30 +#define BTA_DM_PM_SNIFF4_ATTEMPT 4 +#define BTA_DM_PM_SNIFF4_TIMEOUT 1 +#endif + +#ifndef BTA_DM_PM_SNIFF5_MAX +#define BTA_DM_PM_SNIFF5_MAX 36 +#define BTA_DM_PM_SNIFF5_MIN 30 +#define BTA_DM_PM_SNIFF5_ATTEMPT 2 +#define BTA_DM_PM_SNIFF5_TIMEOUT 0 +#endif + +#ifndef BTA_DM_PM_PARK_MAX +#define BTA_DM_PM_PARK_MAX 800 +#define BTA_DM_PM_PARK_MIN 400 +#define BTA_DM_PM_PARK_ATTEMPT 0 +#define BTA_DM_PM_PARK_TIMEOUT 0 +#endif + + +/* Switch callback events */ +#define BTA_DM_SWITCH_CMPL_EVT 0 /* Completion of the Switch API */ + +typedef UINT8 tBTA_DM_SWITCH_EVT; +typedef void (tBTA_DM_SWITCH_CBACK)(tBTA_DM_SWITCH_EVT event, tBTA_STATUS status); + +/* Audio routing out configuration */ +#define BTA_DM_ROUTE_NONE 0x00 /* No Audio output */ +#define BTA_DM_ROUTE_DAC 0x01 /* routing over analog output */ +#define BTA_DM_ROUTE_I2S 0x02 /* routing over digital (I2S) output */ +#define BTA_DM_ROUTE_BT_MONO 0x04 /* routing over SCO */ +#define BTA_DM_ROUTE_BT_STEREO 0x08 /* routing over BT Stereo */ +#define BTA_DM_ROUTE_HOST 0x10 /* routing over Host */ +#define BTA_DM_ROUTE_FMTX 0x20 /* routing over FMTX */ +#define BTA_DM_ROUTE_FMRX 0x40 /* routing over FMRX */ +#define BTA_DM_ROUTE_BTSNK 0x80 /* routing over BT SNK */ + +typedef UINT8 tBTA_DM_ROUTE_PATH; + + +/* Device Identification (DI) data structure +*/ +/* Used to set the DI record */ +typedef tSDP_DI_RECORD tBTA_DI_RECORD; +/* Used to get the DI record */ +typedef tSDP_DI_GET_RECORD tBTA_DI_GET_RECORD; +/* SDP discovery database */ +typedef tSDP_DISCOVERY_DB tBTA_DISCOVERY_DB; + +#ifndef BTA_DI_NUM_MAX +#define BTA_DI_NUM_MAX 3 +#endif + +/* Device features mask definitions */ +#define BTA_FEATURE_BYTES_PER_PAGE BTM_FEATURE_BYTES_PER_PAGE +#define BTA_EXT_FEATURES_PAGE_MAX BTM_EXT_FEATURES_PAGE_MAX +/* ACL type +*/ +#define BTA_DM_LINK_TYPE_BR_EDR 0x01 +#define BTA_DM_LINK_TYPE_LE 0x02 +#define BTA_DM_LINK_TYPE_ALL 0xFF +typedef UINT8 tBTA_DM_LINK_TYPE; + +#define IMMEDIATE_DELY_MODE 0x00 +#define ONFOUND_DELY_MODE 0x01 +#define BATCH_DELY_MODE 0x02 +#define ALLOW_ALL_FILTER 0x00 +#define LOWEST_RSSI_VALUE 129 + +/***************************************************************************** +** External Function Declarations +*****************************************************************************/ +#ifdef __cplusplus +extern "C" +{ +#endif + +/******************************************************************************* +** +** Function BTA_EnableBluetooth +** +** Description This function initializes BTA and prepares BTA and the +** Bluetooth protocol stack for use. This function is +** typically called at startup or when Bluetooth services +** are required by the phone. This function must be called +** before calling any other API function. +** +** +** Returns BTA_SUCCESS if successful. +** BTA_FAIL if internal failure. +** +*******************************************************************************/ +extern tBTA_STATUS BTA_EnableBluetooth(tBTA_DM_SEC_CBACK *p_cback); + +/******************************************************************************* +** +** Function BTA_DisableBluetooth +** +** Description This function disables BTA and the Bluetooth protocol +** stack. It is called when BTA is no longer being used +** by any application in the system. +** +** +** Returns void +** +*******************************************************************************/ +extern tBTA_STATUS BTA_DisableBluetooth(void); + +/******************************************************************************* +** +** Function BTA_EnableTestMode +** +** Description Enables bluetooth device under test mode +** +** +** Returns tBTA_STATUS +** +*******************************************************************************/ +extern tBTA_STATUS BTA_EnableTestMode(void); + +/******************************************************************************* +** +** Function BTA_DisableTestMode +** +** Description Disable bluetooth device under test mode +** +** +** Returns None +** +*******************************************************************************/ +extern void BTA_DisableTestMode(void); + +/******************************************************************************* +** +** Function BTA_DmSetDeviceName +** +** Description This function sets the Bluetooth name of the local device. +** +** +** Returns void +** +*******************************************************************************/ +extern void BTA_DmSetDeviceName(char *p_name); + +/******************************************************************************* +** +** Function BTA_DmSetVisibility +** +** Description This function sets the Bluetooth connectable,discoverable, +** pairable and conn paired only modesmodes of the local device. +** This controls whether other Bluetooth devices can find and connect to +** the local device. +** +** +** Returns void +** +*******************************************************************************/ +extern void BTA_DmSetVisibility(tBTA_DM_DISC disc_mode, tBTA_DM_CONN conn_mode, UINT8 pairable_mode, UINT8 conn_filter); + +/******************************************************************************* +** +** Function BTA_DmSearch +** +** Description This function searches for peer Bluetooth devices. It +** first performs an inquiry; for each device found from the +** inquiry it gets the remote name of the device. If +** parameter services is nonzero, service discovery will be +** performed on each device for the services specified. +** +** +** Returns void +** +*******************************************************************************/ +extern void BTA_DmSearch(tBTA_DM_INQ *p_dm_inq, tBTA_SERVICE_MASK services, + tBTA_DM_SEARCH_CBACK *p_cback); + +/******************************************************************************* +** +** Function BTA_DmSearchCancel +** +** Description This function cancels a search that has been initiated +** by calling BTA_DmSearch(). +** +** +** Returns void +** +*******************************************************************************/ +extern void BTA_DmSearchCancel(void); + +/******************************************************************************* +** +** Function BTA_DmDiscover +** +** Description This function performs service discovery for the services +** of a particular peer device. +** +** +** Returns void +** +*******************************************************************************/ +extern void BTA_DmDiscover(BD_ADDR bd_addr, tBTA_SERVICE_MASK services, + tBTA_DM_SEARCH_CBACK *p_cback, BOOLEAN sdp_search); + +// btla-specific ++ +/******************************************************************************* +** +** Function BTA_DmDiscoverUUID +** +** Description This function performs service discovery for the services +** of a particular peer device. +** +** +** Returns void +** +*******************************************************************************/ +extern void BTA_DmDiscoverUUID(BD_ADDR bd_addr, tSDP_UUID *uuid, + tBTA_DM_SEARCH_CBACK *p_cback, BOOLEAN sdp_search); + +/******************************************************************************* +** +** Function BTA_DmGetCachedRemoteName +** +** Description Retieve cached remote name if available +** +** Returns BTA_SUCCESS if cached name was retrieved +** BTA_FAILURE if cached name is not available +** +*******************************************************************************/ +tBTA_STATUS BTA_DmGetCachedRemoteName(BD_ADDR remote_device, UINT8 **pp_cached_name); +// btla-specific -- + +/******************************************************************************* +** +** Function BTA_DmBond +** +** Description This function initiates a bonding procedure with a peer +** device. The bonding procedure enables authentication +** and optionally encryption on the Bluetooth link. +** +** +** Returns void +** +*******************************************************************************/ +extern void BTA_DmBond(BD_ADDR bd_addr); + +/******************************************************************************* +** +** Function BTA_DmBondByTransport +** +** Description This function initiates a bonding procedure with a peer +** device by designated transport. The bonding procedure enables +** authentication and optionally encryption on the Bluetooth link. +** +** +** Returns void +** +*******************************************************************************/ +extern void BTA_DmBondByTransport(BD_ADDR bd_addr, tBTA_TRANSPORT transport); + + +/******************************************************************************* +** +** Function BTA_DmBondCancel +** +** Description This function cancels a bonding procedure with a peer +** device. +** +** +** Returns void +** +*******************************************************************************/ +extern void BTA_DmBondCancel(BD_ADDR bd_addr); + +/******************************************************************************* +** +** Function BTA_DmPinReply +** +** Description This function provides a PIN when one is requested by DM +** during a bonding procedure. The application should call +** this function after the security callback is called with +** a BTA_DM_PIN_REQ_EVT. +** +** +** Returns void +** +*******************************************************************************/ +extern void BTA_DmPinReply(BD_ADDR bd_addr, BOOLEAN accept, UINT8 pin_len, + UINT8 *p_pin); + +#if (BTM_OOB_INCLUDED == TRUE) +/******************************************************************************* +** +** Function BTA_DmLocalOob +** +** Description This function retrieves the OOB data from local controller. +** The result is reported by bta_dm_co_loc_oob(). +** +** Returns void +** +*******************************************************************************/ +extern void BTA_DmLocalOob(void); +#endif /* BTM_OOB_INCLUDED */ + +/******************************************************************************* +** +** Function BTA_DmConfirm +** +** Description This function accepts or rejects the numerical value of the +** Simple Pairing process on BTA_DM_SP_CFM_REQ_EVT +** +** Returns void +** +*******************************************************************************/ +extern void BTA_DmConfirm(BD_ADDR bd_addr, BOOLEAN accept); + +/******************************************************************************* +** +** Function BTA_DmAddDevice +** +** Description This function adds a device to the security database list +** of peer devices. This function would typically be called +** at system startup to initialize the security database with +** known peer devices. This is a direct execution function +** that may lock task scheduling on some platforms. +** +** Returns void +** +*******************************************************************************/ +extern void BTA_DmAddDevice(BD_ADDR bd_addr, DEV_CLASS dev_class, + LINK_KEY link_key, tBTA_SERVICE_MASK trusted_mask, + BOOLEAN is_trusted, UINT8 key_type, + tBTA_IO_CAP io_cap, UINT8 pin_length); + +/******************************************************************************* +** +** Function BTA_DmRemoveDevice +** +** Description This function removes a device from the security database. +** This is a direct execution function that may lock task +** scheduling on some platforms. +** +** +** Returns BTA_SUCCESS if successful. +** BTA_FAIL if operation failed. +** +*******************************************************************************/ +extern tBTA_STATUS BTA_DmRemoveDevice(BD_ADDR bd_addr); + +/******************************************************************************* +** +** Function BTA_GetEirService +** +** Description This function is called to get BTA service mask from EIR. +** +** Parameters p_eir - pointer of EIR significant part +** p_services - return the BTA service mask +** +** Returns None +** +*******************************************************************************/ +extern void BTA_GetEirService( UINT8 *p_eir, tBTA_SERVICE_MASK *p_services ); + +/******************************************************************************* +** +** Function BTA_DmGetConnectionState +** +** Description Returns whether the remote device is currently connected. +** +** Returns 0 if the device is NOT connected. +** +*******************************************************************************/ +extern UINT16 BTA_DmGetConnectionState( BD_ADDR bd_addr ); + + +/******************************************************************************* +** +** Function BTA_DmSetLocalDiRecord +** +** Description This function adds a DI record to the local SDP database. +** +** Returns BTA_SUCCESS if record set sucessfully, otherwise error code. +** +*******************************************************************************/ +extern tBTA_STATUS BTA_DmSetLocalDiRecord( tBTA_DI_RECORD *p_device_info, + UINT32 *p_handle ); + +/******************************************************************************* +** +** +** Function BTA_DmCloseACL +** +** Description This function force to close an ACL connection and remove the +** device from the security database list of known devices. +** +** Parameters: bd_addr - Address of the peer device +** remove_dev - remove device or not after link down +** transport - which transport to close + +** +** Returns void. +** +*******************************************************************************/ +extern void BTA_DmCloseACL(BD_ADDR bd_addr, BOOLEAN remove_dev, tBTA_TRANSPORT transport); + +/******************************************************************************* +** +** Function bta_dmexecutecallback +** +** Description This function will request BTA to execute a call back in the context of BTU task +** This API was named in lower case because it is only intended +** for the internal customers(like BTIF). +** +** Returns void +** +*******************************************************************************/ +extern void bta_dmexecutecallback (tBTA_DM_EXEC_CBACK* p_callback, void * p_param); + +#if (BTM_SCO_HCI_INCLUDED == TRUE) +/******************************************************************************* +** +** Function BTA_DmPcmInitSamples +** +** Description initialize the down sample converter. +** +** src_sps: original samples per second (source audio data) +** (ex. 44100, 48000) +** bits: number of bits per pcm sample (16) +** n_channels: number of channels (i.e. mono(1), stereo(2)...) +** +** Returns none +** +*******************************************************************************/ +extern void BTA_DmPcmInitSamples (UINT32 src_sps, UINT32 bits, UINT32 n_channels); + +/************************************************************************************** +** Function BTA_DmPcmResample +** +** Description Down sampling utility to convert higher sampling rate into 8K/16bits +** PCM samples. +** +** Parameters p_src: pointer to the buffer where the original sampling PCM +** are stored. +** in_bytes: Length of the input PCM sample buffer in byte. +** p_dst: pointer to the buffer which is to be used to store +** the converted PCM samples. +** +** +** Returns INT32: number of samples converted. +** +**************************************************************************************/ +extern INT32 BTA_DmPcmResample (void *p_src, UINT32 in_bytes, void *p_dst); +#endif + +#if ((defined BLE_INCLUDED) && (BLE_INCLUDED == TRUE)) +/* BLE related API functions */ +/******************************************************************************* +** +** Function BTA_DmBleSecurityGrant +** +** Description Grant security request access. +** +** Parameters: bd_addr - BD address of the peer +** res - security grant status. +** +** Returns void +** +*******************************************************************************/ +extern void BTA_DmBleSecurityGrant(BD_ADDR bd_addr, tBTA_DM_BLE_SEC_GRANT res); + + + +/******************************************************************************* +** +** Function BTA_DmBleSetBgConnType +** +** Description This function is called to set BLE connectable mode for a +** peripheral device. +** +** Parameters bg_conn_type: it can be auto connection, or selective connection. +** p_select_cback: callback function when selective connection procedure +** is being used. +** +** Returns void +** +*******************************************************************************/ +extern void BTA_DmBleSetBgConnType(tBTA_DM_BLE_CONN_TYPE bg_conn_type, tBTA_DM_BLE_SEL_CBACK *p_select_cback); + +/******************************************************************************* +** +** Function BTA_DmBlePasskeyReply +** +** Description Send BLE SMP passkey reply. +** +** Parameters: bd_addr - BD address of the peer +** accept - passkey entry sucessful or declined. +** passkey - passkey value, must be a 6 digit number, +** can be lead by 0. +** +** Returns void +** +*******************************************************************************/ +extern void BTA_DmBlePasskeyReply(BD_ADDR bd_addr, BOOLEAN accept, UINT32 passkey); + +/******************************************************************************* +** +** Function BTA_DmBleConfirmReply +** +** Description Send BLE SMP SC user confirmation reply. +** +** Parameters: bd_addr - BD address of the peer +** accept - numbers to compare are the same or different. +** +** Returns void +** +*******************************************************************************/ +extern void BTA_DmBleConfirmReply(BD_ADDR bd_addr, BOOLEAN accept); + +/******************************************************************************* +** +** Function BTA_DmAddBleDevice +** +** Description Add a BLE device. This function will be normally called +** during host startup to restore all required information +** for a LE device stored in the NVRAM. +** +** Parameters: bd_addr - BD address of the peer +** dev_type - Remote device's device type. +** addr_type - LE device address type. +** +** Returns void +** +*******************************************************************************/ +extern void BTA_DmAddBleDevice(BD_ADDR bd_addr, tBLE_ADDR_TYPE addr_type, + tBT_DEVICE_TYPE dev_type); + + +/******************************************************************************* +** +** Function BTA_DmAddBleKey +** +** Description Add/modify LE device information. This function will be +** normally called during host startup to restore all required +** information stored in the NVRAM. +** +** Parameters: bd_addr - BD address of the peer +** p_le_key - LE key values. +** key_type - LE SMP key type. +** +** Returns void +** +*******************************************************************************/ +extern void BTA_DmAddBleKey (BD_ADDR bd_addr, + tBTA_LE_KEY_VALUE *p_le_key, + tBTA_LE_KEY_TYPE key_type); + +/******************************************************************************* +** +** Function BTA_DmSetBlePrefConnParams +** +** Description This function is called to set the preferred connection +** parameters when default connection parameter is not desired. +** +** Parameters: bd_addr - BD address of the peripheral +** min_conn_int - minimum preferred connection interval +** max_conn_int - maximum preferred connection interval +** slave_latency - preferred slave latency +** supervision_tout - preferred supervision timeout +** +** +** Returns void +** +*******************************************************************************/ +extern void BTA_DmSetBlePrefConnParams(BD_ADDR bd_addr, + UINT16 min_conn_int, UINT16 max_conn_int, + UINT16 slave_latency, UINT16 supervision_tout ); + +/******************************************************************************* +** +** Function BTA_DmSetBleConnScanParams +** +** Description This function is called to set scan parameters used in +** BLE connection request +** +** Parameters: scan_interval - scan interval +** scan_window - scan window +** +** Returns void +** +*******************************************************************************/ +extern void BTA_DmSetBleConnScanParams(UINT32 scan_interval, + UINT32 scan_window); + +/******************************************************************************* +** +** Function BTA_DmSetBleScanParams +** +** Description This function is called to set scan parameters +** +** Parameters: client_if - Client IF +** scan_interval - scan interval +** scan_window - scan window +** scan_mode - scan mode +** scan_param_setup_status_cback - Set scan param status callback +** +** Returns void +** +*******************************************************************************/ +extern void BTA_DmSetBleScanParams(tGATT_IF client_if, UINT32 scan_interval, + UINT32 scan_window, tBLE_SCAN_MODE scan_mode, + tBLE_SCAN_PARAM_SETUP_CBACK scan_param_setup_status_cback); + +/******************************************************************************* +** +** Function BTA_DmSetBleAdvParams +** +** Description This function sets the advertising parameters BLE functionality. +** It is to be called when device act in peripheral or broadcaster +** role. +** +** Parameters: adv_int_min - adv interval minimum +** adv_int_max - adv interval max +** p_dir_bda - directed adv initator address +** +** Returns void +** +*******************************************************************************/ +extern void BTA_DmSetBleAdvParams (UINT16 adv_int_min, UINT16 adv_int_max, + tBLE_BD_ADDR *p_dir_bda); +/******************************************************************************* +** +** Function BTA_DmSearchExt +** +** Description This function searches for peer Bluetooth devices. It performs +** an inquiry and gets the remote name for devices. Service +** discovery is done if services is non zero +** +** Parameters p_dm_inq: inquiry conditions +** services: if service is not empty, service discovery will be done. +** for all GATT based service condition, put num_uuid, and +** p_uuid is the pointer to the list of UUID values. +** p_cback: callback functino when search is completed. +** +** +** +** Returns void +** +*******************************************************************************/ +extern void BTA_DmSearchExt(tBTA_DM_INQ *p_dm_inq, tBTA_SERVICE_MASK_EXT *p_services, + tBTA_DM_SEARCH_CBACK *p_cback); + +/******************************************************************************* +** +** Function BTA_DmDiscoverExt +** +** Description This function does service discovery for services of a +** peer device. When services.num_uuid is 0, it indicates all +** GATT based services are to be searched; other wise a list of +** UUID of interested services should be provided through +** services.p_uuid. +** +** +** +** Returns void +** +*******************************************************************************/ +extern void BTA_DmDiscoverExt(BD_ADDR bd_addr, tBTA_SERVICE_MASK_EXT *p_services, + tBTA_DM_SEARCH_CBACK *p_cback, BOOLEAN sdp_search); + +/******************************************************************************* +** +** Function BTA_DmDiscoverByTransport +** +** Description This function does service discovery on particular transport +** for services of a +** peer device. When services.num_uuid is 0, it indicates all +** GATT based services are to be searched; other wise a list of +** UUID of interested services should be provided through +** p_services->p_uuid. +** +** +** +** Returns void +** +*******************************************************************************/ +extern void BTA_DmDiscoverByTransport(BD_ADDR bd_addr, tBTA_SERVICE_MASK_EXT *p_services, + tBTA_DM_SEARCH_CBACK *p_cback, BOOLEAN sdp_search, + tBTA_TRANSPORT transport); + +/******************************************************************************* +** +** Function BTA_DmSetEncryption +** +** Description This function is called to ensure that connection is +** encrypted. Should be called only on an open connection. +** Typically only needed for connections that first want to +** bring up unencrypted links, then later encrypt them. +** +** Parameters: bd_addr - Address of the peer device +** transport - transport of the link to be encruypted +** p_callback - Pointer to callback function to indicat the +** link encryption status +** sec_act - This is the security action to indicate +** what knid of BLE security level is required for +** the BLE link if the BLE is supported +** Note: This parameter is ignored for the BR/EDR link +** or the BLE is not supported +** +** Returns void +** +** +*******************************************************************************/ +extern void BTA_DmSetEncryption(BD_ADDR bd_addr, tBTA_TRANSPORT transport, + tBTA_DM_ENCRYPT_CBACK *p_callback, + tBTA_DM_BLE_SEC_ACT sec_act); + + +/******************************************************************************* +** +** Function BTA_DmBleObserve +** +** Description This procedure keep the device listening for advertising +** events from a broadcast device. +** +** Parameters start: start or stop observe. +** duration : Duration of the scan. Continuous scan if 0 is passed +** p_results_cb: Callback to be called with scan results +** +** Returns void +** +*******************************************************************************/ +extern void BTA_DmBleObserve(BOOLEAN start, UINT8 duration, + tBTA_DM_SEARCH_CBACK *p_results_cb); + +extern void BTA_DmSetRandAddress(BD_ADDR rand_addr); + +#endif + +#if BLE_INCLUDED == TRUE +// btla-specific -- +/******************************************************************************* +** +** Function BTA_DmBleConfigLocalPrivacy +** +** Description Enable/disable privacy on the local device +** +** Parameters: privacy_enable - enable/disabe privacy on remote device. +** +** Returns void +** +*******************************************************************************/ +extern void BTA_DmBleConfigLocalPrivacy(BOOLEAN privacy_enable); + +/******************************************************************************* +** +** Function BTA_DmBleEnableRemotePrivacy +** +** Description Enable/disable privacy on a remote device +** +** Parameters: bd_addr - BD address of the peer +** privacy_enable - enable/disabe privacy on remote device. +** +** Returns void +** +*******************************************************************************/ +extern void BTA_DmBleEnableRemotePrivacy(BD_ADDR bd_addr, BOOLEAN privacy_enable); + + +/******************************************************************************* +** +** Function BTA_DmBleSetAdvConfig +** +** Description This function is called to override the BTA default ADV parameters. +** +** Parameters Pointer to User defined ADV data structure +** +** Returns None +** +*******************************************************************************/ +extern void BTA_DmBleSetAdvConfig (tBTA_BLE_AD_MASK data_mask, + tBTA_BLE_ADV_DATA *p_adv_cfg, + tBTA_SET_ADV_DATA_CMPL_CBACK *p_adv_data_cback); + +/******************************************************************************* +** +** Function BTA_DmBleSetScanRsp +** +** Description This function is called to override the BTA scan response. +** +** Parameters Pointer to User defined ADV data structure +** +** Returns None +** +*******************************************************************************/ +extern void BTA_DmBleSetScanRsp (tBTA_BLE_AD_MASK data_mask, + tBTA_BLE_ADV_DATA *p_adv_cfg, + tBTA_SET_ADV_DATA_CMPL_CBACK *p_adv_data_cback); + +/******************************************************************************* +** +** Function BTA_DmBleBroadcast +** +** Description This function starts or stops LE broadcasting. +** +** Parameters start: start or stop broadcast. +** +** Returns None +** +*******************************************************************************/ +extern void BTA_DmBleBroadcast (BOOLEAN start); + + +/******************************************************************************* +** +** Function BTA_BleEnableAdvInstance +** +** Description This function enables the Multi ADV instance feature +** +** Parameters p_params Pointer to ADV param user defined structure +** p_cback Pointer to Multi ADV callback structure +** p_ref - Reference pointer +** +** Returns None +** +*******************************************************************************/ +extern void BTA_BleEnableAdvInstance (tBTA_BLE_ADV_PARAMS *p_params, + tBTA_BLE_MULTI_ADV_CBACK *p_cback,void *p_ref); + +/******************************************************************************* +** +** Function BTA_BleUpdateAdvInstParam +** +** Description This function updates the Multi ADV instance params +** +** Parameters inst_id Instance ID +** p_params Pointer to ADV param user defined structure +** +** Returns None +** +*******************************************************************************/ +extern void BTA_BleUpdateAdvInstParam (UINT8 inst_id, + tBTA_BLE_ADV_PARAMS *p_params); + +/******************************************************************************* +** +** Function BTA_BleCfgAdvInstData +** +** Description This function is called to configure the ADV instance data +** +** Parameters inst_id - Instance ID +** is_scan_rsp - Boolean value Scan response +** Pointer to User defined ADV data structure +** Returns None +** +*******************************************************************************/ +extern void BTA_BleCfgAdvInstData (UINT8 inst_id, BOOLEAN is_scan_rsp, + tBTA_BLE_AD_MASK data_mask, tBTA_BLE_ADV_DATA *p_data); + +/******************************************************************************* +** +** Function BTA_BleDisableAdvInstance +** +** Description This function is called to disable the ADV instance +** +** Parameters inst_id - Instance ID to be disabled +** +** Returns None +** +*******************************************************************************/ +extern void BTA_BleDisableAdvInstance(UINT8 inst_id); + +/******************************************************************************* +** +** Function BTA_DmBleUpdateConnectionParams +** +** Description Update connection parameters, can only be used when connection is up. +** +** Parameters: bd_addr - BD address of the peer +** min_int - minimum connection interval, [0x0004~ 0x4000] +** max_int - maximum connection interval, [0x0004~ 0x4000] +** latency - slave latency [0 ~ 500] +** timeout - supervision timeout [0x000a ~ 0xc80] +** +** Returns void +** +*******************************************************************************/ +extern void BTA_DmBleUpdateConnectionParams(BD_ADDR bd_addr, UINT16 min_int, + UINT16 max_int, UINT16 latency, UINT16 timeout); + +/******************************************************************************* +** +** Function BTA_DmBleSetDataLength +** +** Description This function is to set maximum LE data packet size +** +** Returns void +** +*******************************************************************************/ +extern void BTA_DmBleSetDataLength(BD_ADDR remote_device, UINT16 tx_data_length); + +/******************************************************************************* +** +** Function BTA_DmBleSetStorageParams +** +** Description This function is called to set the storage parameters +** +** Parameters batch_scan_full_max -Max storage space (in %) allocated to full scanning +** batch_scan_trunc_max -Max storage space (in %) allocated to truncated scanning +** batch_scan_notify_threshold - Setup notification level based on total space +** consumed by both pools. Setting it to 0 will disable threshold notification +** p_setup_cback - Setup callback +** p_thres_cback - Threshold callback +** p_rep_cback - Reports callback +** ref_value - Reference value +** +** Returns None +** +*******************************************************************************/ +extern void BTA_DmBleSetStorageParams(UINT8 batch_scan_full_max, + UINT8 batch_scan_trunc_max, + UINT8 batch_scan_notify_threshold, + tBTA_BLE_SCAN_SETUP_CBACK *p_setup_cback, + tBTA_BLE_SCAN_THRESHOLD_CBACK *p_thres_cback, + tBTA_BLE_SCAN_REP_CBACK* p_rep_cback, + tBTA_DM_BLE_REF_VALUE ref_value); + +/******************************************************************************* +** +** Function BTA_DmBleEnableBatchScan +** +** Description This function is called to enable the batch scan +** +** Parameters scan_mode -Batch scan mode +** scan_interval - Scan interval +** scan_window - Scan window +** discard_rule -Discard rules +** addr_type - Address type +** ref_value - Reference value +** +** Returns None +** +*******************************************************************************/ +extern void BTA_DmBleEnableBatchScan(tBTA_BLE_BATCH_SCAN_MODE scan_mode, + UINT32 scan_interval, UINT32 scan_window, + tBTA_BLE_DISCARD_RULE discard_rule, + tBLE_ADDR_TYPE addr_type, + tBTA_DM_BLE_REF_VALUE ref_value); + +/******************************************************************************* +** +** Function BTA_DmBleReadScanReports +** +** Description This function is called to read the batch scan reports +** +** Parameters scan_mode -Batch scan mode +** ref_value - Reference value +** +** Returns None +** +*******************************************************************************/ +extern void BTA_DmBleReadScanReports(tBTA_BLE_BATCH_SCAN_MODE scan_type, + tBTA_DM_BLE_REF_VALUE ref_value); + +/******************************************************************************* +** +** Function BTA_DmBleDisableBatchScan +** +** Description This function is called to disable the batch scanning +** +** Parameters ref_value - Reference value +** +** Returns None +** +*******************************************************************************/ +extern void BTA_DmBleDisableBatchScan(tBTA_DM_BLE_REF_VALUE ref_value); + +/******************************************************************************* +** +** Function BTA_DmEnableScanFilter +** +** Description This function is called to enable the adv data payload filter +** +** Parameters action - enable or disable the APCF feature +** p_cmpl_cback - Command completed callback +** ref_value - Reference value +** +** Returns void +** +*******************************************************************************/ +extern void BTA_DmEnableScanFilter(UINT8 action, + tBTA_DM_BLE_PF_STATUS_CBACK *p_cmpl_cback, + tBTA_DM_BLE_REF_VALUE ref_value); + +/******************************************************************************* +** +** Function BTA_DmBleScanFilterSetup +** +** Description This function is called to setup the filter params +** +** Parameters p_target: enable the filter condition on a target device; if NULL +** filt_index - Filter index +** p_filt_params -Filter parameters +** ref_value - Reference value +** action - Add, delete or clear +** p_cmpl_back - Command completed callback +** +** Returns void +** +*******************************************************************************/ +extern void BTA_DmBleScanFilterSetup(UINT8 action, + tBTA_DM_BLE_PF_FILT_INDEX filt_index, + tBTA_DM_BLE_PF_FILT_PARAMS *p_filt_params, + tBLE_BD_ADDR *p_target, + tBTA_DM_BLE_PF_PARAM_CBACK *p_cmpl_cback, + tBTA_DM_BLE_REF_VALUE ref_value); + +/******************************************************************************* +** +** Function BTA_DmBleCfgFilterCondition +** +** Description This function is called to configure the adv data payload filter +** condition. +** +** Parameters action: to read/write/clear +** cond_type: filter condition type +** filt_index - Filter index +** p_cond: filter condition parameter +** p_cmpl_back - Command completed callback +** ref_value - Reference value +** +** Returns void +** +*******************************************************************************/ +extern void BTA_DmBleCfgFilterCondition(tBTA_DM_BLE_SCAN_COND_OP action, + tBTA_DM_BLE_PF_COND_TYPE cond_type, + tBTA_DM_BLE_PF_FILT_INDEX filt_index, + tBTA_DM_BLE_PF_COND_PARAM *p_cond, + tBTA_DM_BLE_PF_CFG_CBACK *p_cmpl_cback, + tBTA_DM_BLE_REF_VALUE ref_value); + + +/******************************************************************************* +** +** Function BTA_DmBleTrackAdvertiser +** +** Description This function is called to track the advertiser +** +** Parameters ref_value - Reference value +** p_track_adv_cback - ADV callback +** +** Returns None +** +*******************************************************************************/ +extern void BTA_DmBleTrackAdvertiser(tBTA_DM_BLE_REF_VALUE ref_value, + tBTA_BLE_TRACK_ADV_CBACK *p_track_adv_cback); + +/******************************************************************************* +** +** Function BTA_DmBleGetEnergyInfo +** +** Description This function is called to obtain the energy info +** +** Parameters p_cmpl_cback - Command complete callback +** +** Returns void +** +*******************************************************************************/ +extern void BTA_DmBleGetEnergyInfo(tBTA_BLE_ENERGY_INFO_CBACK *p_cmpl_cback); + +/******************************************************************************* +** +** Function BTA_BrcmInit +** +** Description This function initializes Broadcom specific VS handler in BTA +** +** Returns void +** +*******************************************************************************/ +extern void BTA_VendorInit (void); + +/******************************************************************************* +** +** Function BTA_BrcmCleanup +** +** Description This function frees up Broadcom specific VS specific dynamic memory +** +** Returns void +** +*******************************************************************************/ +extern void BTA_VendorCleanup (void); + +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* BTA_API_H */ diff --git a/components/bt/bluedroid/bta/include/bta_dm_ci.h b/components/bt/bluedroid/bta/include/bta_dm_ci.h new file mode 100755 index 0000000000..5593b9ec43 --- /dev/null +++ b/components/bt/bluedroid/bta/include/bta_dm_ci.h @@ -0,0 +1,80 @@ +/****************************************************************************** + * + * Copyright (C) 2006-2012 Broadcom Corporation + * + * 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 is the interface file for device mananger call-in functions. + * + ******************************************************************************/ +#ifndef BTA_DM_CI_H +#define BTA_DM_CI_H + +#include "bta_api.h" + +/***************************************************************************** +** Function Declarations +*****************************************************************************/ +#ifdef __cplusplus +extern "C" +{ +#endif + +/******************************************************************************* +** +** Function bta_dm_ci_io_req +** +** Description This function must be called in response to function +** bta_dm_co_io_req(), if *p_oob_data is set to BTA_OOB_UNKNOWN +** by bta_dm_co_io_req(). +** +** Returns void +** +*******************************************************************************/ +extern void bta_dm_ci_io_req(BD_ADDR bd_addr, tBTA_IO_CAP io_cap, + tBTA_OOB_DATA oob_data, tBTA_AUTH_REQ auth_req); + +/******************************************************************************* +** +** Function bta_dm_ci_rmt_oob +** +** Description This function must be called in response to function +** bta_dm_co_rmt_oob() to provide the OOB data associated +** with the remote device. +** +** Returns void +** +*******************************************************************************/ +extern void bta_dm_ci_rmt_oob(BOOLEAN accept, BD_ADDR bd_addr, + BT_OCTET16 c, BT_OCTET16 r); +/******************************************************************************* +** +** Function bta_dm_sco_ci_data_ready +** +** Description This function sends an event to indicating that the phone +** has SCO data ready.. +** +** Returns void +** +*******************************************************************************/ +extern void bta_dm_sco_ci_data_ready(UINT16 event, UINT16 sco_handle); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/components/bt/bluedroid/bta/include/bta_dm_co.h b/components/bt/bluedroid/bta/include/bta_dm_co.h new file mode 100755 index 0000000000..c00a59cf1e --- /dev/null +++ b/components/bt/bluedroid/bta/include/bta_dm_co.h @@ -0,0 +1,274 @@ +/****************************************************************************** + * + * Copyright (C) 2006-2012 Broadcom Corporation + * + * 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 is the interface file for device mananger callout functions. + * + ******************************************************************************/ +#ifndef BTA_DM_CO_H +#define BTA_DM_CO_H + +#include "bta_sys.h" + + +#ifndef BTA_SCO_OUT_PKT_SIZE + #define BTA_SCO_OUT_PKT_SIZE BTM_SCO_DATA_SIZE_MAX +#endif + +#define BTA_SCO_CODEC_PCM 0 /* used for regular SCO */ +#define BTA_SCO_CODEC_SBC 1 /* used for WBS */ +typedef UINT8 tBTA_SCO_CODEC_TYPE; + +#define BTA_DM_SCO_SAMP_RATE_8K 8000 +#define BTA_DM_SCO_SAMP_RATE_16K 16000 + +/* SCO codec information */ +typedef struct +{ + tBTA_SCO_CODEC_TYPE codec_type; +}tBTA_CODEC_INFO; + +#define BTA_DM_SCO_ROUTE_PCM BTM_SCO_ROUTE_PCM +#define BTA_DM_SCO_ROUTE_HCI BTM_SCO_ROUTE_HCI + +typedef tBTM_SCO_ROUTE_TYPE tBTA_DM_SCO_ROUTE_TYPE; + + +/***************************************************************************** +** Function Declarations +*****************************************************************************/ + +/******************************************************************************* +** +** Function bta_dm_co_io_req +** +** Description This callout function is executed by DM to get IO capabilities +** of the local device for the Simple Pairing process +** +** Parameters bd_addr - The peer device +** *p_io_cap - The local Input/Output capabilities +** *p_oob_data - TRUE, if OOB data is available for the peer device. +** *p_auth_req - TRUE, if MITM protection is required. +** +** Returns void. +** +*******************************************************************************/ +extern void bta_dm_co_io_req(BD_ADDR bd_addr, tBTA_IO_CAP *p_io_cap, + tBTA_OOB_DATA *p_oob_data, tBTA_AUTH_REQ *p_auth_req, + BOOLEAN is_orig); + +/******************************************************************************* +** +** Function bta_dm_co_io_rsp +** +** Description This callout function is executed by DM to report IO capabilities +** of the peer device for the Simple Pairing process +** +** Parameters bd_addr - The peer device +** io_cap - The remote Input/Output capabilities +** oob_data - TRUE, if OOB data is available for the peer device. +** auth_req - TRUE, if MITM protection is required. +** +** Returns void. +** +*******************************************************************************/ +extern void bta_dm_co_io_rsp(BD_ADDR bd_addr, tBTA_IO_CAP io_cap, + tBTA_OOB_DATA oob_data, tBTA_AUTH_REQ auth_req); + +/******************************************************************************* +** +** Function bta_dm_co_lk_upgrade +** +** Description This callout function is executed by DM to check if the +** platform wants allow link key upgrade +** +** Parameters bd_addr - The peer device +** *p_upgrade - TRUE, if link key upgrade is desired. +** +** Returns void. +** +*******************************************************************************/ +extern void bta_dm_co_lk_upgrade(BD_ADDR bd_addr, BOOLEAN *p_upgrade ); + +/******************************************************************************* +** +** Function bta_dm_co_loc_oob +** +** Description This callout function is executed by DM to report the OOB +** data of the local device for the Simple Pairing process +** +** Parameters valid - TRUE, if the local OOB data is retrieved from LM +** c - Simple Pairing Hash C +** r - Simple Pairing Randomnizer R +** +** Returns void. +** +*******************************************************************************/ +extern void bta_dm_co_loc_oob(BOOLEAN valid, BT_OCTET16 c, BT_OCTET16 r); + +/******************************************************************************* +** +** Function bta_dm_co_rmt_oob +** +** Description This callout function is executed by DM to request the OOB +** data for the remote device for the Simple Pairing process +** +** Parameters bd_addr - The peer device +** +** Returns void. +** +*******************************************************************************/ +extern void bta_dm_co_rmt_oob(BD_ADDR bd_addr); + +/***************************************************************************** +** SCO over HCI Function Declarations +*****************************************************************************/ +/******************************************************************************* +** +** Function bta_dm_sco_co_init +** +** Description This function can be used by the phone to initialize audio +** codec or for other initialization purposes before SCO connection +** is opened. +** +** +** Returns Void. +** +*******************************************************************************/ +extern tBTA_DM_SCO_ROUTE_TYPE bta_dm_sco_co_init(UINT32 rx_bw, UINT32 tx_bw, + tBTA_CODEC_INFO *p_codec_info, UINT8 app_id); + + +/******************************************************************************* +** +** Function bta_dm_sco_co_open +** +** Description This function is executed when a SCO connection is open. +** +** +** Returns void +** +*******************************************************************************/ +extern void bta_dm_sco_co_open(UINT16 handle, UINT8 pkt_size, UINT16 event); + +/******************************************************************************* +** +** Function bta_dm_sco_co_close +** +** Description This function is called when a SCO connection is closed +** +** +** Returns void +** +*******************************************************************************/ +extern void bta_dm_sco_co_close(void); + +/******************************************************************************* +** +** Function bta_dm_sco_co_out_data +** +** Description This function is called to send SCO data over HCI. +** +** Returns void +** +*******************************************************************************/ +extern void bta_dm_sco_co_out_data(BT_HDR **p_buf); + +/******************************************************************************* +** +** Function bta_dm_sco_co_in_data +** +** Description This function is called to send incoming SCO data to application. +** +** Returns void +** +*******************************************************************************/ +extern void bta_dm_sco_co_in_data(BT_HDR *p_buf, tBTM_SCO_DATA_FLAG status); + + + +/******************************************************************************* +** +** Function bta_dm_co_ble_io_req +** +** Description This callout function is executed by DM to get BLE IO capabilities +** before SMP pairing gets going. +** +** Parameters bd_addr - The peer device +** *p_io_cap - The local Input/Output capabilities +** *p_oob_data - TRUE, if OOB data is available for the peer device. +** *p_auth_req - Auth request setting (Bonding and MITM required or not) +** *p_max_key_size - max key size local device supported. +** *p_init_key - initiator keys. +** *p_resp_key - responder keys. +** +** Returns void. +** +*******************************************************************************/ +extern void bta_dm_co_ble_io_req(BD_ADDR bd_addr, tBTA_IO_CAP *p_io_cap, + tBTA_OOB_DATA *p_oob_data, + tBTA_LE_AUTH_REQ *p_auth_req, + UINT8 *p_max_key_size, + tBTA_LE_KEY_TYPE *p_init_key, + tBTA_LE_KEY_TYPE *p_resp_key ); + + +/******************************************************************************* +** +** Function bta_dm_co_ble_local_key_reload +** +** Description This callout function is to load the local BLE keys if available +** on the device. +** +** Parameters none +** +** Returns void. +** +*******************************************************************************/ +extern void bta_dm_co_ble_load_local_keys (tBTA_DM_BLE_LOCAL_KEY_MASK *p_key_mask, BT_OCTET16 er, + tBTA_BLE_LOCAL_ID_KEYS *p_id_keys); + +// btla-specific ++ +/******************************************************************************* +** +** Function bta_dm_co_ble_io_req +** +** Description This callout function is executed by DM to get BLE IO capabilities +** before SMP pairing gets going. +** +** Parameters bd_addr - The peer device +** *p_io_cap - The local Input/Output capabilities +** *p_oob_data - TRUE, if OOB data is available for the peer device. +** *p_auth_req - Auth request setting (Bonding and MITM required or not) +** *p_max_key_size - max key size local device supported. +** *p_init_key - initiator keys. +** *p_resp_key - responder keys. +** +** Returns void. +** +*******************************************************************************/ +extern void bta_dm_co_ble_io_req(BD_ADDR bd_addr, tBTA_IO_CAP *p_io_cap, + tBTA_OOB_DATA *p_oob_data, + tBTA_LE_AUTH_REQ *p_auth_req, + UINT8 *p_max_key_size, + tBTA_LE_KEY_TYPE *p_init_key, + tBTA_LE_KEY_TYPE *p_resp_key ); +// btla-specific -- + +#endif diff --git a/components/bt/bluedroid/bta/include/bta_gatt_api.h b/components/bt/bluedroid/bta/include/bta_gatt_api.h new file mode 100755 index 0000000000..5ef9ad74cb --- /dev/null +++ b/components/bt/bluedroid/bta/include/bta_gatt_api.h @@ -0,0 +1,1411 @@ +/****************************************************************************** + * + * Copyright (C) 2003-2013 Broadcom Corporation + * + * 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 is the public interface file for BTA GATT. + * + ******************************************************************************/ + +#ifndef BTA_GATT_API_H +#define BTA_GATT_API_H + +#include "bta_api.h" +#include "gatt_api.h" + +#ifndef BTA_GATT_INCLUDED +#warning BTA_GATT_INCLUDED not defined +#define BTA_GATT_INCLUDED FALSE +#endif + +#if ((BLE_INCLUDED == FALSE) && (BTA_GATT_INCLUDED == TRUE)) +#undef BTA_GATT_INCLUDED +#define BTA_GATT_INCLUDED FALSE +#endif + + +#ifndef BTA_GATT_DEBUG +#define BTA_GATT_DEBUG FALSE +#endif + +/***************************************************************************** +** Constants and data types +*****************************************************************************/ +/************************** +** Common Definitions +***************************/ +/* GATT ID */ +typedef struct +{ + tBT_UUID uuid; /* uuid of the attribute */ + UINT8 inst_id; /* instance ID */ +} __attribute__((packed)) tBTA_GATT_ID; + +/* Success code and error codes */ +#define BTA_GATT_OK GATT_SUCCESS +#define BTA_GATT_INVALID_HANDLE GATT_INVALID_HANDLE /* 0x0001 */ +#define BTA_GATT_READ_NOT_PERMIT GATT_READ_NOT_PERMIT /* 0x0002 */ +#define BTA_GATT_WRITE_NOT_PERMIT GATT_WRITE_NOT_PERMIT /* 0x0003 */ +#define BTA_GATT_INVALID_PDU GATT_INVALID_PDU /* 0x0004 */ +#define BTA_GATT_INSUF_AUTHENTICATION GATT_INSUF_AUTHENTICATION /* 0x0005 */ +#define BTA_GATT_REQ_NOT_SUPPORTED GATT_REQ_NOT_SUPPORTED /* 0x0006 */ +#define BTA_GATT_INVALID_OFFSET GATT_INVALID_OFFSET /* 0x0007 */ +#define BTA_GATT_INSUF_AUTHORIZATION GATT_INSUF_AUTHORIZATION /* 0x0008 */ +#define BTA_GATT_PREPARE_Q_FULL GATT_PREPARE_Q_FULL /* 0x0009 */ +#define BTA_GATT_NOT_FOUND GATT_NOT_FOUND /* 0x000a */ +#define BTA_GATT_NOT_LONG GATT_NOT_LONG /* 0x000b */ +#define BTA_GATT_INSUF_KEY_SIZE GATT_INSUF_KEY_SIZE /* 0x000c */ +#define BTA_GATT_INVALID_ATTR_LEN GATT_INVALID_ATTR_LEN /* 0x000d */ +#define BTA_GATT_ERR_UNLIKELY GATT_ERR_UNLIKELY /* 0x000e */ +#define BTA_GATT_INSUF_ENCRYPTION GATT_INSUF_ENCRYPTION /* 0x000f */ +#define BTA_GATT_UNSUPPORT_GRP_TYPE GATT_UNSUPPORT_GRP_TYPE /* 0x0010 */ +#define BTA_GATT_INSUF_RESOURCE GATT_INSUF_RESOURCE /* 0x0011 */ + + +#define BTA_GATT_NO_RESOURCES GATT_NO_RESOURCES /* 0x80 */ +#define BTA_GATT_INTERNAL_ERROR GATT_INTERNAL_ERROR /* 0x81 */ +#define BTA_GATT_WRONG_STATE GATT_WRONG_STATE /* 0x82 */ +#define BTA_GATT_DB_FULL GATT_DB_FULL /* 0x83 */ +#define BTA_GATT_BUSY GATT_BUSY /* 0x84 */ +#define BTA_GATT_ERROR GATT_ERROR /* 0x85 */ +#define BTA_GATT_CMD_STARTED GATT_CMD_STARTED /* 0x86 */ +#define BTA_GATT_ILLEGAL_PARAMETER GATT_ILLEGAL_PARAMETER /* 0x87 */ +#define BTA_GATT_PENDING GATT_PENDING /* 0x88 */ +#define BTA_GATT_AUTH_FAIL GATT_AUTH_FAIL /* 0x89 */ +#define BTA_GATT_MORE GATT_MORE /* 0x8a */ +#define BTA_GATT_INVALID_CFG GATT_INVALID_CFG /* 0x8b */ +#define BTA_GATT_SERVICE_STARTED GATT_SERVICE_STARTED /* 0x8c */ +#define BTA_GATT_ENCRYPED_MITM GATT_ENCRYPED_MITM /* GATT_SUCCESS */ +#define BTA_GATT_ENCRYPED_NO_MITM GATT_ENCRYPED_NO_MITM /* 0x8d */ +#define BTA_GATT_NOT_ENCRYPTED GATT_NOT_ENCRYPTED /* 0x8e */ +#define BTA_GATT_CONGESTED GATT_CONGESTED /* 0x8f */ + +#define BTA_GATT_DUP_REG 0x90 /* 0x90 */ +#define BTA_GATT_ALREADY_OPEN 0x91 /* 0x91 */ +#define BTA_GATT_CANCEL 0x92 /* 0x92 */ + + /* 0xE0 ~ 0xFC reserved for future use */ +#define BTA_GATT_CCC_CFG_ERR GATT_CCC_CFG_ERR /* 0xFD Client Characteristic Configuration Descriptor Improperly Configured */ +#define BTA_GATT_PRC_IN_PROGRESS GATT_PRC_IN_PROGRESS /* 0xFE Procedure Already in progress */ +#define BTA_GATT_OUT_OF_RANGE GATT_OUT_OF_RANGE /* 0xFFAttribute value out of range */ + +typedef UINT8 tBTA_GATT_STATUS; + +#define BTA_GATT_INVALID_CONN_ID GATT_INVALID_CONN_ID + + +/* Client callback function events */ +#define BTA_GATTC_REG_EVT 0 /* GATT client is registered. */ +#define BTA_GATTC_DEREG_EVT 1 /* GATT client deregistered event */ +#define BTA_GATTC_OPEN_EVT 2 /* GATTC open request status event */ +#define BTA_GATTC_READ_CHAR_EVT 3 /* GATT read characteristic event */ +#define BTA_GATTC_WRITE_CHAR_EVT 4 /* GATT write characteristic or char descriptor event */ +#define BTA_GATTC_CLOSE_EVT 5 /* GATTC close request status event */ +#define BTA_GATTC_SEARCH_CMPL_EVT 6 /* GATT discovery complete event */ +#define BTA_GATTC_SEARCH_RES_EVT 7 /* GATT discovery result event */ +#define BTA_GATTC_READ_DESCR_EVT 8 /* GATT read characterisitc descriptor event */ +#define BTA_GATTC_WRITE_DESCR_EVT 9 /* GATT write characteristic descriptor event */ +#define BTA_GATTC_NOTIF_EVT 10 /* GATT attribute notification event */ +#define BTA_GATTC_PREP_WRITE_EVT 11 /* GATT prepare write event */ +#define BTA_GATTC_EXEC_EVT 12 /* execute write complete event */ +#define BTA_GATTC_ACL_EVT 13 /* ACL up event */ +#define BTA_GATTC_CANCEL_OPEN_EVT 14 /* cancel open event */ +#define BTA_GATTC_SRVC_CHG_EVT 15 /* service change event */ +#define BTA_GATTC_LISTEN_EVT 16 /* listen event */ +#define BTA_GATTC_ENC_CMPL_CB_EVT 17 /* encryption complete callback event */ +#define BTA_GATTC_CFG_MTU_EVT 18 /* configure MTU complete event */ +#define BTA_GATTC_ADV_DATA_EVT 19 /* ADV data event */ +#define BTA_GATTC_MULT_ADV_ENB_EVT 20 /* Enable Multi ADV event */ +#define BTA_GATTC_MULT_ADV_UPD_EVT 21 /* Update parameter event */ +#define BTA_GATTC_MULT_ADV_DATA_EVT 22 /* Multi ADV data event */ +#define BTA_GATTC_MULT_ADV_DIS_EVT 23 /* Disable Multi ADV event */ +#define BTA_GATTC_CONGEST_EVT 24 /* Congestion event */ +#define BTA_GATTC_BTH_SCAN_ENB_EVT 25 /* Enable batch scan event */ +#define BTA_GATTC_BTH_SCAN_CFG_EVT 26 /* Config storage event */ +#define BTA_GATTC_BTH_SCAN_RD_EVT 27 /* Batch scan reports read event */ +#define BTA_GATTC_BTH_SCAN_THR_EVT 28 /* Batch scan threshold event */ +#define BTA_GATTC_BTH_SCAN_PARAM_EVT 29 /* Batch scan param event */ +#define BTA_GATTC_BTH_SCAN_DIS_EVT 30 /* Disable batch scan event */ +#define BTA_GATTC_SCAN_FLT_CFG_EVT 31 /* Scan filter config event */ +#define BTA_GATTC_SCAN_FLT_PARAM_EVT 32 /* Param filter event */ +#define BTA_GATTC_SCAN_FLT_STATUS_EVT 33 /* Filter status event */ +#define BTA_GATTC_ADV_VSC_EVT 34 /* ADV VSC event */ + +typedef UINT8 tBTA_GATTC_EVT; + +typedef tGATT_IF tBTA_GATTC_IF; + +typedef struct +{ + UINT16 unit; /* as UUIUD defined by SIG */ + UINT16 descr; /* as UUID as defined by SIG */ + tGATT_FORMAT format; + INT8 exp; + UINT8 name_spc; /* The name space of the description */ +}tBTA_GATT_CHAR_PRES; + +#define BTA_GATT_CLT_CONFIG_NONE GATT_CLT_CONFIG_NONE /* 0x0000 */ +#define BTA_GATT_CLT_CONFIG_NOTIFICATION GATT_CLT_CONFIG_NOTIFICATION /* 0x0001 */ +#define BTA_GATT_CLT_CONFIG_INDICATION GATT_CLT_CONFIG_INDICATION /* 0x0002 */ +typedef UINT16 tBTA_GATT_CLT_CHAR_CONFIG; + +/* characteristic descriptor: server configuration value +*/ +#define BTA_GATT_SVR_CONFIG_NONE GATT_SVR_CONFIG_NONE /* 0x0000 */ +#define BTA_GATT_SVR_CONFIG_BROADCAST GATT_SVR_CONFIG_BROADCAST /* 0x0001 */ +typedef UINT16 tBTA_GATT_SVR_CHAR_CONFIG; + +/* Characteristic Aggregate Format attribute value +*/ +#define BTA_GATT_AGGR_HANDLE_NUM_MAX 10 +typedef struct +{ + UINT8 num_handle; + UINT16 handle_list[BTA_GATT_AGGR_HANDLE_NUM_MAX]; +} tBTA_GATT_CHAR_AGGRE; +typedef tGATT_VALID_RANGE tBTA_GATT_VALID_RANGE; + +typedef struct +{ + UINT16 len; + UINT8 *p_value; +}tBTA_GATT_UNFMT; + +#define BTA_GATT_MAX_ATTR_LEN GATT_MAX_ATTR_LEN + +#define BTA_GATTC_TYPE_WRITE GATT_WRITE +#define BTA_GATTC_TYPE_WRITE_NO_RSP GATT_WRITE_NO_RSP +typedef UINT8 tBTA_GATTC_WRITE_TYPE; + +#define BTA_GATT_CONN_UNKNOWN 0 +#define BTA_GATT_CONN_L2C_FAILURE GATT_CONN_L2C_FAILURE /* general l2cap resource failure */ +#define BTA_GATT_CONN_TIMEOUT GATT_CONN_TIMEOUT /* 0x08 connection timeout */ +#define BTA_GATT_CONN_TERMINATE_PEER_USER GATT_CONN_TERMINATE_PEER_USER /* 0x13 connection terminate by peer user */ +#define BTA_GATT_CONN_TERMINATE_LOCAL_HOST GATT_CONN_TERMINATE_LOCAL_HOST/* 0x16 connectionterminated by local host */ +#define BTA_GATT_CONN_FAIL_ESTABLISH GATT_CONN_FAIL_ESTABLISH /* 0x03E connection fail to establish */ +#define BTA_GATT_CONN_LMP_TIMEOUT GATT_CONN_LMP_TIMEOUT /* 0x22 connection fail for LMP response tout */ +#define BTA_GATT_CONN_CANCEL GATT_CONN_CANCEL /* 0x0100 L2CAP connection cancelled */ +#define BTA_GATT_CONN_NONE 0x0101 /* 0x0101 no connection to cancel */ +typedef UINT16 tBTA_GATT_REASON; + +typedef struct +{ + tBTA_GATT_ID id; + BOOLEAN is_primary; +}tBTA_GATT_SRVC_ID; + +typedef struct +{ + tBTA_GATT_SRVC_ID srvc_id; + tBTA_GATT_ID char_id; +}tBTA_GATTC_CHAR_ID; + +typedef struct +{ + tBTA_GATTC_CHAR_ID char_id; + tBTA_GATT_ID descr_id; +}tBTA_GATTC_CHAR_DESCR_ID; + +typedef struct +{ + tBTA_GATT_SRVC_ID srvc_id; + tBTA_GATT_SRVC_ID incl_svc_id; +}tBTA_GATTC_INCL_SVC_ID; + +#define BTA_GATT_TYPE_CHAR 0 +#define BTA_GATT_TYPE_CHAR_DESCR 1 +typedef UINT8 tBTA_GATT_ID_TYPE; + +typedef struct +{ + tBTA_GATT_ID_TYPE id_type; + union + { + tBTA_GATTC_CHAR_ID char_id; + tBTA_GATTC_CHAR_DESCR_ID char_descr_id; + + } id_value; +}tBTA_GATTC_ATTR_ID; + +#define BTA_GATTC_MULTI_MAX GATT_MAX_READ_MULTI_HANDLES + +typedef struct +{ + UINT8 num_attr; + tBTA_GATTC_ATTR_ID id_list[BTA_GATTC_MULTI_MAX]; + +}tBTA_GATTC_MULTI; + +#define BTA_GATT_AUTH_REQ_NONE GATT_AUTH_REQ_NONE +#define BTA_GATT_AUTH_REQ_NO_MITM GATT_AUTH_REQ_NO_MITM /* unauthenticated encryption */ +#define BTA_GATT_AUTH_REQ_MITM GATT_AUTH_REQ_MITM /* authenticated encryption */ +#define BTA_GATT_AUTH_REQ_SIGNED_NO_MITM GATT_AUTH_REQ_SIGNED_NO_MITM +#define BTA_GATT_AUTH_REQ_SIGNED_MITM GATT_AUTH_REQ_SIGNED_MITM + +typedef tGATT_AUTH_REQ tBTA_GATT_AUTH_REQ; + +enum +{ + BTA_GATTC_ATTR_TYPE_INCL_SRVC, + BTA_GATTC_ATTR_TYPE_CHAR, + BTA_GATTC_ATTR_TYPE_CHAR_DESCR, + BTA_GATTC_ATTR_TYPE_SRVC +}; +typedef UINT8 tBTA_GATTC_ATTR_TYPE; + + +typedef struct +{ + tBT_UUID uuid; + UINT16 s_handle; + UINT16 e_handle; /* used for service only */ + UINT8 attr_type; + UINT8 id; + UINT8 prop; /* used when attribute type is characteristic */ + BOOLEAN is_primary; /* used when attribute type is service */ +}tBTA_GATTC_NV_ATTR; + +/* callback data structure */ +typedef struct +{ + tBTA_GATT_STATUS status; + tBTA_GATTC_IF client_if; +// btla-specific ++ + tBT_UUID app_uuid; +// btla-specific -- +}tBTA_GATTC_REG; + +typedef struct +{ + UINT8 num_pres_fmt; /* number of presentation format aggregated*/ + tBTA_GATTC_CHAR_DESCR_ID pre_format[BTA_GATTC_MULTI_MAX]; +}tBTA_GATT_CHAR_AGGRE_VALUE; + +typedef union +{ + tBTA_GATT_CHAR_AGGRE_VALUE aggre_value; + tBTA_GATT_UNFMT unformat; + +}tBTA_GATT_READ_VAL; + +typedef struct +{ + UINT16 conn_id; + tBTA_GATT_STATUS status; + tBTA_GATT_SRVC_ID srvc_id; + tBTA_GATT_ID char_id; + tBTA_GATT_ID descr_type; + tBTA_GATT_READ_VAL *p_value; +}tBTA_GATTC_READ; + +typedef struct +{ + UINT16 conn_id; + tBTA_GATT_STATUS status; + tBTA_GATT_SRVC_ID srvc_id; + tBTA_GATT_ID char_id; + tBTA_GATT_ID descr_type; +}tBTA_GATTC_WRITE; + +typedef struct +{ + UINT16 conn_id; + tBTA_GATT_STATUS status; +}tBTA_GATTC_EXEC_CMPL; + +typedef struct +{ + UINT16 conn_id; + tBTA_GATT_STATUS status; +}tBTA_GATTC_SEARCH_CMPL; + +typedef struct +{ + UINT16 conn_id; + tBTA_GATT_SRVC_ID service_uuid; +}tBTA_GATTC_SRVC_RES; + +typedef struct +{ + UINT16 conn_id; + tBTA_GATT_STATUS status; + UINT16 mtu; +}tBTA_GATTC_CFG_MTU; + +typedef struct +{ + tBTA_GATT_STATUS status; + UINT16 conn_id; + tBTA_GATTC_IF client_if; + BD_ADDR remote_bda; + tBTA_TRANSPORT transport; + UINT16 mtu; +}tBTA_GATTC_OPEN; + +typedef struct +{ + tBTA_GATT_STATUS status; + UINT16 conn_id; + tBTA_GATTC_IF client_if; + BD_ADDR remote_bda; + tBTA_GATT_REASON reason; /* disconnect reason code, not useful when connect event is reported */ +}tBTA_GATTC_CLOSE; + +typedef struct +{ + UINT16 conn_id; + BD_ADDR bda; + tBTA_GATTC_CHAR_ID char_id; + tBTA_GATT_ID descr_type; + UINT16 len; + UINT8 value[BTA_GATT_MAX_ATTR_LEN]; + BOOLEAN is_notify; +}tBTA_GATTC_NOTIFY; + +typedef struct +{ + UINT16 conn_id; + BOOLEAN congested; /* congestion indicator */ +}tBTA_GATTC_CONGEST; + +// btla-specific ++ +typedef struct +{ + tBTA_GATT_STATUS status; + tBTA_GATTC_IF client_if; + UINT16 conn_id; + BD_ADDR remote_bda; +}tBTA_GATTC_OPEN_CLOSE; +// btla-specific -- + +typedef struct +{ + tBTA_GATTC_IF client_if; + BD_ADDR remote_bda; +}tBTA_GATTC_ENC_CMPL_CB; + +typedef union +{ + tBTA_GATT_STATUS status; + + tBTA_GATTC_SEARCH_CMPL search_cmpl; /* discovery complete */ + tBTA_GATTC_SRVC_RES srvc_res; /* discovery result */ + tBTA_GATTC_REG reg_oper; /* registration data */ + tBTA_GATTC_OPEN open; + tBTA_GATTC_CLOSE close; + tBTA_GATTC_READ read; /* read attribute/descriptor data */ + tBTA_GATTC_WRITE write; /* write complete data */ + tBTA_GATTC_EXEC_CMPL exec_cmpl; /* execute complete */ + tBTA_GATTC_NOTIFY notify; /* notification/indication event data */ + tBTA_GATTC_ENC_CMPL_CB enc_cmpl; + BD_ADDR remote_bda; /* service change event */ + tBTA_GATTC_CFG_MTU cfg_mtu; /* configure MTU operation */ + tBTA_GATTC_CONGEST congest; +} tBTA_GATTC; + +/* GATTC enable callback function */ +typedef void (tBTA_GATTC_ENB_CBACK)(tBTA_GATT_STATUS status); + +/* Client callback function */ +typedef void (tBTA_GATTC_CBACK)(tBTA_GATTC_EVT event, tBTA_GATTC *p_data); + + +/* GATT Server Data Structure */ +/* Server callback function events */ +#define BTA_GATTS_REG_EVT 0 +#define BTA_GATTS_READ_EVT GATTS_REQ_TYPE_READ /* 1 */ +#define BTA_GATTS_WRITE_EVT GATTS_REQ_TYPE_WRITE /* 2 */ +#define BTA_GATTS_EXEC_WRITE_EVT GATTS_REQ_TYPE_WRITE_EXEC /* 3 */ +#define BTA_GATTS_MTU_EVT GATTS_REQ_TYPE_MTU /* 4 */ +#define BTA_GATTS_CONF_EVT GATTS_REQ_TYPE_CONF /* 5 */ +#define BTA_GATTS_DEREG_EVT 6 +#define BTA_GATTS_CREATE_EVT 7 +#define BTA_GATTS_ADD_INCL_SRVC_EVT 8 +#define BTA_GATTS_ADD_CHAR_EVT 9 +#define BTA_GATTS_ADD_CHAR_DESCR_EVT 10 +#define BTA_GATTS_DELELTE_EVT 11 +#define BTA_GATTS_START_EVT 12 +#define BTA_GATTS_STOP_EVT 13 +#define BTA_GATTS_CONNECT_EVT 14 +#define BTA_GATTS_DISCONNECT_EVT 15 +#define BTA_GATTS_OPEN_EVT 16 +#define BTA_GATTS_CANCEL_OPEN_EVT 17 +#define BTA_GATTS_CLOSE_EVT 18 +#define BTA_GATTS_LISTEN_EVT 19 +#define BTA_GATTS_CONGEST_EVT 20 + +typedef UINT8 tBTA_GATTS_EVT; +typedef tGATT_IF tBTA_GATTS_IF; + +/* Attribute permissions +*/ +#define BTA_GATT_PERM_READ GATT_PERM_READ /* bit 0 - 0x0001 */ +#define BTA_GATT_PERM_READ_ENCRYPTED GATT_PERM_READ_ENCRYPTED /* bit 1 - 0x0002 */ +#define BTA_GATT_PERM_READ_ENC_MITM GATT_PERM_READ_ENC_MITM /* bit 2 - 0x0004 */ +#define BTA_GATT_PERM_WRITE GATT_PERM_WRITE /* bit 4 - 0x0010 */ +#define BTA_GATT_PERM_WRITE_ENCRYPTED GATT_PERM_WRITE_ENCRYPTED /* bit 5 - 0x0020 */ +#define BTA_GATT_PERM_WRITE_ENC_MITM GATT_PERM_WRITE_ENC_MITM /* bit 6 - 0x0040 */ +#define BTA_GATT_PERM_WRITE_SIGNED GATT_PERM_WRITE_SIGNED /* bit 7 - 0x0080 */ +#define BTA_GATT_PERM_WRITE_SIGNED_MITM GATT_PERM_WRITE_SIGNED_MITM /* bit 8 - 0x0100 */ +typedef UINT16 tBTA_GATT_PERM; + +#define BTA_GATTS_INVALID_APP 0xff + +#define BTA_GATTS_INVALID_IF 0 + +/* definition of characteristic properties */ +#define BTA_GATT_CHAR_PROP_BIT_BROADCAST GATT_CHAR_PROP_BIT_BROADCAST /* 0x01 */ +#define BTA_GATT_CHAR_PROP_BIT_READ GATT_CHAR_PROP_BIT_READ /* 0x02 */ +#define BTA_GATT_CHAR_PROP_BIT_WRITE_NR GATT_CHAR_PROP_BIT_WRITE_NR /* 0x04 */ +#define BTA_GATT_CHAR_PROP_BIT_WRITE GATT_CHAR_PROP_BIT_WRITE /* 0x08 */ +#define BTA_GATT_CHAR_PROP_BIT_NOTIFY GATT_CHAR_PROP_BIT_NOTIFY /* 0x10 */ +#define BTA_GATT_CHAR_PROP_BIT_INDICATE GATT_CHAR_PROP_BIT_INDICATE /* 0x20 */ +#define BTA_GATT_CHAR_PROP_BIT_AUTH GATT_CHAR_PROP_BIT_AUTH /* 0x40 */ +#define BTA_GATT_CHAR_PROP_BIT_EXT_PROP GATT_CHAR_PROP_BIT_EXT_PROP /* 0x80 */ +typedef UINT8 tBTA_GATT_CHAR_PROP; + +#ifndef BTA_GATTC_CHAR_DESCR_MAX +#define BTA_GATTC_CHAR_DESCR_MAX 7 +#endif + +/*********************** NV callback Data Definitions ********************** +*/ +typedef struct +{ + tBT_UUID app_uuid128; + tBT_UUID svc_uuid; + UINT16 svc_inst; + UINT16 s_handle; + UINT16 e_handle; + BOOLEAN is_primary; /* primary service or secondary */ +} tBTA_GATTS_HNDL_RANGE; + +#define BTA_GATTS_SRV_CHG_CMD_ADD_CLIENT GATTS_SRV_CHG_CMD_ADD_CLIENT +#define BTA_GATTS_SRV_CHG_CMD_UPDATE_CLIENT GATTS_SRV_CHG_CMD_UPDATE_CLIENT +#define BTA_GATTS_SRV_CHG_CMD_REMOVE_CLIENT GATTS_SRV_CHG_CMD_REMOVE_CLIENT +#define BTA_GATTS_SRV_CHG_CMD_READ_NUM_CLENTS GATTS_SRV_CHG_CMD_READ_NUM_CLENTS +#define BTA_GATTS_SRV_CHG_CMD_READ_CLENT GATTS_SRV_CHG_CMD_READ_CLENT +typedef tGATTS_SRV_CHG_CMD tBTA_GATTS_SRV_CHG_CMD; + +typedef tGATTS_SRV_CHG tBTA_GATTS_SRV_CHG; +typedef tGATTS_SRV_CHG_REQ tBTA_GATTS_SRV_CHG_REQ; +typedef tGATTS_SRV_CHG_RSP tBTA_GATTS_SRV_CHG_RSP; + +#define BTA_GATT_TRANSPORT_LE GATT_TRANSPORT_LE +#define BTA_GATT_TRANSPORT_BR_EDR GATT_TRANSPORT_BR_EDR +#define BTA_GATT_TRANSPORT_LE_BR_EDR GATT_TRANSPORT_LE_BR_EDR +typedef UINT8 tBTA_GATT_TRANSPORT; + +/* attribute value */ +typedef tGATT_VALUE tBTA_GATT_VALUE; + +/* attribute response data */ +typedef tGATTS_RSP tBTA_GATTS_RSP; + +/* attribute request data from the client */ +#define BTA_GATT_PREP_WRITE_CANCEL 0x00 +#define BTA_GATT_PREP_WRITE_EXEC 0x01 +typedef tGATT_EXEC_FLAG tBTA_GATT_EXEC_FLAG; + +/* read request always based on UUID */ +typedef tGATT_READ_REQ tTA_GBATT_READ_REQ; + +/* write request data */ +typedef tGATT_WRITE_REQ tBTA_GATT_WRITE_REQ; + +/* callback data for server access request from client */ +typedef tGATTS_DATA tBTA_GATTS_REQ_DATA; + +typedef struct +{ + tBTA_GATT_STATUS status; + BD_ADDR remote_bda; + UINT32 trans_id; + UINT16 conn_id; + tBTA_GATTS_REQ_DATA *p_data; +}tBTA_GATTS_REQ; + +typedef struct +{ + tBTA_GATTS_IF server_if; + tBTA_GATT_STATUS status; +// btla-specific ++ + tBT_UUID uuid; +// btla-specific -- +}tBTA_GATTS_REG_OPER; + + +typedef struct +{ + tBTA_GATTS_IF server_if; + UINT16 service_id; +// btla-specific ++ + UINT16 svc_instance; + BOOLEAN is_primary; + tBTA_GATT_STATUS status; + tBT_UUID uuid; +// btla-specific -- +}tBTA_GATTS_CREATE; + +typedef struct +{ + tBTA_GATTS_IF server_if; + UINT16 service_id; + UINT16 attr_id; + tBTA_GATT_STATUS status; +// btla-specific ++ + tBT_UUID char_uuid; +// btla-specific -- +}tBTA_GATTS_ADD_RESULT; + +typedef struct +{ + tBTA_GATTS_IF server_if; + UINT16 service_id; + tBTA_GATT_STATUS status; +}tBTA_GATTS_SRVC_OPER; + + +typedef struct +{ + tBTA_GATTS_IF server_if; + BD_ADDR remote_bda; + UINT16 conn_id; + tBTA_GATT_REASON reason; /* report disconnect reason */ + tBTA_GATT_TRANSPORT transport; +}tBTA_GATTS_CONN; + +typedef struct +{ + UINT16 conn_id; + BOOLEAN congested; /* report channel congestion indicator */ +}tBTA_GATTS_CONGEST; + +typedef struct +{ + UINT16 conn_id; /* connection ID */ + tBTA_GATT_STATUS status; /* notification/indication status */ +}tBTA_GATTS_CONF; + +/* GATTS callback data */ +typedef union +{ + tBTA_GATTS_REG_OPER reg_oper; + tBTA_GATTS_CREATE create; + tBTA_GATTS_SRVC_OPER srvc_oper; + tBTA_GATT_STATUS status; /* BTA_GATTS_LISTEN_EVT */ + tBTA_GATTS_ADD_RESULT add_result; /* add included service: BTA_GATTS_ADD_INCL_SRVC_EVT + add char : BTA_GATTS_ADD_CHAR_EVT + add char descriptor: BTA_GATTS_ADD_CHAR_DESCR_EVT */ + tBTA_GATTS_REQ req_data; + tBTA_GATTS_CONN conn; /* BTA_GATTS_CONN_EVT */ + tBTA_GATTS_CONGEST congest; /* BTA_GATTS_CONGEST_EVT callback data */ + tBTA_GATTS_CONF confirm; /* BTA_GATTS_CONF_EVT callback data */ +}tBTA_GATTS; + +/* GATTS enable callback function */ +typedef void (tBTA_GATTS_ENB_CBACK)(tBTA_GATT_STATUS status); + +/* Server callback function */ +typedef void (tBTA_GATTS_CBACK)(tBTA_GATTS_EVT event, tBTA_GATTS *p_data); + +/***************************************************************************** +** External Function Declarations +*****************************************************************************/ + +#ifdef __cplusplus +extern "C" +{ +#endif + +/************************** +** Client Functions +***************************/ + +/******************************************************************************* +** +** Function BTA_GATTC_Disable +** +** Description This function is called to disable the GATTC module +** +** Parameters None. +** +** Returns None +** +*******************************************************************************/ +extern void BTA_GATTC_Disable(void); + +/******************************************************************************* +** +** Function BTA_GATTC_AppRegister +** +** Description This function is called to register application callbacks +** with BTA GATTC module. +** +** Parameters p_app_uuid - applicaiton UUID +** p_client_cb - pointer to the application callback function. +** +** Returns None +** +*******************************************************************************/ +extern void BTA_GATTC_AppRegister(tBT_UUID *p_app_uuid, tBTA_GATTC_CBACK *p_client_cb); + +/******************************************************************************* +** +** Function BTA_GATTC_AppDeregister +** +** Description This function is called to deregister an application +** from BTA GATTC module. +** +** Parameters client_if - client interface identifier. +** +** Returns None +** +*******************************************************************************/ +extern void BTA_GATTC_AppDeregister (tBTA_GATTC_IF client_if); + +/******************************************************************************* +** +** Function BTA_GATTC_Open +** +** Description Open a direct connection or add a background auto connection +** bd address +** +** Parameters client_if: server interface. +** remote_bda: remote device BD address. +** is_direct: direct connection or background auto connection +** +** Returns void +** +*******************************************************************************/ +extern void BTA_GATTC_Open(tBTA_GATTC_IF client_if, BD_ADDR remote_bda, + BOOLEAN is_direct, tBTA_GATT_TRANSPORT transport); + +/******************************************************************************* +** +** Function BTA_GATTC_CancelOpen +** +** Description Open a direct connection or add a background auto connection +** bd address +** +** Parameters client_if: server interface. +** remote_bda: remote device BD address. +** is_direct: direct connection or background auto connection +** +** Returns void +** +*******************************************************************************/ +extern void BTA_GATTC_CancelOpen(tBTA_GATTC_IF client_if, BD_ADDR remote_bda, BOOLEAN is_direct); + +/******************************************************************************* +** +** Function BTA_GATTC_Close +** +** Description Close a connection to a GATT server. +** +** Parameters conn_id: connectino ID to be closed. +** +** Returns void +** +*******************************************************************************/ +extern void BTA_GATTC_Close(UINT16 conn_id); + +/******************************************************************************* +** +** Function BTA_GATTC_ServiceSearchRequest +** +** Description This function is called to request a GATT service discovery +** on a GATT server. This function report service search result +** by a callback event, and followed by a service search complete +** event. +** +** Parameters conn_id: connection ID. +** p_srvc_uuid: a UUID of the service application is interested in. +** If Null, discover for all services. +** +** Returns None +** +*******************************************************************************/ +extern void BTA_GATTC_ServiceSearchRequest(UINT16 conn_id, tBT_UUID *p_srvc_uuid); + +/******************************************************************************* +** +** Function BTA_GATTC_GetFirstChar +** +** Description This function is called to find the first charatceristic of the +** service on the given server. +** +** Parameters conn_id: connection ID which identify the server. +** p_srvc_id: the service ID of which the characteristic is belonged to. +** p_char_uuid_cond: Characteristic UUID, if NULL find the first available +** characteristic. +** p_char_result: output parameter which will store the GATT +** characteristic ID. +** p_property: output parameter to carry the characteristic property. +** +** Returns returns status. +** +*******************************************************************************/ +extern tBTA_GATT_STATUS BTA_GATTC_GetFirstChar (UINT16 conn_id, + tBTA_GATT_SRVC_ID *p_srvc_id, + tBT_UUID *p_char_uuid_cond, + tBTA_GATTC_CHAR_ID *p_char_result, + tBTA_GATT_CHAR_PROP *p_property); + +/******************************************************************************* +** +** Function BTA_GATTC_GetNextChar +** +** Description This function is called to find the next charatceristic of the +** service on the given server. +** +** Parameters conn_id: connection ID which identify the server. +** p_start_char_id: start the characteristic search from the next record +** after the one identified by char_id. +** p_char_uuid_cond: Characteristic UUID, if NULL find the first available +** characteristic. +** p_char_result: output parameter which will store the GATT +** characteristic ID. +** p_property: output parameter, characteristic property. +** +** Returns returns status. +** +*******************************************************************************/ +extern tBTA_GATT_STATUS BTA_GATTC_GetNextChar (UINT16 conn_id, + tBTA_GATTC_CHAR_ID *p_start_char_id, + tBT_UUID *p_char_uuid_cond, + tBTA_GATTC_CHAR_ID *p_char_result, + tBTA_GATT_CHAR_PROP *p_property); + +/******************************************************************************* +** +** Function BTA_GATTC_GetFirstCharDescr +** +** Description This function is called to find the first charatceristic descriptor of the +** charatceristic on the given server. +** +** Parameters conn_id: connection ID which identify the server. +** p_char_id: the characteristic ID of which the descriptor is belonged to. +** p_descr_uuid_cond: Characteristic Descr UUID, if NULL find the first available +** characteristic. +** p_descr_result: output parameter which will store the GATT +** characteristic descriptor ID. +** +** Returns returns status. +** +*******************************************************************************/ +extern tBTA_GATT_STATUS BTA_GATTC_GetFirstCharDescr (UINT16 conn_id, tBTA_GATTC_CHAR_ID *p_char_id, + tBT_UUID *p_descr_uuid_cond, + tBTA_GATTC_CHAR_DESCR_ID *p_descr_result); + +/******************************************************************************* +** +** Function BTA_GATTC_GetNextCharDescr +** +** Description This function is called to find the next charatceristic of the +** service on the given server. +** +** Parameters conn_id: connection ID which identify the server. +** p_start_descr_id: start the characteristic search from the next record +** after the one identified by p_start_descr_id. +** p_descr_uuid_cond: Characteristic descriptor UUID, if NULL find +** the first available characteristic descriptor. +** p_descr_result: output parameter which will store the GATT +** characteristic descriptor ID. +** +** Returns returns status. +** +*******************************************************************************/ +extern tBTA_GATT_STATUS BTA_GATTC_GetNextCharDescr (UINT16 conn_id, + tBTA_GATTC_CHAR_DESCR_ID *p_start_descr_id, + tBT_UUID *p_descr_uuid_cond, + tBTA_GATTC_CHAR_DESCR_ID *p_descr_result); + + +/******************************************************************************* +** +** Function BTA_GATTC_GetFirstIncludedService +** +** Description This function is called to find the first included service of the +** service on the given server. +** +** Parameters conn_id: connection ID which identify the server. +** p_srvc_id: the service ID of which the included service is belonged to. +** p_uuid_cond: include service UUID, if NULL find the first available +** included service. +** p_result: output parameter which will store the GATT ID +** of the included service found. +** +** Returns returns status. +** +*******************************************************************************/ +extern tBTA_GATT_STATUS BTA_GATTC_GetFirstIncludedService(UINT16 conn_id, + tBTA_GATT_SRVC_ID *p_srvc_id, + tBT_UUID *p_uuid_cond, + tBTA_GATTC_INCL_SVC_ID *p_result); + +/******************************************************************************* +** +** Function BTA_GATTC_GetNextIncludedService +** +** Description This function is called to find the next included service of the +** service on the given server. +** +** Parameters conn_id: connection ID which identify the server. +** p_start_id: start the search from the next record +** after the one identified by p_start_id. +** p_uuid_cond: Included service UUID, if NULL find the first available +** included service. +** p_result: output parameter which will store the GATT ID +** of the included service found. +** +** Returns returns status. +** +*******************************************************************************/ +extern tBTA_GATT_STATUS BTA_GATTC_GetNextIncludedService(UINT16 conn_id, + tBTA_GATTC_INCL_SVC_ID *p_start_id, + tBT_UUID *p_uuid_cond, + tBTA_GATTC_INCL_SVC_ID *p_result); + +/******************************************************************************* +** +** Function BTA_GATTC_ReadCharacteristic +** +** Description This function is called to read a service's characteristics of +** the given characteritisc ID. +** +** Parameters conn_id - connectino ID. +** p_char_id - characteritic ID to read. +** +** Returns None +** +*******************************************************************************/ +extern void BTA_GATTC_ReadCharacteristic (UINT16 conn_id, + tBTA_GATTC_CHAR_ID *p_char_id, + tBTA_GATT_AUTH_REQ auth_req); + +/******************************************************************************* +** +** Function BTA_GATTC_ReadCharDescr +** +** Description This function is called to read a characteristics descriptor. +** +** Parameters conn_id - connection ID. +** p_char_descr_id - characteritic descriptor ID to read. +** +** Returns None +** +*******************************************************************************/ +extern void BTA_GATTC_ReadCharDescr (UINT16 conn_id, + tBTA_GATTC_CHAR_DESCR_ID *p_char_descr_id, + tBTA_GATT_AUTH_REQ auth_req); + +/******************************************************************************* +** +** Function BTA_GATTC_WriteCharValue +** +** Description This function is called to write characteristic value. +** +** Parameters conn_id - connection ID. +** p_char_id - characteristic ID to write. +** write_type - type of write. +** len: length of the data to be written. +** p_value - the value to be written. +** +** Returns None +** +*******************************************************************************/ +extern void BTA_GATTC_WriteCharValue (UINT16 conn_id, + tBTA_GATTC_CHAR_ID *p_char_id, + tBTA_GATTC_WRITE_TYPE write_type, + UINT16 len, + UINT8 *p_value, + tBTA_GATT_AUTH_REQ auth_req); + +/******************************************************************************* +** +** Function BTA_GATTC_WriteCharDescr +** +** Description This function is called to write characteristic descriptor value. +** +** Parameters conn_id - connection ID +** p_char_descr_id - characteristic descriptor ID to write. +** write_type - type of write. +** p_value - the value to be written. +** +** Returns None +** +*******************************************************************************/ +extern void BTA_GATTC_WriteCharDescr (UINT16 conn_id, + tBTA_GATTC_CHAR_DESCR_ID *p_char_descr_id, + tBTA_GATTC_WRITE_TYPE write_type, + tBTA_GATT_UNFMT *p_data, + tBTA_GATT_AUTH_REQ auth_req); + +/******************************************************************************* +** +** Function BTA_GATTC_SendIndConfirm +** +** Description This function is called to send handle value confirmation. +** +** Parameters conn_id - connection ID. +** p_char_id - characteristic ID to confrim. +** +** Returns None +** +*******************************************************************************/ +extern void BTA_GATTC_SendIndConfirm (UINT16 conn_id, tBTA_GATTC_CHAR_ID *p_char_id); + +/******************************************************************************* +** +** Function BTA_GATTC_RegisterForNotifications +** +** Description This function is called to register for notification of a service. +** +** Parameters client_if - client interface. +** remote_bda - target GATT server. +** p_char_id - pointer to GATT characteristic ID. +** +** Returns OK if registration succeed, otherwise failed. +** +*******************************************************************************/ +extern tBTA_GATT_STATUS BTA_GATTC_RegisterForNotifications (tBTA_GATTC_IF client_if, + BD_ADDR remote_bda, + tBTA_GATTC_CHAR_ID *p_char_id); + + +/******************************************************************************* +** +** Function BTA_GATTC_DeregisterForNotifications +** +** Description This function is called to de-register for notification of a servbice. +** +** Parameters client_if - client interface. +** remote_bda - target GATT server. +** p_char_id - pointer to a GATT characteristic ID. +** +** Returns OK if deregistration succeed, otherwise failed. +** +*******************************************************************************/ +extern tBTA_GATT_STATUS BTA_GATTC_DeregisterForNotifications (tBTA_GATTC_IF client_if, + BD_ADDR remote_bda, + tBTA_GATTC_CHAR_ID *p_char_id); + +/******************************************************************************* +** +** Function BTA_GATTC_PrepareWrite +** +** Description This function is called to prepare write a characteristic value. +** +** Parameters conn_id - connection ID. +** p_char_id - GATT characteritic ID of the service. +** offset - offset of the write value. +** len: length of the data to be written. +** p_value - the value to be written. +** +** Returns None +** +*******************************************************************************/ +extern void BTA_GATTC_PrepareWrite (UINT16 conn_id, + tBTA_GATTC_CHAR_ID *p_char_id, + UINT16 offset, + UINT16 len, + UINT8 *p_value, + tBTA_GATT_AUTH_REQ auth_req); + +/******************************************************************************* +** +** Function BTA_GATTC_ExecuteWrite +** +** Description This function is called to execute write a prepare write sequence. +** +** Parameters conn_id - connection ID. +** is_execute - execute or cancel. +** +** Returns None +** +*******************************************************************************/ +extern void BTA_GATTC_ExecuteWrite (UINT16 conn_id, BOOLEAN is_execute); + +/******************************************************************************* +** +** Function BTA_GATTC_ReadMultiple +** +** Description This function is called to read multiple characteristic or +** characteristic descriptors. +** +** Parameters conn_id - connectino ID. +** p_read_multi - read multiple parameters. +** +** Returns None +** +*******************************************************************************/ +extern void BTA_GATTC_ReadMultiple(UINT16 conn_id, tBTA_GATTC_MULTI *p_read_multi, + tBTA_GATT_AUTH_REQ auth_req); + + +/******************************************************************************* +** +** Function BTA_GATTC_Refresh +** +** Description Refresh the server cache of the remote device +** +** Parameters remote_bda: remote device BD address. +** +** Returns void +** +*******************************************************************************/ +extern void BTA_GATTC_Refresh(BD_ADDR remote_bda); + + +/******************************************************************************* +** +** Function BTA_GATTC_Listen +** +** Description Start advertisement to listen for connection request. +** +** Parameters client_if: server interface. +** start: to start or stop listening for connection +** remote_bda: remote device BD address, if listen to all device +** use NULL. +** +** Returns void +** +*******************************************************************************/ +extern void BTA_GATTC_Listen(tBTA_GATTC_IF client_if, BOOLEAN start, BD_ADDR_PTR target_bda); + +/******************************************************************************* +** +** Function BTA_GATTC_Broadcast +** +** Description Start broadcasting (non-connectable advertisements) +** +** Parameters client_if: client interface. +** start: to start or stop listening for connection +** +** Returns void +** +*******************************************************************************/ +extern void BTA_GATTC_Broadcast(tBTA_GATTC_IF client_if, BOOLEAN start); + + +/******************************************************************************* +** +** Function BTA_GATTC_ConfigureMTU +** +** Description Configure the MTU size in the GATT channel. This can be done +** only once per connection. +** +** Parameters conn_id: connection ID. +** mtu: desired MTU size to use. +** +** Returns void +** +*******************************************************************************/ +extern void BTA_GATTC_ConfigureMTU (UINT16 conn_id, UINT16 mtu); + +/******************************************************************************* +** BTA GATT Server API +********************************************************************************/ + +/******************************************************************************* +** +** Function BTA_GATTS_Init +** +** Description This function is called to initalize GATTS module +** +** Parameters None +** +** Returns None +** +*******************************************************************************/ +extern void BTA_GATTS_Init(); + +/******************************************************************************* +** +** Function BTA_GATTS_Disable +** +** Description This function is called to disable GATTS module +** +** Parameters None. +** +** Returns None +** +*******************************************************************************/ +extern void BTA_GATTS_Disable(void); + +/******************************************************************************* +** +** Function BTA_GATTS_AppRegister +** +** Description This function is called to register application callbacks +** with BTA GATTS module. +** +** Parameters p_app_uuid - applicaiton UUID +** p_cback - pointer to the application callback function. +** +** Returns None +** +*******************************************************************************/ +extern void BTA_GATTS_AppRegister(tBT_UUID *p_app_uuid, tBTA_GATTS_CBACK *p_cback); + + +/******************************************************************************* +** +** Function BTA_GATTS_AppDeregister +** +** Description De-register with BTA GATT Server. +** +** Parameters server_if: server interface +** +** Returns void +** +*******************************************************************************/ +extern void BTA_GATTS_AppDeregister(tBTA_GATTS_IF server_if); + +/******************************************************************************* +** +** Function BTA_GATTS_CreateService +** +** Description Create a service. When service creation is done, a callback +** event BTA_GATTS_CREATE_SRVC_EVT is called to report status +** and service ID to the profile. The service ID obtained in +** the callback function needs to be used when adding included +** service and characteristics/descriptors into the service. +** +** Parameters server_if: server interface. +** p_service_uuid: service UUID. +** inst: instance ID number of this service. +** num_handle: numble of handle requessted for this service. +** is_primary: is this service a primary one or not. +** +** Returns void +** +*******************************************************************************/ +extern void BTA_GATTS_CreateService(tBTA_GATTS_IF server_if, tBT_UUID *p_service_uuid, + UINT8 inst, UINT16 num_handle, BOOLEAN is_primary); + +/******************************************************************************* +** +** Function BTA_GATTS_AddIncludeService +** +** Description This function is called to add an included service. After included +** service is included, a callback event BTA_GATTS_ADD_INCL_SRVC_EVT +** is reported the included service ID. +** +** Parameters service_id: service ID to which this included service is to +** be added. +** included_service_id: the service ID to be included. +** +** Returns void +** +*******************************************************************************/ +extern void BTA_GATTS_AddIncludeService(UINT16 service_id, UINT16 included_service_id); + +/******************************************************************************* +** +** Function BTA_GATTS_AddCharacteristic +** +** Description This function is called to add a characteristic into a service. +** +** Parameters service_id: service ID to which this included service is to +** be added. +** p_char_uuid : Characteristic UUID. +** perm : Characteristic value declaration attribute permission. +** property : Characteristic Properties +** +** Returns None +** +*******************************************************************************/ +extern void BTA_GATTS_AddCharacteristic (UINT16 service_id, tBT_UUID *p_char_uuid, + tBTA_GATT_PERM perm, tBTA_GATT_CHAR_PROP property); + +/******************************************************************************* +** +** Function BTA_GATTS_AddCharDescriptor +** +** Description This function is called to add characteristic descriptor. When +** it's done, a callback event BTA_GATTS_ADD_DESCR_EVT is called +** to report the status and an ID number for this descriptor. +** +** Parameters service_id: service ID to which this charatceristic descriptor is to +** be added. +** perm: descriptor access permission. +** p_descr_uuid: descriptor UUID. +** p_descr_params: descriptor value if it's read only descriptor. +** +** Returns returns status. +** +*******************************************************************************/ +extern void BTA_GATTS_AddCharDescriptor (UINT16 service_id, + tBTA_GATT_PERM perm, + tBT_UUID * p_descr_uuid); + +/******************************************************************************* +** +** Function BTA_GATTS_DeleteService +** +** Description This function is called to delete a service. When this is done, +** a callback event BTA_GATTS_DELETE_EVT is report with the status. +** +** Parameters service_id: service_id to be deleted. +** +** Returns returns none. +** +*******************************************************************************/ +extern void BTA_GATTS_DeleteService(UINT16 service_id); + +/******************************************************************************* +** +** Function BTA_GATTS_StartService +** +** Description This function is called to start a service. +** +** Parameters service_id: the service ID to be started. +** sup_transport: supported trasnport. +** +** Returns None. +** +*******************************************************************************/ +extern void BTA_GATTS_StartService(UINT16 service_id, tBTA_GATT_TRANSPORT sup_transport); + +/******************************************************************************* +** +** Function BTA_GATTS_StopService +** +** Description This function is called to stop a service. +** +** Parameters service_id - service to be topped. +** +** Returns None +** +*******************************************************************************/ +extern void BTA_GATTS_StopService(UINT16 service_id); + +/******************************************************************************* +** +** Function BTA_GATTS_HandleValueIndication +** +** Description This function is called to read a characteristics descriptor. +** +** Parameters conn_id - connection identifier. +** attr_id - attribute ID to indicate. +** data_len - indicate data length. +** p_data: data to indicate. +** need_confirm - if this indication expects a confirmation or not. +** +** Returns None +** +*******************************************************************************/ +extern void BTA_GATTS_HandleValueIndication (UINT16 conn_id, UINT16 attr_id, + UINT16 data_len, + UINT8 *p_data, + BOOLEAN need_confirm); + +/******************************************************************************* +** +** Function BTA_GATTS_SendRsp +** +** Description This function is called to send a response to a request. +** +** Parameters conn_id - connection identifier. +** trans_id - transaction ID. +** status - response status +** p_msg - response data. +** +** Returns None +** +*******************************************************************************/ +extern void BTA_GATTS_SendRsp (UINT16 conn_id, UINT32 trans_id, + tBTA_GATT_STATUS status, tBTA_GATTS_RSP *p_msg); + + +/******************************************************************************* +** +** Function BTA_GATTS_Open +** +** Description Open a direct open connection or add a background auto connection +** bd address +** +** Parameters server_if: server interface. +** remote_bda: remote device BD address. +** is_direct: direct connection or background auto connection +** +** Returns void +** +*******************************************************************************/ +extern void BTA_GATTS_Open(tBTA_GATTS_IF server_if, BD_ADDR remote_bda, + BOOLEAN is_direct, tBTA_GATT_TRANSPORT transport); + + +/******************************************************************************* +** +** Function BTA_GATTS_CancelOpen +** +** Description Cancel a direct open connection or remove a background auto connection +** bd address +** +** Parameters server_if: server interface. +** remote_bda: remote device BD address. +** is_direct: direct connection or background auto connection +** +** Returns void +** +*******************************************************************************/ +extern void BTA_GATTS_CancelOpen(tBTA_GATTS_IF server_if, BD_ADDR remote_bda, BOOLEAN is_direct); + + +/******************************************************************************* +** +** Function BTA_GATTS_Close +** +** Description Close a connection a remote device. +** +** Parameters conn_id: connectino ID to be closed. +** +** Returns void +** +*******************************************************************************/ +extern void BTA_GATTS_Close(UINT16 conn_id); + +/******************************************************************************* +** +** Function BTA_GATTS_Listen +** +** Description Start advertisement to listen for connection request for a +** GATT server +** +** Parameters server_if: server interface. +** start: to start or stop listening for connection +** remote_bda: remote device BD address, if listen to all device +** use NULL. +** +** Returns void +** +*******************************************************************************/ +extern void BTA_GATTS_Listen(tBTA_GATTS_IF server_if, BOOLEAN start, + BD_ADDR_PTR target_bda); + + +#ifdef __cplusplus + +} +#endif + + +#endif /* BTA_GATT_API_H */ diff --git a/components/bt/bluedroid/bta/include/bta_gattc_ci.h b/components/bt/bluedroid/bta/include/bta_gattc_ci.h new file mode 100755 index 0000000000..a64bf89b0f --- /dev/null +++ b/components/bt/bluedroid/bta/include/bta_gattc_ci.h @@ -0,0 +1,119 @@ +/****************************************************************************** + * + * Copyright (C) 2003-2012 Broadcom Corporation + * + * 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 is the interface file for GATT call-in functions. + * + ******************************************************************************/ +#ifndef BTA_GATTC_CI_H +#define BTA_GATTC_CI_H + +#include "bta_gatt_api.h" + +/***************************************************************************** +** Constants and data types +*****************************************************************************/ + +/* Open Complete Event */ +typedef struct +{ + BT_HDR hdr; + tBTA_GATT_STATUS status; +} tBTA_GATTC_CI_EVT; + +#define BTA_GATTC_NV_LOAD_MAX 10 + +/* Read Ready Event */ +typedef struct +{ + BT_HDR hdr; + tBTA_GATT_STATUS status; + UINT16 num_attr; + tBTA_GATTC_NV_ATTR attr[BTA_GATTC_NV_LOAD_MAX]; +} tBTA_GATTC_CI_LOAD; + + +/***************************************************************************** +** Function Declarations +*****************************************************************************/ +#ifdef __cplusplus +extern "C" +{ +#endif + +/******************************************************************************* +** +** Function bta_gattc_ci_cache_open +** +** Description This function sends an event to indicate server cache open +** completed. +** +** Parameters server_bda - server BDA of this cache. +** status - BTA_GATT_OK if full buffer of data, +** BTA_GATT_FAIL if an error has occurred. +** +** Returns void +** +*******************************************************************************/ +extern void bta_gattc_ci_cache_open(BD_ADDR server_bda, UINT16 evt, + tBTA_GATT_STATUS status, UINT16 conn_id); + +/******************************************************************************* +** +** Function bta_gattc_ci_cache_load +** +** Description This function sends an event to BTA indicating the phone has +** load the servere cache and ready to send it to the stack. +** +** Parameters server_bda - server BDA of this cache. +** num_bytes_read - number of bytes read into the buffer +** specified in the read callout-function. +** status - BTA_GATT_OK if full buffer of data, +** BTA_GATT_FAIL if an error has occurred. +** +** Returns void +** +*******************************************************************************/ +extern void bta_gattc_ci_cache_load(BD_ADDR server_bda, UINT16 evt, + UINT16 num_attr, tBTA_GATTC_NV_ATTR *p_atrr, + tBTA_GATT_STATUS status, UINT16 conn_id); + +/******************************************************************************* +** +** Function bta_gattc_ci_save +** +** Description This function sends an event to BTA indicating the phone has +** save the server cache. +** +** Parameters server_bda - server BDA of this cache. +** status - BTA_GATT_OK if full buffer of data, +** BTA_GATT_FAIL if an error has occurred. +** +** Returns void +** +*******************************************************************************/ +extern void bta_gattc_ci_cache_save(BD_ADDR server_bda, UINT16 evt, + tBTA_GATT_STATUS status, UINT16 conn_id); + + +#ifdef __cplusplus +} +#endif + +#endif /* BTA_GATTC_CI_H */ diff --git a/components/bt/bluedroid/bta/include/bta_gattc_co.h b/components/bt/bluedroid/bta/include/bta_gattc_co.h new file mode 100755 index 0000000000..b96ebf3b5d --- /dev/null +++ b/components/bt/bluedroid/bta/include/bta_gattc_co.h @@ -0,0 +1,114 @@ +/****************************************************************************** + * + * Copyright (C) 2009-2013 Broadcom Corporation + * + * 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 is the interface file for BTA GATT client call-out functions. + * + ******************************************************************************/ +#ifndef BTA_GATTC_CO_H +#define BTA_GATTC_CO_H + +#include "bta_gatt_api.h" + +/******************************************************************************* +** +** Function bta_gattc_co_cache_open +** +** Description This callout function is executed by GATTC when a GATT server +** cache is ready to be sent. +** +** Parameter server_bda: server bd address of this cache belongs to +** evt: call in event to be passed in when cache open is done. +** conn_id: connection ID of this cache operation attach to. +** to_save: open cache to save or to load. +** +** Returns void. +** +*******************************************************************************/ +extern void bta_gattc_co_cache_open(BD_ADDR server_bda, UINT16 evt, + UINT16 conn_id, BOOLEAN to_save); + +/******************************************************************************* +** +** Function bta_gattc_co_cache_close +** +** Description This callout function is executed by GATTC when a GATT server +** cache is written completely. +** +** Parameter server_bda: server bd address of this cache belongs to +** conn_id: connection ID of this cache operation attach to. +** +** Returns void. +** +*******************************************************************************/ +extern void bta_gattc_co_cache_close(BD_ADDR server_bda, UINT16 conn_id); + +/******************************************************************************* +** +** Function bta_gattc_co_cache_save +** +** Description This callout function is executed by GATT when a server cache +** is available to save. +** +** Parameter server_bda: server bd address of this cache belongs to +** evt: call in event to be passed in when cache save is done. +** num_attr: number of attribute to be save. +** p_attr: pointer to the list of attributes to save. +** attr_index: starting attribute index of the save operation. +** conn_id: connection ID of this cache operation attach to. +** Returns +** +*******************************************************************************/ +extern void bta_gattc_co_cache_save(BD_ADDR server_bda, UINT16 evt, + UINT16 num_attr, tBTA_GATTC_NV_ATTR *p_attr, + UINT16 attr_index, UINT16 conn_id); + +/******************************************************************************* +** +** Function bta_gattc_co_cache_load +** +** Description This callout function is executed by GATT when server cache +** is required to load. +** +** Parameter server_bda: server bd address of this cache belongs to +** evt: call in event to be passed in when cache save is done. +** num_attr: number of attribute to be save. +** attr_index: starting attribute index of the save operation. +** conn_id: connection ID of this cache operation attach to. +** Returns +** +*******************************************************************************/ +extern void bta_gattc_co_cache_load(BD_ADDR server_bda, UINT16 evt, + UINT16 start_index, UINT16 conn_id); + +/******************************************************************************* +** +** Function bta_gattc_co_cache_reset +** +** Description This callout function is executed by GATTC to reset cache in +** application +** +** Parameter server_bda: server bd address of this cache belongs to +** +** Returns void. +** +*******************************************************************************/ +extern void bta_gattc_co_cache_reset(BD_ADDR server_bda); + +#endif /* BTA_GATT_CO_H */ diff --git a/components/bt/bluedroid/bta/include/bta_gattc_int.h b/components/bt/bluedroid/bta/include/bta_gattc_int.h new file mode 100755 index 0000000000..ad2d61e2f4 --- /dev/null +++ b/components/bt/bluedroid/bta/include/bta_gattc_int.h @@ -0,0 +1,554 @@ +/****************************************************************************** + * + * Copyright (C) 2003-2012 Broadcom Corporation + * + * 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 is the private file for the file transfer client (FTC). + * + ******************************************************************************/ +#ifndef BTA_GATTC_INT_H +#define BTA_GATTC_INT_H + +#include "bt_target.h" +#include "bta_sys.h" +#include "bta_gatt_api.h" +#include "bta_gattc_ci.h" +#include "bta_gattc_co.h" + +#include "gki.h" + +/***************************************************************************** +** Constants and data types +*****************************************************************************/ +enum +{ + BTA_GATTC_API_OPEN_EVT = BTA_SYS_EVT_START(BTA_ID_GATTC), + BTA_GATTC_INT_OPEN_FAIL_EVT, + BTA_GATTC_API_CANCEL_OPEN_EVT, + BTA_GATTC_INT_CANCEL_OPEN_OK_EVT, + + BTA_GATTC_API_READ_EVT, + BTA_GATTC_API_WRITE_EVT, + BTA_GATTC_API_EXEC_EVT, + BTA_GATTC_API_CFG_MTU_EVT, + + BTA_GATTC_API_CLOSE_EVT, + + BTA_GATTC_API_SEARCH_EVT, + BTA_GATTC_API_CONFIRM_EVT, + BTA_GATTC_API_READ_MULTI_EVT, + BTA_GATTC_API_REFRESH_EVT, + + BTA_GATTC_INT_CONN_EVT, + BTA_GATTC_INT_DISCOVER_EVT, + BTA_GATTC_DISCOVER_CMPL_EVT, + BTA_GATTC_OP_CMPL_EVT, + BTA_GATTC_INT_DISCONN_EVT, + + /* for cache loading/saving */ + BTA_GATTC_START_CACHE_EVT, + BTA_GATTC_CI_CACHE_OPEN_EVT, + BTA_GATTC_CI_CACHE_LOAD_EVT, + BTA_GATTC_CI_CACHE_SAVE_EVT, + + BTA_GATTC_INT_START_IF_EVT, + BTA_GATTC_API_REG_EVT, + BTA_GATTC_API_DEREG_EVT, + BTA_GATTC_API_LISTEN_EVT, + BTA_GATTC_API_BROADCAST_EVT, + BTA_GATTC_API_DISABLE_EVT, + BTA_GATTC_ENC_CMPL_EVT +}; +typedef UINT16 tBTA_GATTC_INT_EVT; + +/* max client application GATTC can support */ +#ifndef BTA_GATTC_CL_MAX +#define BTA_GATTC_CL_MAX 8 // 32 +#endif + +/* max known devices GATTC can support */ +#ifndef BTA_GATTC_KNOWN_SR_MAX +#define BTA_GATTC_KNOWN_SR_MAX 5 // 10 +#endif + +#define BTA_GATTC_CONN_MAX GATT_MAX_PHY_CHANNEL + +#ifndef BTA_GATTC_CLCB_MAX + #define BTA_GATTC_CLCB_MAX GATT_CL_MAX_LCB +#endif + +#define BTA_GATTC_WRITE_PREPARE GATT_WRITE_PREPARE + + +/* internal strucutre for GATTC register API */ +typedef struct +{ + BT_HDR hdr; + tBT_UUID app_uuid; + tBTA_GATTC_CBACK *p_cback; +}tBTA_GATTC_API_REG; + +typedef struct +{ + BT_HDR hdr; + tBTA_GATTC_IF client_if; +}tBTA_GATTC_INT_START_IF; + +typedef tBTA_GATTC_INT_START_IF tBTA_GATTC_API_DEREG; +typedef tBTA_GATTC_INT_START_IF tBTA_GATTC_INT_DEREG; + +typedef struct +{ + BT_HDR hdr; + BD_ADDR remote_bda; + tBTA_GATTC_IF client_if; + BOOLEAN is_direct; + tBTA_TRANSPORT transport; +} tBTA_GATTC_API_OPEN; + +typedef tBTA_GATTC_API_OPEN tBTA_GATTC_API_CANCEL_OPEN; + +typedef struct +{ + BT_HDR hdr; + tBTA_GATT_AUTH_REQ auth_req; + tBTA_GATT_SRVC_ID srvc_id; + tBTA_GATT_ID char_id; + tBTA_GATT_ID *p_descr_type; +} tBTA_GATTC_API_READ; + +typedef struct +{ + BT_HDR hdr; + tBTA_GATT_AUTH_REQ auth_req; + tBTA_GATT_SRVC_ID srvc_id; + tBTA_GATT_ID char_id; + tBTA_GATT_ID *p_descr_type; + tBTA_GATTC_WRITE_TYPE write_type; + UINT16 offset; + UINT16 len; + UINT8 *p_value; +}tBTA_GATTC_API_WRITE; + +typedef struct +{ + BT_HDR hdr; + BOOLEAN is_execute; +}tBTA_GATTC_API_EXEC; + +typedef struct +{ + BT_HDR hdr; + tBTA_GATT_SRVC_ID srvc_id; + tBTA_GATT_ID char_id; +} tBTA_GATTC_API_CONFIRM; + +typedef tGATT_CL_COMPLETE tBTA_GATTC_CMPL; + +typedef struct +{ + BT_HDR hdr; + UINT8 op_code; + tGATT_STATUS status; + tBTA_GATTC_CMPL *p_cmpl; +}tBTA_GATTC_OP_CMPL; + +typedef struct +{ + BT_HDR hdr; + tBT_UUID *p_srvc_uuid; +}tBTA_GATTC_API_SEARCH; + +typedef struct +{ + BT_HDR hdr; + tBTA_GATT_AUTH_REQ auth_req; + UINT8 num_attr; + tBTA_GATTC_ATTR_ID *p_id_list; +}tBTA_GATTC_API_READ_MULTI; + +typedef struct +{ + BT_HDR hdr; + BD_ADDR_PTR remote_bda; + tBTA_GATTC_IF client_if; + BOOLEAN start; +} tBTA_GATTC_API_LISTEN; + + +typedef struct +{ + BT_HDR hdr; + UINT16 mtu; +}tBTA_GATTC_API_CFG_MTU; + +typedef struct +{ + BT_HDR hdr; + BD_ADDR remote_bda; + tBTA_GATTC_IF client_if; + UINT8 role; + tBT_TRANSPORT transport; + tGATT_DISCONN_REASON reason; +}tBTA_GATTC_INT_CONN; + +typedef struct +{ + BT_HDR hdr; + BD_ADDR remote_bda; + tBTA_GATTC_IF client_if; +}tBTA_GATTC_ENC_CMPL; + +typedef union +{ + BT_HDR hdr; + tBTA_GATTC_API_REG api_reg; + tBTA_GATTC_API_DEREG api_dereg; + tBTA_GATTC_API_OPEN api_conn; + tBTA_GATTC_API_CANCEL_OPEN api_cancel_conn; + tBTA_GATTC_API_READ api_read; + tBTA_GATTC_API_SEARCH api_search; + tBTA_GATTC_API_WRITE api_write; + tBTA_GATTC_API_CONFIRM api_confirm; + tBTA_GATTC_API_EXEC api_exec; + tBTA_GATTC_API_READ_MULTI api_read_multi; + tBTA_GATTC_API_CFG_MTU api_mtu; + tBTA_GATTC_OP_CMPL op_cmpl; + tBTA_GATTC_CI_EVT ci_open; + tBTA_GATTC_CI_EVT ci_save; + tBTA_GATTC_CI_LOAD ci_load; + tBTA_GATTC_INT_CONN int_conn; + tBTA_GATTC_ENC_CMPL enc_cmpl; + + tBTA_GATTC_INT_START_IF int_start_if; + tBTA_GATTC_INT_DEREG int_dereg; + /* if peripheral role is supported */ + tBTA_GATTC_API_LISTEN api_listen; + +} tBTA_GATTC_DATA; + + +/* GATT server cache on the client */ +typedef union +{ + UINT8 uuid128[LEN_UUID_128]; + UINT16 uuid16; +}tBTA_GATTC_UUID; + +typedef struct gattc_attr_cache +{ + tBTA_GATTC_UUID *p_uuid; + struct gattc_attr_cache *p_next; + UINT16 uuid_len; + UINT16 attr_handle; + UINT8 inst_id; + tBTA_GATT_CHAR_PROP property; /* if characteristic, it is char property; + if included service, flag primary, + if descriptor, not used */ + tBTA_GATTC_ATTR_TYPE attr_type; +// btla-specific ++ +} __attribute__((packed)) tBTA_GATTC_CACHE_ATTR; +// btla-specific -- + +typedef struct gattc_svc_cache +{ + tBTA_GATT_SRVC_ID service_uuid; + tBTA_GATTC_CACHE_ATTR *p_attr; + tBTA_GATTC_CACHE_ATTR *p_last_attr; + UINT16 s_handle; + UINT16 e_handle; + struct gattc_svc_cache *p_next; + tBTA_GATTC_CACHE_ATTR *p_cur_char; +// btla-specific ++ +} __attribute__((packed)) tBTA_GATTC_CACHE; +// btla-specific -- + +typedef struct +{ + tBT_UUID uuid; + UINT16 s_handle; + UINT16 e_handle; + BOOLEAN is_primary; + UINT8 srvc_inst_id; + tBTA_GATT_CHAR_PROP property; +}tBTA_GATTC_ATTR_REC; + + +#define BTA_GATTC_MAX_CACHE_CHAR 40 +#define BTA_GATTC_ATTR_LIST_SIZE (BTA_GATTC_MAX_CACHE_CHAR * sizeof(tBTA_GATTC_ATTR_REC)) + +#ifndef BTA_GATTC_CACHE_SRVR_SIZE + #define BTA_GATTC_CACHE_SRVR_SIZE 600 +#endif + +enum +{ + BTA_GATTC_IDLE_ST = 0, /* Idle */ + BTA_GATTC_W4_CONN_ST, /* Wait for connection - (optional) */ + BTA_GATTC_CONN_ST, /* connected state */ + BTA_GATTC_DISCOVER_ST /* discover is in progress */ +}; +typedef UINT8 tBTA_GATTC_STATE; + +typedef struct +{ + BOOLEAN in_use; + BD_ADDR server_bda; + BOOLEAN connected; + +#define BTA_GATTC_SERV_IDLE 0 +#define BTA_GATTC_SERV_LOAD 1 +#define BTA_GATTC_SERV_SAVE 2 +#define BTA_GATTC_SERV_DISC 3 +#define BTA_GATTC_SERV_DISC_ACT 4 + + UINT8 state; + + tBTA_GATTC_CACHE *p_srvc_cache; + tBTA_GATTC_CACHE *p_cur_srvc; + BUFFER_Q cache_buffer; /* buffer queue used for storing the cache data */ + UINT8 *p_free; /* starting point to next available byte */ + UINT16 free_byte; /* number of available bytes in server cache buffer */ + UINT8 update_count; /* indication received */ + UINT8 num_clcb; /* number of associated CLCB */ + + + tBTA_GATTC_ATTR_REC *p_srvc_list; + UINT8 cur_srvc_idx; + UINT8 cur_char_idx; + UINT8 next_avail_idx; + UINT8 total_srvc; + UINT8 total_char; + + UINT8 srvc_hdl_chg; /* service handle change indication pending */ + UINT16 attr_index; /* cahce NV saving/loading attribute index */ + + UINT16 mtu; +} tBTA_GATTC_SERV; + +#ifndef BTA_GATTC_NOTIF_REG_MAX +#define BTA_GATTC_NOTIF_REG_MAX 15 +#endif + +typedef struct +{ + BOOLEAN in_use; + BD_ADDR remote_bda; + tBTA_GATTC_CHAR_ID char_id; +}tBTA_GATTC_NOTIF_REG; + +typedef struct +{ + tBTA_GATTC_CBACK *p_cback; + BOOLEAN in_use; + tBTA_GATTC_IF client_if; /* client interface with BTE stack for this application */ + UINT8 num_clcb; /* number of associated CLCB */ + BOOLEAN dereg_pending; + tBT_UUID app_uuid; + tBTA_GATTC_NOTIF_REG notif_reg[BTA_GATTC_NOTIF_REG_MAX]; +}tBTA_GATTC_RCB; + +/* client channel is a mapping between a BTA client(cl_id) and a remote BD address */ +typedef struct +{ + UINT16 bta_conn_id; /* client channel ID, unique for clcb */ + BD_ADDR bda; + tBTA_TRANSPORT transport; /* channel transport */ + tBTA_GATTC_RCB *p_rcb; /* pointer to the registration CB */ + tBTA_GATTC_SERV *p_srcb; /* server cache CB */ + tBTA_GATTC_DATA *p_q_cmd; /* command in queue waiting for execution */ + +#define BTA_GATTC_NO_SCHEDULE 0 +#define BTA_GATTC_DISC_WAITING 0x01 +#define BTA_GATTC_REQ_WAITING 0x10 + + UINT8 auto_update; /* auto update is waiting */ + BOOLEAN disc_active; + BOOLEAN in_use; + tBTA_GATTC_STATE state; + tBTA_GATT_STATUS status; + UINT16 reason; +} tBTA_GATTC_CLCB; + +/* back ground connection tracking information */ +#if GATT_MAX_APPS <= 8 +typedef UINT8 tBTA_GATTC_CIF_MASK ; +#elif GATT_MAX_APPS <= 16 +typedef UINT16 tBTA_GATTC_CIF_MASK; +#elif GATT_MAX_APPS <= 32 +typedef UINT32 tBTA_GATTC_CIF_MASK; +#endif + +typedef struct +{ + BOOLEAN in_use; + BD_ADDR remote_bda; + tBTA_GATTC_CIF_MASK cif_mask; + tBTA_GATTC_CIF_MASK cif_adv_mask; + +}tBTA_GATTC_BG_TCK; + +typedef struct +{ + BOOLEAN in_use; + BD_ADDR remote_bda; +}tBTA_GATTC_CONN; + +enum +{ + BTA_GATTC_STATE_DISABLED, + BTA_GATTC_STATE_ENABLING, + BTA_GATTC_STATE_ENABLED, + BTA_GATTC_STATE_DISABLING +}; + +typedef struct +{ + UINT8 state; + + tBTA_GATTC_CONN conn_track[BTA_GATTC_CONN_MAX]; + tBTA_GATTC_BG_TCK bg_track[BTA_GATTC_KNOWN_SR_MAX]; + tBTA_GATTC_RCB cl_rcb[BTA_GATTC_CL_MAX]; + + tBTA_GATTC_CLCB clcb[BTA_GATTC_CLCB_MAX]; + tBTA_GATTC_SERV known_server[BTA_GATTC_KNOWN_SR_MAX]; + + tSDP_DISCOVERY_DB *p_sdp_db; + UINT16 sdp_conn_id; +}tBTA_GATTC_CB; + +/***************************************************************************** +** Global data +*****************************************************************************/ + +/* GATTC control block */ +#if BTA_DYNAMIC_MEMORY == FALSE +extern tBTA_GATTC_CB bta_gattc_cb; +#else +extern tBTA_GATTC_CB *bta_gattc_cb_ptr; +#define bta_gattc_cb (*bta_gattc_cb_ptr) +#endif + +/***************************************************************************** +** Function prototypes +*****************************************************************************/ +extern BOOLEAN bta_gattc_hdl_event(BT_HDR *p_msg); +extern BOOLEAN bta_gattc_sm_execute(tBTA_GATTC_CLCB *p_clcb, UINT16 event, tBTA_GATTC_DATA *p_data); + +/* function processed outside SM */ +extern void bta_gattc_disable(tBTA_GATTC_CB *p_cb); +extern void bta_gattc_register(tBTA_GATTC_CB *p_cb, tBTA_GATTC_DATA *p_data); +extern void bta_gattc_start_if(tBTA_GATTC_CB *p_cb, tBTA_GATTC_DATA *p_data); +extern void bta_gattc_process_api_open (tBTA_GATTC_CB *p_cb, tBTA_GATTC_DATA * p_msg); +extern void bta_gattc_process_api_open_cancel (tBTA_GATTC_CB *p_cb, tBTA_GATTC_DATA * p_msg); +extern void bta_gattc_deregister(tBTA_GATTC_CB *p_cb, tBTA_GATTC_RCB *p_clreg); +extern void bta_gattc_process_enc_cmpl(tBTA_GATTC_CB *p_cb, tBTA_GATTC_DATA *p_msg); + +/* function within state machine */ +extern void bta_gattc_open(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data); +extern void bta_gattc_open_fail(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data); +extern void bta_gattc_open_error(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data); + +extern void bta_gattc_cancel_open(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data); +extern void bta_gattc_cancel_open_ok(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data); +extern void bta_gattc_cancel_open_error(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data); + +extern void bta_gattc_conn(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data); + +extern void bta_gattc_close(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data); +extern void bta_gattc_close_fail(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data); +extern void bta_gattc_disc_close(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data); + +extern void bta_gattc_start_discover(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data); +extern void bta_gattc_disc_cmpl(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data); +extern void bta_gattc_read(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data); +extern void bta_gattc_write(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data); +extern void bta_gattc_op_cmpl(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data); +extern void bta_gattc_q_cmd(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data); +extern void bta_gattc_search(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data); +extern void bta_gattc_fail(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data); +extern void bta_gattc_confirm(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data); +extern void bta_gattc_execute(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data); +extern void bta_gattc_read_multi(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data); +extern void bta_gattc_ci_open(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data); +extern void bta_gattc_ci_load(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data); +extern void bta_gattc_ci_close(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data); +extern void bta_gattc_ci_save(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data); +extern void bta_gattc_cache_open(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data); +extern void bta_gattc_ignore_op_cmpl(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data); +extern void bta_gattc_restart_discover(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA * p_msg); +extern void bta_gattc_init_bk_conn(tBTA_GATTC_API_OPEN *p_data, tBTA_GATTC_RCB *p_clreg); +extern void bta_gattc_cancel_bk_conn(tBTA_GATTC_API_CANCEL_OPEN *p_data); +extern void bta_gattc_send_open_cback( tBTA_GATTC_RCB *p_clreg, tBTA_GATT_STATUS status, + BD_ADDR remote_bda, UINT16 conn_id, tBTA_TRANSPORT transport, UINT16 mtu); +extern void bta_gattc_process_api_refresh(tBTA_GATTC_CB *p_cb, tBTA_GATTC_DATA * p_msg); +extern void bta_gattc_cfg_mtu(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data); +#if BLE_INCLUDED == TRUE +extern void bta_gattc_listen(tBTA_GATTC_CB *p_cb, tBTA_GATTC_DATA * p_msg); +extern void bta_gattc_broadcast(tBTA_GATTC_CB *p_cb, tBTA_GATTC_DATA * p_msg); +#endif +/* utility functions */ +extern tBTA_GATTC_CLCB * bta_gattc_find_clcb_by_cif (UINT8 client_if, BD_ADDR remote_bda, tBTA_TRANSPORT transport); +extern tBTA_GATTC_CLCB * bta_gattc_find_clcb_by_conn_id (UINT16 conn_id); +extern tBTA_GATTC_CLCB * bta_gattc_clcb_alloc(tBTA_GATTC_IF client_if, BD_ADDR remote_bda, tBTA_TRANSPORT transport); +extern void bta_gattc_clcb_dealloc(tBTA_GATTC_CLCB *p_clcb); +extern tBTA_GATTC_CLCB * bta_gattc_find_alloc_clcb(tBTA_GATTC_IF client_if, BD_ADDR remote_bda, tBTA_TRANSPORT transport); +extern tBTA_GATTC_RCB * bta_gattc_cl_get_regcb(UINT8 client_if); +extern tBTA_GATTC_SERV * bta_gattc_find_srcb(BD_ADDR bda); +extern tBTA_GATTC_SERV * bta_gattc_srcb_alloc(BD_ADDR bda); +extern tBTA_GATTC_SERV * bta_gattc_find_scb_by_cid (UINT16 conn_id); +extern tBTA_GATTC_CLCB * bta_gattc_find_int_conn_clcb(tBTA_GATTC_DATA *p_msg); +extern tBTA_GATTC_CLCB * bta_gattc_find_int_disconn_clcb(tBTA_GATTC_DATA *p_msg); + +extern BOOLEAN bta_gattc_enqueue(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data); + +extern UINT16 bta_gattc_id2handle(tBTA_GATTC_SERV *p_srcb, tBTA_GATT_SRVC_ID *p_service_id, tBTA_GATT_ID *p_char_id, tBTA_GATT_ID *p_descr_uuid); +extern BOOLEAN bta_gattc_handle2id(tBTA_GATTC_SERV *p_srcb, UINT16 handle, tBTA_GATT_SRVC_ID *service_id, tBTA_GATT_ID *char_id, tBTA_GATT_ID *p_type); +extern BOOLEAN bta_gattc_uuid_compare (tBT_UUID *p_src, tBT_UUID *p_tar, BOOLEAN is_precise); +extern void bta_gattc_pack_attr_uuid(tBTA_GATTC_CACHE_ATTR *p_attr, tBT_UUID *p_uuid); +extern BOOLEAN bta_gattc_check_notif_registry(tBTA_GATTC_RCB *p_clreg, tBTA_GATTC_SERV *p_srcb, tBTA_GATTC_NOTIFY *p_notify); +extern tBTA_GATT_STATUS bta_gattc_pack_read_cb_data(tBTA_GATTC_SERV *p_srcb, tBT_UUID *p_descr_uuid, tGATT_VALUE *p_attr, tBTA_GATT_READ_VAL *p_value); +extern BOOLEAN bta_gattc_mark_bg_conn (tBTA_GATTC_IF client_if, BD_ADDR_PTR remote_bda, BOOLEAN add, BOOLEAN is_listen); +extern BOOLEAN bta_gattc_check_bg_conn (tBTA_GATTC_IF client_if, BD_ADDR remote_bda, UINT8 role); +extern UINT8 bta_gattc_num_reg_app(void); +extern void bta_gattc_clear_notif_registration(UINT16 conn_id); +extern tBTA_GATTC_SERV * bta_gattc_find_srvr_cache(BD_ADDR bda); +extern BOOLEAN bta_gattc_charid_compare(tBTA_GATTC_CHAR_ID *p_src, tBTA_GATTC_CHAR_ID *p_tar); +extern BOOLEAN bta_gattc_srvcid_compare(tBTA_GATT_SRVC_ID *p_src, tBTA_GATT_SRVC_ID *p_tar); +extern void bta_gattc_cpygattid(tBTA_GATT_ID *p_des, tBTA_GATT_ID *p_src); + +/* discovery functions */ +extern void bta_gattc_disc_res_cback (UINT16 conn_id, tGATT_DISC_TYPE disc_type, tGATT_DISC_RES *p_data); +extern void bta_gattc_disc_cmpl_cback (UINT16 conn_id, tGATT_DISC_TYPE disc_type, tGATT_STATUS status); +extern tBTA_GATT_STATUS bta_gattc_discover_procedure(UINT16 conn_id, tBTA_GATTC_SERV *p_server_cb, UINT8 disc_type); +extern tBTA_GATT_STATUS bta_gattc_discover_pri_service(UINT16 conn_id, tBTA_GATTC_SERV *p_server_cb, UINT8 disc_type); +extern void bta_gattc_search_service(tBTA_GATTC_CLCB *p_clcb, tBT_UUID *p_uuid); +extern tBTA_GATT_STATUS bta_gattc_query_cache(UINT16 conn_id, UINT8 query_type, tBTA_GATT_SRVC_ID *p_srvc_id, + tBTA_GATT_ID *p_start_rec,tBT_UUID *p_uuid_cond, + tBTA_GATT_ID *p_output, void *p_param); +extern tBTA_GATT_STATUS bta_gattc_init_cache(tBTA_GATTC_SERV *p_srvc_cb); +extern void bta_gattc_rebuild_cache(tBTA_GATTC_SERV *p_srcv, UINT16 num_attr, tBTA_GATTC_NV_ATTR *p_attr, UINT16 attr_index); +extern BOOLEAN bta_gattc_cache_save(tBTA_GATTC_SERV *p_srvc_cb, UINT16 conn_id); + + +extern tBTA_GATTC_CONN * bta_gattc_conn_alloc(BD_ADDR remote_bda); +extern tBTA_GATTC_CONN * bta_gattc_conn_find(BD_ADDR remote_bda); +extern tBTA_GATTC_CONN * bta_gattc_conn_find_alloc(BD_ADDR remote_bda); +extern BOOLEAN bta_gattc_conn_dealloc(BD_ADDR remote_bda); + +#endif /* BTA_GATTC_INT_H */ diff --git a/components/bt/bluedroid/bta/include/bta_gatts_co.h b/components/bt/bluedroid/bta/include/bta_gatts_co.h new file mode 100755 index 0000000000..b3ee99b0a9 --- /dev/null +++ b/components/bt/bluedroid/bta/include/bta_gatts_co.h @@ -0,0 +1,81 @@ +/****************************************************************************** + * + * Copyright (C) 2010-2012 Broadcom Corporation + * + * 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 is the interface file for BTA GATT server call-out functions. + * + ******************************************************************************/ +#ifndef BTA_GATTS_CO_H +#define BTA_GATTS_CO_H + +#include "bta_gatt_api.h" + +/******************************************************************************* +** +** Function bta_gatts_co_update_handle_range +** +** Description This callout function is executed by GATTS when a GATT server +** handle range ios to be added or removed. +** +** Parameter is_add: true is to add a handle range; otherwise is to delete. +** p_hndl_range: handle range. +** +** Returns void. +** +*******************************************************************************/ +extern void bta_gatts_co_update_handle_range(BOOLEAN is_add, tBTA_GATTS_HNDL_RANGE *p_hndl_range); + +/******************************************************************************* +** +** Function bta_gatts_co_srv_chg +** +** Description This call-out is to read/write/remove service change related +** informaiton. The request consists of the cmd and p_req and the +** response is returned in p_rsp +** +** Parameter cmd - request command +** p_req - request paramters +** p_rsp - response data for the request +** +** Returns TRUE - if the request is processed successfully and +** the response is returned in p_rsp. +** FASLE - if the request can not be processed +** +*******************************************************************************/ +extern BOOLEAN bta_gatts_co_srv_chg(tBTA_GATTS_SRV_CHG_CMD cmd, + tBTA_GATTS_SRV_CHG_REQ *p_req, + tBTA_GATTS_SRV_CHG_RSP *p_rsp); + +/******************************************************************************* +** +** Function bta_gatts_co_load_handle_range +** +** Description This callout function is executed by GATTS when a GATT server +** handle range is requested to be loaded from NV. +** +** Parameter +** +** Returns void. +** +*******************************************************************************/ +extern BOOLEAN bta_gatts_co_load_handle_range(UINT8 index, + tBTA_GATTS_HNDL_RANGE *p_handle); + + +#endif /* BTA_GATTS_CO_H */ diff --git a/components/bt/bluedroid/bta/include/bta_gatts_int.h b/components/bt/bluedroid/bta/include/bta_gatts_int.h new file mode 100755 index 0000000000..9a12dfd277 --- /dev/null +++ b/components/bt/bluedroid/bta/include/bta_gatts_int.h @@ -0,0 +1,260 @@ +/****************************************************************************** + * + * Copyright (C) 2003-2012 Broadcom Corporation + * + * 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 is the private file for the BTA GATT server. + * + ******************************************************************************/ +#ifndef BTA_GATTS_INT_H +#define BTA_GATTS_INT_H + +#include "bt_target.h" +#include "bta_sys.h" +#include "bta_gatt_api.h" +#include "gatt_api.h" + +#include "gki.h" + +/***************************************************************************** +** Constants and data types +*****************************************************************************/ +enum +{ + BTA_GATTS_API_REG_EVT = BTA_SYS_EVT_START(BTA_ID_GATTS), + BTA_GATTS_INT_START_IF_EVT, + BTA_GATTS_API_DEREG_EVT, + BTA_GATTS_API_CREATE_SRVC_EVT, + BTA_GATTS_API_INDICATION_EVT, + + BTA_GATTS_API_ADD_INCL_SRVC_EVT, + BTA_GATTS_API_ADD_CHAR_EVT, + BTA_GATTS_API_ADD_DESCR_EVT, + BTA_GATTS_API_DEL_SRVC_EVT, + BTA_GATTS_API_START_SRVC_EVT, + BTA_GATTS_API_STOP_SRVC_EVT, + BTA_GATTS_API_RSP_EVT, + BTA_GATTS_API_OPEN_EVT, + BTA_GATTS_API_CANCEL_OPEN_EVT, + BTA_GATTS_API_CLOSE_EVT, + BTA_GATTS_API_LISTEN_EVT, + BTA_GATTS_API_DISABLE_EVT +}; +typedef UINT16 tBTA_GATTS_INT_EVT; + +/* max number of application allowed on device */ +#define BTA_GATTS_MAX_APP_NUM GATT_MAX_SR_PROFILES + +/* max number of services allowed in the device */ +#define BTA_GATTS_MAX_SRVC_NUM GATT_MAX_SR_PROFILES + +/* internal strucutre for GATTC register API */ +typedef struct +{ + BT_HDR hdr; + tBT_UUID app_uuid; + tBTA_GATTS_CBACK *p_cback; +}tBTA_GATTS_API_REG; + +typedef struct +{ + BT_HDR hdr; + tBTA_GATTS_IF server_if; +}tBTA_GATTS_INT_START_IF; + +typedef tBTA_GATTS_INT_START_IF tBTA_GATTS_API_DEREG; + +typedef struct +{ + BT_HDR hdr; + tBTA_GATTS_IF server_if; + tBT_UUID service_uuid; + UINT16 num_handle; + UINT8 inst; + BOOLEAN is_pri; + +} tBTA_GATTS_API_CREATE_SRVC; + +typedef struct +{ + BT_HDR hdr; + tBT_UUID char_uuid; + tBTA_GATT_PERM perm; + tBTA_GATT_CHAR_PROP property; + +}tBTA_GATTS_API_ADD_CHAR; + +typedef struct +{ + BT_HDR hdr; + UINT16 included_service_id; + +}tBTA_GATTS_API_ADD_INCL_SRVC; + +typedef struct +{ + BT_HDR hdr; + tBT_UUID descr_uuid; + tBTA_GATT_PERM perm; +}tBTA_GATTS_API_ADD_DESCR; + +typedef struct +{ + BT_HDR hdr; + UINT16 attr_id; + UINT16 len; + BOOLEAN need_confirm; + UINT8 value[BTA_GATT_MAX_ATTR_LEN]; +}tBTA_GATTS_API_INDICATION; + +typedef struct +{ + BT_HDR hdr; + UINT32 trans_id; + tBTA_GATT_STATUS status; + tBTA_GATTS_RSP *p_rsp; +}tBTA_GATTS_API_RSP; + +typedef struct +{ + BT_HDR hdr; + tBTA_GATT_TRANSPORT transport; +}tBTA_GATTS_API_START; + + +typedef struct +{ + BT_HDR hdr; + BD_ADDR remote_bda; + tBTA_GATTS_IF server_if; + BOOLEAN is_direct; + tBTA_GATT_TRANSPORT transport; + +}tBTA_GATTS_API_OPEN; + +typedef tBTA_GATTS_API_OPEN tBTA_GATTS_API_CANCEL_OPEN; + +typedef struct +{ + BT_HDR hdr; + BD_ADDR_PTR remote_bda; + tBTA_GATTS_IF server_if; + BOOLEAN start; +} tBTA_GATTS_API_LISTEN; + +typedef union +{ + BT_HDR hdr; + tBTA_GATTS_API_REG api_reg; + tBTA_GATTS_API_DEREG api_dereg; + tBTA_GATTS_API_CREATE_SRVC api_create_svc; + tBTA_GATTS_API_ADD_INCL_SRVC api_add_incl_srvc; + tBTA_GATTS_API_ADD_CHAR api_add_char; + tBTA_GATTS_API_ADD_DESCR api_add_char_descr; + tBTA_GATTS_API_START api_start; + tBTA_GATTS_API_INDICATION api_indicate; + tBTA_GATTS_API_RSP api_rsp; + tBTA_GATTS_API_OPEN api_open; + tBTA_GATTS_API_CANCEL_OPEN api_cancel_open; + + tBTA_GATTS_INT_START_IF int_start_if; + /* if peripheral role is supported */ + tBTA_GATTS_API_LISTEN api_listen; +} tBTA_GATTS_DATA; + +/* application registration control block */ +typedef struct +{ + BOOLEAN in_use; + tBT_UUID app_uuid; + tBTA_GATTS_CBACK *p_cback; + tBTA_GATTS_IF gatt_if; +}tBTA_GATTS_RCB; + +/* service registration control block */ +typedef struct +{ + tBT_UUID service_uuid; /* service UUID */ + UINT16 service_id; /* service handle */ + UINT8 inst_num; /* instance ID */ + UINT8 rcb_idx; + UINT8 idx; /* self index of serviec CB */ + BOOLEAN in_use; + +}tBTA_GATTS_SRVC_CB; + + +/* GATT server control block */ +typedef struct +{ + BOOLEAN enabled; + tBTA_GATTS_RCB rcb[BTA_GATTS_MAX_APP_NUM]; + tBTA_GATTS_SRVC_CB srvc_cb[BTA_GATTS_MAX_SRVC_NUM]; +}tBTA_GATTS_CB; + + + +/***************************************************************************** +** Global data +*****************************************************************************/ + +/* GATTC control block */ +#if BTA_DYNAMIC_MEMORY == FALSE +extern tBTA_GATTS_CB bta_gatts_cb; +#else +extern tBTA_GATTS_CB *bta_gatts_cb_ptr; + #define bta_gatts_cb (*bta_gatts_cb_ptr) +#endif + +/***************************************************************************** +** Function prototypes +*****************************************************************************/ +extern BOOLEAN bta_gatts_hdl_event(BT_HDR *p_msg); + +extern void bta_gatts_api_disable(tBTA_GATTS_CB *p_cb); +extern void bta_gatts_api_enable(tBTA_GATTS_CB *p_cb, tBTA_GATTS_DATA *p_data); +extern void bta_gatts_register(tBTA_GATTS_CB *p_cb, tBTA_GATTS_DATA *p_msg); +extern void bta_gatts_start_if(tBTA_GATTS_CB *p_cb, tBTA_GATTS_DATA *p_msg); +extern void bta_gatts_deregister(tBTA_GATTS_CB *p_cb, tBTA_GATTS_DATA *p_msg); +extern void bta_gatts_create_srvc(tBTA_GATTS_CB *p_cb, tBTA_GATTS_DATA * p_msg); +extern void bta_gatts_add_include_srvc(tBTA_GATTS_SRVC_CB *p_srvc_cb, tBTA_GATTS_DATA * p_msg); +extern void bta_gatts_add_char(tBTA_GATTS_SRVC_CB *p_srvc_cb, tBTA_GATTS_DATA * p_msg); +extern void bta_gatts_add_char_descr(tBTA_GATTS_SRVC_CB *p_srvc_cb, tBTA_GATTS_DATA * p_msg); +extern void bta_gatts_delete_service(tBTA_GATTS_SRVC_CB *p_srvc_cb, tBTA_GATTS_DATA * p_msg); +extern void bta_gatts_start_service(tBTA_GATTS_SRVC_CB *p_srvc_cb, tBTA_GATTS_DATA * p_msg); +extern void bta_gatts_stop_service(tBTA_GATTS_SRVC_CB *p_srvc_cb, tBTA_GATTS_DATA * p_msg); + +extern void bta_gatts_send_rsp(tBTA_GATTS_CB *p_cb, tBTA_GATTS_DATA * p_msg); +extern void bta_gatts_indicate_handle (tBTA_GATTS_CB *p_cb, tBTA_GATTS_DATA * p_msg); + + +extern void bta_gatts_open (tBTA_GATTS_CB *p_cb, tBTA_GATTS_DATA * p_msg); +extern void bta_gatts_cancel_open (tBTA_GATTS_CB *p_cb, tBTA_GATTS_DATA * p_msg); +extern void bta_gatts_close (tBTA_GATTS_CB *p_cb, tBTA_GATTS_DATA * p_msg); +extern void bta_gatts_listen(tBTA_GATTS_CB *p_cb, tBTA_GATTS_DATA * p_msg); + +extern BOOLEAN bta_gatts_uuid_compare(tBT_UUID tar, tBT_UUID src); +extern tBTA_GATTS_RCB *bta_gatts_find_app_rcb_by_app_if(tBTA_GATTS_IF server_if); +extern UINT8 bta_gatts_find_app_rcb_idx_by_app_if(tBTA_GATTS_CB *p_cb, tBTA_GATTS_IF server_if); +extern UINT8 bta_gatts_alloc_srvc_cb(tBTA_GATTS_CB *p_cb, UINT8 rcb_idx); +extern tBTA_GATTS_SRVC_CB * bta_gatts_find_srvc_cb_by_srvc_id(tBTA_GATTS_CB *p_cb, UINT16 service_id); +extern tBTA_GATTS_SRVC_CB * bta_gatts_find_srvc_cb_by_attr_id(tBTA_GATTS_CB *p_cb, UINT16 attr_id); + + +#endif /* BTA_GATTS_INT_H */ + diff --git a/components/bt/bluedroid/bta/include/bta_hh_api.h b/components/bt/bluedroid/bta/include/bta_hh_api.h new file mode 100644 index 0000000000..d43e492b61 --- /dev/null +++ b/components/bt/bluedroid/bta/include/bta_hh_api.h @@ -0,0 +1,558 @@ +/****************************************************************************** + * + * Copyright (C) 2002-2012 Broadcom Corporation + * + * 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. + * + ******************************************************************************/ +#ifndef BTA_HH_API_H +#define BTA_HH_API_H + +#include "bta_api.h" +#include "hidh_api.h" + +#if (defined BTA_HH_LE_INCLUDED && BTA_HH_LE_INCLUDED == TRUE) +#include "gatt_api.h" +#endif + +/***************************************************************************** +** Constants and Type Definitions +*****************************************************************************/ +#ifndef BTA_HH_DEBUG +#define BTA_HH_DEBUG TRUE +#endif + +#ifndef BTA_HH_SSR_MAX_LATENCY_DEF +#define BTA_HH_SSR_MAX_LATENCY_DEF 800 /* 500 ms*/ +#endif + +#ifndef BTA_HH_SSR_MIN_TOUT_DEF +#define BTA_HH_SSR_MIN_TOUT_DEF 2 +#endif + +/* BTA HID Host callback events */ +#define BTA_HH_ENABLE_EVT 0 /* HH enabled */ +#define BTA_HH_DISABLE_EVT 1 /* HH disabled */ +#define BTA_HH_OPEN_EVT 2 /* connection opened */ +#define BTA_HH_CLOSE_EVT 3 /* connection closed */ +#define BTA_HH_GET_RPT_EVT 4 /* BTA_HhGetReport callback */ +#define BTA_HH_SET_RPT_EVT 5 /* BTA_HhSetReport callback */ +#define BTA_HH_GET_PROTO_EVT 6 /* BTA_GetProtoMode callback */ +#define BTA_HH_SET_PROTO_EVT 7 /* BTA_HhSetProtoMode callback */ +#define BTA_HH_GET_IDLE_EVT 8 /* BTA_HhGetIdle comes callback */ +#define BTA_HH_SET_IDLE_EVT 9 /* BTA_HhSetIdle finish callback */ +#define BTA_HH_GET_DSCP_EVT 10 /* Get report descriptor */ +#define BTA_HH_ADD_DEV_EVT 11 /* Add Device callback */ +#define BTA_HH_RMV_DEV_EVT 12 /* remove device finished */ +#define BTA_HH_VC_UNPLUG_EVT 13 /* virtually unplugged */ +#define BTA_HH_DATA_EVT 15 +#define BTA_HH_API_ERR_EVT 16 /* API error is caught */ +#define BTA_HH_UPDATE_SCPP_EVT 17 /* update scan paramter complete */ + +typedef UINT16 tBTA_HH_EVT; + +/* application ID(none-zero) for each type of device */ +#define BTA_HH_APP_ID_MI 1 +#define BTA_HH_APP_ID_KB 2 +#define BTA_HH_APP_ID_RMC 3 +#define BTA_HH_APP_ID_3DSG 4 +#define BTA_HH_APP_ID_JOY 5 +#define BTA_HH_APP_ID_GPAD 6 +#define BTA_HH_APP_ID_LE 0xff + +/* defined the minimum offset */ +#define BTA_HH_MIN_OFFSET L2CAP_MIN_OFFSET+1 + +/* HID_HOST_MAX_DEVICES can not exceed 15 for th design of BTA HH */ +#define BTA_HH_IDX_INVALID 0xff +#define BTA_HH_MAX_KNOWN HID_HOST_MAX_DEVICES + +#if (defined BTA_HH_LE_INCLUDED && BTA_HH_LE_INCLUDED == TRUE) +/* GATT_MAX_PHY_CHANNEL can not exceed 14 for the design of BTA HH */ +#define BTA_HH_LE_MAX_KNOWN GATT_MAX_PHY_CHANNEL +#define BTA_HH_MAX_DEVICE (HID_HOST_MAX_DEVICES + GATT_MAX_PHY_CHANNEL) +#else +#define BTA_HH_MAX_DEVICE HID_HOST_MAX_DEVICES +#endif +/* invalid device handle */ +#define BTA_HH_INVALID_HANDLE 0xff + +/* type of protocol mode */ +#define BTA_HH_PROTO_RPT_MODE (0x00) +#define BTA_HH_PROTO_BOOT_MODE (0x01) +#define BTA_HH_PROTO_UNKNOWN (0xff) +typedef UINT8 tBTA_HH_PROTO_MODE; + +enum +{ + BTA_HH_KEYBD_RPT_ID = 1, + BTA_HH_MOUSE_RPT_ID +}; +typedef UINT8 tBTA_HH_BOOT_RPT_ID; + +/* type of devices, bit mask */ +#define BTA_HH_DEVT_UNKNOWN 0x00 +#define BTA_HH_DEVT_JOS 0x01 /* joy stick */ +#define BTA_HH_DEVT_GPD 0x02 /* game pad */ +#define BTA_HH_DEVT_RMC 0x03 /* remote control */ +#define BTA_HH_DEVT_SED 0x04 /* sensing device */ +#define BTA_HH_DEVT_DGT 0x05 /* Digitizer tablet */ +#define BTA_HH_DEVT_CDR 0x06 /* card reader */ +#define BTA_HH_DEVT_KBD 0x10 /* keyboard */ +#define BTA_HH_DEVT_MIC 0x20 /* pointing device */ +#define BTA_HH_DEVT_COM 0x30 /* Combo keyboard/pointing */ +#define BTA_HH_DEVT_OTHER 0x80 +typedef UINT8 tBTA_HH_DEVT; + +enum +{ + BTA_HH_OK, + BTA_HH_HS_HID_NOT_READY, /* handshake error : device not ready */ + BTA_HH_HS_INVALID_RPT_ID, /* handshake error : invalid report ID */ + BTA_HH_HS_TRANS_NOT_SPT, /* handshake error : transaction not spt */ + BTA_HH_HS_INVALID_PARAM, /* handshake error : invalid paremter */ + BTA_HH_HS_ERROR, /* handshake error : unspecified HS error */ + BTA_HH_ERR, /* general BTA HH error */ + BTA_HH_ERR_SDP, /* SDP error */ + BTA_HH_ERR_PROTO, /* SET_Protocol error, + only used in BTA_HH_OPEN_EVT callback */ + + BTA_HH_ERR_DB_FULL, /* device database full error, used in + BTA_HH_OPEN_EVT/BTA_HH_ADD_DEV_EVT */ + BTA_HH_ERR_TOD_UNSPT, /* type of device not supported */ + BTA_HH_ERR_NO_RES, /* out of system resources */ + BTA_HH_ERR_AUTH_FAILED, /* authentication fail */ + BTA_HH_ERR_HDL, + BTA_HH_ERR_SEC +}; +typedef UINT8 tBTA_HH_STATUS; + + +#define BTA_HH_VIRTUAL_CABLE HID_VIRTUAL_CABLE +#define BTA_HH_NORMALLY_CONNECTABLE HID_NORMALLY_CONNECTABLE +#define BTA_HH_RECONN_INIT HID_RECONN_INIT +#define BTA_HH_SDP_DISABLE HID_SDP_DISABLE +#define BTA_HH_BATTERY_POWER HID_BATTERY_POWER +#define BTA_HH_REMOTE_WAKE HID_REMOTE_WAKE +#define BTA_HH_SUP_TOUT_AVLBL HID_SUP_TOUT_AVLBL +#define BTA_HH_SEC_REQUIRED HID_SEC_REQUIRED +typedef UINT16 tBTA_HH_ATTR_MASK; + +/* supported type of device and corresponding application ID */ +typedef struct +{ + tBTA_HH_DEVT tod; /* type of device */ + UINT8 app_id; /* corresponding application ID */ +}tBTA_HH_SPT_TOD; + +/* configuration struct */ +typedef struct +{ + UINT8 max_devt_spt; /* max number of types of devices spt */ + tBTA_HH_SPT_TOD *p_devt_list; /* supported types of device list */ + UINT16 sdp_db_size; +}tBTA_HH_CFG; + +enum +{ + BTA_HH_RPTT_RESRV, /* reserved */ + BTA_HH_RPTT_INPUT, /* input report */ + BTA_HH_RPTT_OUTPUT, /* output report */ + BTA_HH_RPTT_FEATURE /* feature report */ +}; +typedef UINT8 tBTA_HH_RPT_TYPE; + +/* HID_CONTROL operation code used in BTA_HhSendCtrl() +*/ +enum +{ + BTA_HH_CTRL_NOP = 0 + HID_PAR_CONTROL_NOP ,/* mapping from BTE */ + BTA_HH_CTRL_HARD_RESET, /* hard reset */ + BTA_HH_CTRL_SOFT_RESET, /* soft reset */ + BTA_HH_CTRL_SUSPEND, /* enter suspend */ + BTA_HH_CTRL_EXIT_SUSPEND, /* exit suspend */ + BTA_HH_CTRL_VIRTUAL_CABLE_UNPLUG /* virtual unplug */ +}; +typedef UINT8 tBTA_HH_TRANS_CTRL_TYPE; + +typedef tHID_DEV_DSCP_INFO tBTA_HH_DEV_DESCR; + +#define BTA_HH_SSR_PARAM_INVALID HID_SSR_PARAM_INVALID + +/* id DI is not existing in remote device, vendor_id in tBTA_HH_DEV_DSCP_INFO will be set to 0xffff */ +#define BTA_HH_VENDOR_ID_INVALID 0xffff + + +/* report descriptor information */ +typedef struct +{ + UINT16 vendor_id; /* vendor ID */ + UINT16 product_id; /* product ID */ + UINT16 version; /* version */ + UINT16 ssr_max_latency; /* SSR max latency, BTA_HH_SSR_PARAM_INVALID if unknown */ + UINT16 ssr_min_tout; /* SSR min timeout, BTA_HH_SSR_PARAM_INVALID if unknown */ + UINT8 ctry_code; /*Country Code.*/ +#if (defined BTA_HH_LE_INCLUDED && BTA_HH_LE_INCLUDED == TRUE) +#define BTA_HH_LE_REMOTE_WAKE 0x01 +#define BTA_HH_LE_NORMAL_CONN 0x02 + + UINT8 flag; +#endif + tBTA_HH_DEV_DESCR descriptor; +}tBTA_HH_DEV_DSCP_INFO; + +/* callback event data for BTA_HH_OPEN_EVT */ +typedef struct +{ + BD_ADDR bda; /* HID device bd address */ + tBTA_HH_STATUS status; /* operation status */ + UINT8 handle; /* device handle */ +#if (defined BTA_HH_LE_INCLUDED && BTA_HH_LE_INCLUDED == TRUE) + BOOLEAN le_hid; /* is LE devices? */ + BOOLEAN scps_supported; /* scan parameter service supported */ +#endif + +} tBTA_HH_CONN; + +typedef tBTA_HH_CONN tBTA_HH_DEV_INFO; + +/* callback event data */ +typedef struct +{ + tBTA_HH_STATUS status; /* operation status */ + UINT8 handle; /* device handle */ +} tBTA_HH_CBDATA; + +enum +{ + BTA_HH_MOD_CTRL_KEY, + BTA_HH_MOD_SHFT_KEY, + BTA_HH_MOD_ALT_KEY, + BTA_HH_MOD_GUI_KEY, + BTA_HH_MOD_MAX_KEY +}; + +/* parsed boot mode keyboard report */ +typedef struct +{ + UINT8 this_char[6]; /* virtual key code */ + BOOLEAN mod_key[BTA_HH_MOD_MAX_KEY]; + /* ctrl, shift, Alt, GUI */ + /* modifier key: is Shift key pressed */ + /* modifier key: is Ctrl key pressed */ + /* modifier key: is Alt key pressed */ + /* modifier key: GUI up/down */ + BOOLEAN caps_lock; /* is caps locked */ + BOOLEAN num_lock; /* is Num key pressed */ +} tBTA_HH_KEYBD_RPT; + +/* parsed boot mode mouse report */ +typedef struct +{ + UINT8 mouse_button; /* mouse button is clicked */ + INT8 delta_x; /* displacement x */ + INT8 delta_y; /* displacement y */ +}tBTA_HH_MICE_RPT; + +/* parsed Boot report */ +typedef struct +{ + tBTA_HH_BOOT_RPT_ID dev_type; /* type of device report */ + union + { + tBTA_HH_KEYBD_RPT keybd_rpt; /* keyboard report */ + tBTA_HH_MICE_RPT mice_rpt; /* mouse report */ + } data_rpt; +} tBTA_HH_BOOT_RPT; + +/* handshake data */ +typedef struct +{ + tBTA_HH_STATUS status; /* handshake status */ + UINT8 handle; /* device handle */ + union + { + tBTA_HH_PROTO_MODE proto_mode; /* GET_PROTO_EVT :protocol mode */ + BT_HDR *p_rpt_data; /* GET_RPT_EVT : report data */ + UINT8 idle_rate; /* GET_IDLE_EVT : idle rate */ + } rsp_data; + +}tBTA_HH_HSDATA; + +/* union of data associated with HD callback */ +typedef union +{ + tBTA_HH_DEV_INFO dev_info; /* BTA_HH_ADD_DEV_EVT, BTA_HH_RMV_DEV_EVT */ + tBTA_HH_CONN conn; /* BTA_HH_OPEN_EVT */ + tBTA_HH_CBDATA dev_status; /* BTA_HH_CLOSE_EVT, + BTA_HH_SET_PROTO_EVT + BTA_HH_SET_RPT_EVT + BTA_HH_SET_IDLE_EVT + BTA_HH_UPDATE_SCPP_EVT */ + + tBTA_HH_STATUS status; /* BTA_HH_ENABLE_EVT */ + tBTA_HH_DEV_DSCP_INFO dscp_info; /* BTA_HH_GET_DSCP_EVT */ + tBTA_HH_HSDATA hs_data; /* GET_ transaction callback + BTA_HH_GET_RPT_EVT + BTA_HH_GET_PROTO_EVT + BTA_HH_GET_IDLE_EVT */ +} tBTA_HH; + +/* BTA HH callback function */ +typedef void (tBTA_HH_CBACK) (tBTA_HH_EVT event, tBTA_HH *p_data); + + +/***************************************************************************** +** External Function Declarations +*****************************************************************************/ +#ifdef __cplusplus +extern "C" +{ +#endif + +/******************************************************************************* +** +** Function BTA_HhRegister +** +** Description This function enable HID host and registers HID-Host with +** lower layers. +** +** Returns void +** +*******************************************************************************/ +extern void BTA_HhEnable(tBTA_SEC sec_mask, tBTA_HH_CBACK *p_cback); + +/******************************************************************************* +** +** Function BTA_HhDeregister +** +** Description This function is called when the host is about power down. +** +** Returns void +** +*******************************************************************************/ +extern void BTA_HhDisable(void); + +/******************************************************************************* +** +** Function BTA_HhOpen +** +** Description This function is called to start an inquiry and read SDP +** record of responding devices; connect to a device if only +** one active HID device is found. +** +** Returns void +** +*******************************************************************************/ +extern void BTA_HhOpen (BD_ADDR dev_bda, tBTA_HH_PROTO_MODE mode, + tBTA_SEC sec_mask); + +/******************************************************************************* +** +** Function BTA_HhClose +** +** Description This function disconnects the device. +** +** Returns void +** +*******************************************************************************/ +extern void BTA_HhClose(UINT8 dev_handle); + +/******************************************************************************* +** +** Function BTA_HhSetProtoMode +** +** Description This function set the protocol mode at specified HID handle +** +** Returns void +** +*******************************************************************************/ +extern void BTA_HhSetProtoMode(UINT8 handle, tBTA_HH_PROTO_MODE t_type); + +/******************************************************************************* +** +** Function BTA_HhGetProtoMode +** +** Description This function get the protocol mode of a specified HID device. +** +** Returns void +** +*******************************************************************************/ +extern void BTA_HhGetProtoMode(UINT8 dev_handle); +/******************************************************************************* +** +** Function BTA_HhSetReport +** +** Description send SET_REPORT to device. +** +** Returns void +** +*******************************************************************************/ +extern void BTA_HhSetReport(UINT8 dev_handle, tBTA_HH_RPT_TYPE r_type, + BT_HDR *p_data); + +/******************************************************************************* +** +** Function BTA_HhGetReport +** +** Description Send a GET_REPORT to HID device. +** +** Returns void +** +*******************************************************************************/ +extern void BTA_HhGetReport(UINT8 dev_handle, tBTA_HH_RPT_TYPE r_type, + UINT8 rpt_id, UINT16 buf_size); +/******************************************************************************* +** +** Function BTA_HhSetIdle +** +** Description send SET_IDLE to device. +** +** Returns void +** +*******************************************************************************/ +extern void BTA_HhSetIdle(UINT8 dev_handle, UINT16 idle_rate); + +/******************************************************************************* +** +** Function BTA_HhGetIdle +** +** Description Send a GET_IDLE to HID device. +** +** Returns void +** +*******************************************************************************/ +extern void BTA_HhGetIdle(UINT8 dev_handle); + +/******************************************************************************* +** +** Function BTA_HhSendCtrl +** +** Description Send HID_CONTROL request to a HID device. +** +** Returns void +** +*******************************************************************************/ +extern void BTA_HhSendCtrl(UINT8 dev_handle, + tBTA_HH_TRANS_CTRL_TYPE c_type); + +/******************************************************************************* +** +** Function BTA_HhSetIdle +** +** Description send SET_IDLE to device. +** +** Returns void +** +*******************************************************************************/ +extern void BTA_HhSetIdle(UINT8 dev_handle, UINT16 idle_rate); + + +/******************************************************************************* +** +** Function BTA_HhGetIdle +** +** Description Send a GET_IDLE from HID device. +** +** Returns void +** +*******************************************************************************/ +extern void BTA_HhGetIdle(UINT8 dev_handle); + +/******************************************************************************* +** +** Function BTA_HhSendData +** +** Description Send DATA transaction to a HID device. +** +** Returns void +** +*******************************************************************************/ +extern void BTA_HhSendData(UINT8 dev_handle, BD_ADDR dev_bda, BT_HDR *p_buf); + +/******************************************************************************* +** +** Function BTA_HhGetDscpInfo +** +** Description Get report descriptor of the device +** +** Returns void +** +*******************************************************************************/ +extern void BTA_HhGetDscpInfo(UINT8 dev_handle); + +/******************************************************************************* +** Function BTA_HhAddDev +** +** Description Add a virtually cabled device into HID-Host device list +** to manage and assign a device handle for future API call, +** host applciation call this API at start-up to initialize its +** virtually cabled devices. +** +** Returns void +** +*******************************************************************************/ +extern void BTA_HhAddDev(BD_ADDR bda, tBTA_HH_ATTR_MASK attr_mask, + UINT8 sub_class, UINT8 app_id, + tBTA_HH_DEV_DSCP_INFO dscp_info); +/******************************************************************************* +** +** Function BTA_HhRemoveDev +** +** Description Remove a device from the HID host devices list. +** +** Returns void +** +*******************************************************************************/ +extern void BTA_HhRemoveDev(UINT8 dev_handle ); + +/******************************************************************************* +** +** Parsing Utility Functions +** +*******************************************************************************/ +/******************************************************************************* +** +** Function BTA_HhParseBootRpt +** +** Description This utility function parse a boot mode report. +** +** Returns void +** +*******************************************************************************/ +extern void BTA_HhParseBootRpt(tBTA_HH_BOOT_RPT *p_data, UINT8 *p_report, + UINT16 report_len); + +#if BTA_HH_LE_INCLUDED == TRUE +/******************************************************************************* +** +** Function BTA_HhUpdateLeScanParam +** +** Description Update the scan paramteters if connected to a LE hid device as +** report host. +** +** Returns void +** +*******************************************************************************/ +extern void BTA_HhUpdateLeScanParam(UINT8 dev_handle, UINT16 scan_int, UINT16 scan_win); +#endif +/* test commands */ +extern void bta_hh_le_hid_read_rpt_clt_cfg(BD_ADDR bd_addr, UINT8 rpt_id); + + + +#ifdef __cplusplus +} +#endif + +#endif /* BTA_HH_API_H */ diff --git a/components/bt/bluedroid/bta/include/bta_hh_co.h b/components/bt/bluedroid/bta/include/bta_hh_co.h new file mode 100644 index 0000000000..09cb565ea6 --- /dev/null +++ b/components/bt/bluedroid/bta/include/bta_hh_co.h @@ -0,0 +1,133 @@ +/****************************************************************************** + * + * Copyright (C) 2005-2012 Broadcom Corporation + * + * 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 is the interface file for hid host call-out functions. + * + ******************************************************************************/ +#ifndef BTA_HH_CO_H +#define BTA_HH_CO_H + +#include "bta_hh_api.h" + +typedef struct +{ + UINT16 rpt_uuid; + UINT8 rpt_id; + tBTA_HH_RPT_TYPE rpt_type; + UINT8 inst_id; + UINT8 prop; +}tBTA_HH_RPT_CACHE_ENTRY; + +/******************************************************************************* +** +** Function bta_hh_co_data +** +** Description This callout function is executed by HH when data is received +** in interupt channel. +** +** +** Returns void. +** +*******************************************************************************/ +extern void bta_hh_co_data(UINT8 dev_handle, UINT8 *p_rpt, UINT16 len, + tBTA_HH_PROTO_MODE mode, UINT8 sub_class, + UINT8 ctry_code, BD_ADDR peer_addr, UINT8 app_id); + +/******************************************************************************* +** +** Function bta_hh_co_open +** +** Description This callout function is executed by HH when connection is +** opened, and application may do some device specific +** initialization. +** +** Returns void. +** +*******************************************************************************/ +extern void bta_hh_co_open(UINT8 dev_handle, UINT8 sub_class, + UINT16 attr_mask, UINT8 app_id); + +/******************************************************************************* +** +** Function bta_hh_co_close +** +** Description This callout function is executed by HH when connection is +** closed, and device specific finalizatio nmay be needed. +** +** Returns void. +** +*******************************************************************************/ +extern void bta_hh_co_close(UINT8 dev_handle, UINT8 app_id); + +#if (BLE_INCLUDED == TRUE && BTA_HH_LE_INCLUDED == TRUE) +/******************************************************************************* +** +** Function bta_hh_le_co_rpt_info +** +** Description This callout function is to convey the report information on +** a HOGP device to the application. Application can save this +** information in NV if device is bonded and load it back when +** stack reboot. +** +** Parameters remote_bda - remote device address +** p_entry - report entry pointer +** app_id - application id +** +** Returns void. +** +*******************************************************************************/ +extern void bta_hh_le_co_rpt_info(BD_ADDR remote_bda, + tBTA_HH_RPT_CACHE_ENTRY *p_entry, + UINT8 app_id); + +/******************************************************************************* +** +** Function bta_hh_le_co_cache_load +** +** Description This callout function is to request the application to load the +** cached HOGP report if there is any. When cache reading is completed, +** bta_hh_le_ci_cache_load() is called by the application. +** +** Parameters remote_bda - remote device address +** p_num_rpt: number of cached report +** app_id - application id +** +** Returns the acched report array +** +*******************************************************************************/ +extern tBTA_HH_RPT_CACHE_ENTRY *bta_hh_le_co_cache_load (BD_ADDR remote_bda, + UINT8 *p_num_rpt, + UINT8 app_id); + +/******************************************************************************* +** +** Function bta_hh_le_co_reset_rpt_cache +** +** Description This callout function is to reset the HOGP device cache. +** +** Parameters remote_bda - remote device address +** +** Returns none +** +*******************************************************************************/ +extern void bta_hh_le_co_reset_rpt_cache (BD_ADDR remote_bda, UINT8 app_id); + +#endif /* #if (BLE_INCLUDED == TRUE && BTA_HH_LE_INCLUDED == TRUE) */ +#endif /* BTA_HH_CO_H */ diff --git a/components/bt/bluedroid/bta/include/bta_sys.h b/components/bt/bluedroid/bta/include/bta_sys.h new file mode 100644 index 0000000000..8eacd3a9cf --- /dev/null +++ b/components/bt/bluedroid/bta/include/bta_sys.h @@ -0,0 +1,287 @@ +/****************************************************************************** + * + * Copyright (C) 2003-2012 Broadcom Corporation + * + * 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 is the public interface file for the BTA system manager. + * + ******************************************************************************/ +#ifndef BTA_SYS_H +#define BTA_SYS_H + +#include "bt_target.h" +#include "gki.h" + +/***************************************************************************** +** Constants and data types +*****************************************************************************/ + +/* vendor specific event handler function type */ +typedef BOOLEAN (tBTA_SYS_VS_EVT_HDLR)(UINT16 evt, void *p); + +/* event handler function type */ +typedef BOOLEAN (tBTA_SYS_EVT_HDLR)(BT_HDR *p_msg); + +/* disable function type */ +typedef void (tBTA_SYS_DISABLE)(void); + + +/* HW modules */ +enum +{ + BTA_SYS_HW_BLUETOOTH, + BTA_SYS_HW_RT, + + BTA_SYS_MAX_HW_MODULES +}; + +typedef UINT16 tBTA_SYS_HW_MODULE; + +#ifndef BTA_DM_NUM_JV_ID +#define BTA_DM_NUM_JV_ID 2 +#endif + +/* SW sub-systems */ +#define BTA_ID_SYS 0 /* system manager */ +/* BLUETOOTH PART - from 0 to BTA_ID_BLUETOOTH_MAX */ +#define BTA_ID_DM 1 /* device manager */ +#define BTA_ID_DM_SEARCH 2 /* device manager search */ +#define BTA_ID_DM_SEC 3 /* device manager security */ +#define BTA_ID_DG 4 /* data gateway */ +#define BTA_ID_AG 5 /* audio gateway */ +#define BTA_ID_OPC 6 /* object push client */ +#define BTA_ID_OPS 7 /* object push server */ +#define BTA_ID_FTS 8 /* file transfer server */ +#define BTA_ID_CT 9 /* cordless telephony terminal */ +#define BTA_ID_FTC 10 /* file transfer client */ +#define BTA_ID_SS 11 /* synchronization server */ +#define BTA_ID_PR 12 /* Printer client */ +#define BTA_ID_BIC 13 /* Basic Imaging Client */ +#define BTA_ID_PAN 14 /* Personal Area Networking */ +#define BTA_ID_BIS 15 /* Basic Imaging Server */ +#define BTA_ID_ACC 16 /* Advanced Camera Client */ +#define BTA_ID_SC 17 /* SIM Card Access server */ +#define BTA_ID_AV 18 /* Advanced audio/video */ +#define BTA_ID_AVK 19 /* Audio/video sink */ +#define BTA_ID_HD 20 /* HID Device */ +#define BTA_ID_CG 21 /* Cordless Gateway */ +#define BTA_ID_BP 22 /* Basic Printing Client */ +#define BTA_ID_HH 23 /* Human Interface Device Host */ +#define BTA_ID_PBS 24 /* Phone Book Access Server */ +#define BTA_ID_PBC 25 /* Phone Book Access Client */ +#define BTA_ID_JV 26 /* Java */ +#define BTA_ID_HS 27 /* Headset */ +#define BTA_ID_MSE 28 /* Message Server Equipment */ +#define BTA_ID_MCE 29 /* Message Client Equipment */ +#define BTA_ID_HL 30 /* Health Device Profile*/ +#define BTA_ID_GATTC 31 /* GATT Client */ +#define BTA_ID_GATTS 32 /* GATT Client */ +#define BTA_ID_SDP 33 /* SDP Client */ +#define BTA_ID_BLUETOOTH_MAX 34 /* last BT profile */ + +/* GENERIC */ +#define BTA_ID_PRM 38 +#define BTA_ID_SYSTEM 39 /* platform-specific */ +#define BTA_ID_SWRAP 40 /* Insight script wrapper */ +#define BTA_ID_MIP 41 /* Multicase Individual Polling */ +#define BTA_ID_RT 42 /* Audio Routing module: This module is always on. */ + + +/* JV */ +#define BTA_ID_JV1 44 /* JV1 */ +#define BTA_ID_JV2 45 /* JV2 */ + +#define BTA_ID_MAX (44 + BTA_DM_NUM_JV_ID) + +typedef UINT8 tBTA_SYS_ID; + + +#define BTA_SYS_CONN_OPEN 0x00 +#define BTA_SYS_CONN_CLOSE 0x01 +#define BTA_SYS_APP_OPEN 0x02 +#define BTA_SYS_APP_CLOSE 0x03 +#define BTA_SYS_SCO_OPEN 0x04 +#define BTA_SYS_SCO_CLOSE 0x05 +#define BTA_SYS_CONN_IDLE 0x06 +#define BTA_SYS_CONN_BUSY 0x07 + +/* for link policy */ +#define BTA_SYS_PLCY_SET 0x10 /* set the link policy to the given addr */ +#define BTA_SYS_PLCY_CLR 0x11 /* clear the link policy to the given addr */ +#define BTA_SYS_PLCY_DEF_SET 0x12 /* set the default link policy */ +#define BTA_SYS_PLCY_DEF_CLR 0x13 /* clear the default link policy */ +#define BTA_SYS_ROLE_CHANGE 0x14 /* role change */ + +typedef UINT8 tBTA_SYS_CONN_STATUS; + +/* Bitmask of sys features */ +#define BTA_SYS_FEAT_PCM2 0x0001 +#define BTA_SYS_FEAT_PCM2_MASTER 0x0002 + +/* tBTA_PREF_ROLES */ +typedef UINT8 tBTA_SYS_PREF_ROLES; + +/* conn callback for role / low power manager*/ +typedef void (tBTA_SYS_CONN_CBACK)(tBTA_SYS_CONN_STATUS status,UINT8 id, UINT8 app_id, BD_ADDR peer_addr); + +/* conn callback for role / low power manager*/ +typedef void (tBTA_SYS_SSR_CFG_CBACK)(UINT8 id, UINT8 app_id, UINT16 latency, UINT16 tout); + +#if (BTA_EIR_CANNED_UUID_LIST != TRUE) +/* eir callback for adding/removeing UUID */ +typedef void (tBTA_SYS_EIR_CBACK)(UINT16 uuid16, BOOLEAN adding); +#endif + +/* registration structure */ +typedef struct +{ + tBTA_SYS_EVT_HDLR *evt_hdlr; + tBTA_SYS_DISABLE *disable; +} tBTA_SYS_REG; + +/* data type to send events to BTA SYS HW manager */ +typedef struct +{ + BT_HDR hdr; + tBTA_SYS_HW_MODULE hw_module; +} tBTA_SYS_HW_MSG; + +/***************************************************************************** +** Global data +*****************************************************************************/ + +/* trace level */ +extern UINT8 appl_trace_level; + +/***************************************************************************** +** Macros +*****************************************************************************/ + +/* Calculate start of event enumeration; id is top 8 bits of event */ +#define BTA_SYS_EVT_START(id) ((id) << 8) + +/***************************************************************************** +** events for BTA SYS HW manager +*****************************************************************************/ + +/* events sent to SYS HW manager - must be kept synchronized with tables in bta_sys_main.c */ +enum +{ + /* device manager local device API events */ + BTA_SYS_API_ENABLE_EVT = BTA_SYS_EVT_START(BTA_ID_SYS), + BTA_SYS_EVT_ENABLED_EVT, + BTA_SYS_EVT_STACK_ENABLED_EVT, + BTA_SYS_API_DISABLE_EVT, + BTA_SYS_EVT_DISABLED_EVT, + BTA_SYS_ERROR_EVT, + + BTA_SYS_MAX_EVT +}; + + + +/* SYS HW status events - returned by SYS HW manager to other modules. */ +enum +{ + BTA_SYS_HW_OFF_EVT, + BTA_SYS_HW_ON_EVT, + BTA_SYS_HW_STARTING_EVT, + BTA_SYS_HW_STOPPING_EVT, + BTA_SYS_HW_ERROR_EVT + +}; +typedef UINT8 tBTA_SYS_HW_EVT; + +/* HW enable callback type */ +typedef void (tBTA_SYS_HW_CBACK)(tBTA_SYS_HW_EVT status); + +/***************************************************************************** +** Function declarations +*****************************************************************************/ + +#ifdef __cplusplus +extern "C" { +#endif + +extern void bta_sys_init(void); +extern void bta_sys_free(void); +extern void bta_sys_event(BT_HDR *p_msg); +extern void bta_sys_set_trace_level(UINT8 level); +extern void bta_sys_register(UINT8 id, const tBTA_SYS_REG *p_reg); +extern void bta_sys_deregister(UINT8 id); +extern BOOLEAN bta_sys_is_register(UINT8 id); +extern UINT16 bta_sys_get_sys_features(void); +extern void bta_sys_sendmsg(void *p_msg); +extern void bta_sys_start_timer(TIMER_LIST_ENT *p_tle, UINT16 type, INT32 timeout_ms); +extern void bta_sys_stop_timer(TIMER_LIST_ENT *p_tle); +extern void bta_sys_disable(tBTA_SYS_HW_MODULE module); +extern UINT32 bta_sys_get_remaining_ticks(TIMER_LIST_ENT *p_target_tle); + +extern void bta_sys_hw_register( tBTA_SYS_HW_MODULE module, tBTA_SYS_HW_CBACK *cback); +extern void bta_sys_hw_unregister( tBTA_SYS_HW_MODULE module ); + + +extern void bta_sys_rm_register(tBTA_SYS_CONN_CBACK * p_cback); +extern void bta_sys_pm_register(tBTA_SYS_CONN_CBACK * p_cback); + +extern void bta_sys_policy_register(tBTA_SYS_CONN_CBACK * p_cback); +extern void bta_sys_sco_register(tBTA_SYS_CONN_CBACK * p_cback); + + +extern void bta_sys_conn_open(UINT8 id, UINT8 app_id, BD_ADDR peer_addr); +extern void bta_sys_conn_close(UINT8 id, UINT8 app_id, BD_ADDR peer_addr); +extern void bta_sys_app_open(UINT8 id, UINT8 app_id, BD_ADDR peer_addr); +extern void bta_sys_app_close(UINT8 id, UINT8 app_id, BD_ADDR peer_addr); +extern void bta_sys_sco_open(UINT8 id, UINT8 app_id, BD_ADDR peer_addr); +extern void bta_sys_sco_close(UINT8 id, UINT8 app_id, BD_ADDR peer_addr); +extern void bta_sys_sco_use(UINT8 id, UINT8 app_id, BD_ADDR peer_addr); +extern void bta_sys_sco_unuse(UINT8 id, UINT8 app_id, BD_ADDR peer_addr); +extern void bta_sys_idle(UINT8 id, UINT8 app_id, BD_ADDR peer_addr); +extern void bta_sys_busy(UINT8 id, UINT8 app_id, BD_ADDR peer_addr); + +#if (BTM_SSR_INCLUDED == TRUE) +extern void bta_sys_ssr_cfg_register(tBTA_SYS_SSR_CFG_CBACK * p_cback); +extern void bta_sys_chg_ssr_config (UINT8 id, UINT8 app_id, UINT16 max_latency, UINT16 min_tout); +#endif + +extern void bta_sys_role_chg_register(tBTA_SYS_CONN_CBACK * p_cback); +extern void bta_sys_notify_role_chg(BD_ADDR_PTR p_bda, UINT8 new_role, UINT8 hci_status); +extern void bta_sys_collision_register(UINT8 bta_id, tBTA_SYS_CONN_CBACK *p_cback); +extern void bta_sys_notify_collision (BD_ADDR_PTR p_bda); + +#if (BTA_EIR_CANNED_UUID_LIST != TRUE) +extern void bta_sys_eir_register(tBTA_SYS_EIR_CBACK * p_cback); +extern void bta_sys_add_uuid(UINT16 uuid16); +extern void bta_sys_remove_uuid(UINT16 uuid16); +#else +#define bta_sys_eir_register(ut) +#define bta_sys_add_uuid(ut) +#define bta_sys_remove_uuid(ut) +#endif + +extern void bta_sys_set_policy (UINT8 id, UINT8 policy, BD_ADDR peer_addr); +extern void bta_sys_clear_policy (UINT8 id, UINT8 policy, BD_ADDR peer_addr); +extern void bta_sys_set_default_policy (UINT8 id, UINT8 policy); +extern void bta_sys_clear_default_policy (UINT8 id, UINT8 policy); +extern BOOLEAN bta_sys_vs_hdl(UINT16 evt, void *p); + +#ifdef __cplusplus +} +#endif + +#endif /* BTA_SYS_H */ diff --git a/components/bt/bluedroid/bta/include/utl.h b/components/bt/bluedroid/bta/include/utl.h new file mode 100755 index 0000000000..efae0678bc --- /dev/null +++ b/components/bt/bluedroid/bta/include/utl.h @@ -0,0 +1,170 @@ +/****************************************************************************** + * + * Copyright (C) 2003-2012 Broadcom Corporation + * + * 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. + * + ******************************************************************************/ + +/****************************************************************************** + * + * Basic utility functions. + * + ******************************************************************************/ +#ifndef UTL_H +#define UTL_H + +#include "bt_types.h" +// #include "bt_utils.h" + +/***************************************************************************** +** Constants +*****************************************************************************/ +/*** class of device settings ***/ +#define BTA_UTL_SET_COD_MAJOR_MINOR 0x01 +#define BTA_UTL_SET_COD_SERVICE_CLASS 0x02 /* only set the bits in the input */ +#define BTA_UTL_CLR_COD_SERVICE_CLASS 0x04 +#define BTA_UTL_SET_COD_ALL 0x08 /* take service class as the input (may clear some set bits!!) */ +#define BTA_UTL_INIT_COD 0x0a + +/***************************************************************************** +** Type Definitions +*****************************************************************************/ + +/** for utl_set_device_class() **/ +typedef struct +{ + UINT8 minor; + UINT8 major; + UINT16 service; +} tBTA_UTL_COD; + + +#ifdef __cplusplus +extern "C" +{ +#endif + +/***************************************************************************** +** External Function Declarations +*****************************************************************************/ + +/******************************************************************************* +** +** Function utl_str2int +** +** Description This utility function converts a character string to an +** integer. Acceptable values in string are 0-9. If invalid +** string or string value too large, -1 is returned. +** +** +** Returns Integer value or -1 on error. +** +*******************************************************************************/ +extern INT16 utl_str2int(const char *p_s); + +/******************************************************************************* +** +** Function utl_strucmp +** +** Description This utility function compares two strings in uppercase. +** String p_s must be uppercase. String p_t is converted to +** uppercase if lowercase. If p_s ends first, the substring +** match is counted as a match. +** +** +** Returns 0 if strings match, nonzero otherwise. +** +*******************************************************************************/ +extern int utl_strucmp(const char *p_s, const char *p_t); + +/******************************************************************************* +** +** Function utl_itoa +** +** Description This utility function converts a UINT16 to a string. The +** string is NULL-terminated. The length of the string is +** returned. +** +** +** Returns Length of string. +** +*******************************************************************************/ +extern UINT8 utl_itoa(UINT16 i, char *p_s); + +/******************************************************************************* +** +** Function utl_freebuf +** +** Description This function calls GKI_freebuf to free the buffer passed +** in, if buffer pointer is not NULL, and also initializes +** buffer pointer to NULL. +** +** +** Returns Nothing. +** +*******************************************************************************/ +extern void utl_freebuf(void **p); + +/******************************************************************************* +** +** Function utl_set_device_class +** +** Description This function updates the local Device Class. +** +** Parameters: +** p_cod - Pointer to the device class to set to +** +** cmd - the fields of the device class to update. +** BTA_UTL_SET_COD_MAJOR_MINOR, - overwrite major, minor class +** BTA_UTL_SET_COD_SERVICE_CLASS - set the bits in the input +** BTA_UTL_CLR_COD_SERVICE_CLASS - clear the bits in the input +** BTA_UTL_SET_COD_ALL - overwrite major, minor, set the bits in service class +** BTA_UTL_INIT_COD - overwrite major, minor, and service class +** +** Returns TRUE if successful, Otherwise FALSE +** +*******************************************************************************/ +extern BOOLEAN utl_set_device_class(tBTA_UTL_COD *p_cod, UINT8 cmd); + +/******************************************************************************* +** +** Function utl_isintstr +** +** Description This utility function checks if the given string is an +** integer string or not +** +** +** Returns TRUE if successful, Otherwise FALSE +** +*******************************************************************************/ +extern BOOLEAN utl_isintstr(const char *p_s); + +/******************************************************************************* +** +** Function utl_isdialstr +** +** Description This utility function checks if the given string contains +** only dial digits or not +** +** +** Returns TRUE if successful, Otherwise FALSE +** +*******************************************************************************/ +extern BOOLEAN utl_isdialstr(const char *p_s); + +#ifdef __cplusplus +} +#endif + +#endif /* UTL_H */ diff --git a/components/bt/bluedroid/bta/sys/bta_sys_conn.c b/components/bt/bluedroid/bta/sys/bta_sys_conn.c new file mode 100755 index 0000000000..087a9ff750 --- /dev/null +++ b/components/bt/bluedroid/bta/sys/bta_sys_conn.c @@ -0,0 +1,598 @@ +/****************************************************************************** + * + * Copyright (C) 2003-2012 Broadcom Corporation + * + * 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. + * + ******************************************************************************/ + +/****************************************************************************** + * + * Routes connection status callbacks from various sub systems to DM + * + ******************************************************************************/ + +#include +#include "bta_api.h" +#include "bta_sys.h" +#include "bta_sys_int.h" +#include "gki.h" +#include "utl.h" + +/******************************************************************************* +** +** Function bta_sys_rm_register +** +** Description Called by BTA DM to register role management callbacks +** +** +** Returns void +** +*******************************************************************************/ +void bta_sys_rm_register(tBTA_SYS_CONN_CBACK * p_cback) +{ + bta_sys_cb.prm_cb = p_cback; +} + + +/******************************************************************************* +** +** Function bta_sys_policy_register +** +** Description Called by BTA DM to register link policy change callbacks +** +** +** Returns void +** +*******************************************************************************/ +void bta_sys_policy_register(tBTA_SYS_CONN_CBACK * p_cback) +{ + bta_sys_cb.p_policy_cb = p_cback; +} + +/******************************************************************************* +** +** Function bta_sys_role_chg_register +** +** Description Called by BTA AV to register role change callbacks +** +** +** Returns void +** +*******************************************************************************/ +void bta_sys_role_chg_register(tBTA_SYS_CONN_CBACK * p_cback) +{ + bta_sys_cb.p_role_cb = p_cback; +} +/******************************************************************************* +** +** Function bta_sys_ssr_cfg_register +** +** Description Called by BTA DM to register SSR configuration callback +** +** +** Returns void +** +*******************************************************************************/ +#if (BTM_SSR_INCLUDED == TRUE) +void bta_sys_ssr_cfg_register(tBTA_SYS_SSR_CFG_CBACK * p_cback) +{ + bta_sys_cb.p_ssr_cb = p_cback; +} +#endif +/******************************************************************************* +** +** Function bta_sys_role_chg_register +** +** Description Called by BTA AV to register role change callbacks +** +** +** Returns void +** +*******************************************************************************/ +void bta_sys_notify_role_chg(BD_ADDR_PTR p_bda, UINT8 new_role, UINT8 hci_status) +{ + if (bta_sys_cb.p_role_cb) + { + bta_sys_cb.p_role_cb(BTA_SYS_ROLE_CHANGE, new_role, hci_status, p_bda); + } +} + +/******************************************************************************* +** +** Function bta_sys_collision_register +** +** Description Called by any BTA module to register for collision event. +** +** +** Returns void +** +*******************************************************************************/ +void bta_sys_collision_register(UINT8 bta_id, tBTA_SYS_CONN_CBACK *p_cback) +{ + UINT8 index; + + for (index = 0; index < MAX_COLLISION_REG; index++) + { + if ((bta_sys_cb.colli_reg.id[index] == bta_id) || + (bta_sys_cb.colli_reg.id[index] == 0)) + { + bta_sys_cb.colli_reg.id[index] = bta_id; + bta_sys_cb.colli_reg.p_coll_cback[index] = p_cback; + return; + } + } +} + +/******************************************************************************* +** +** Function bta_sys_notify_collision +** +** Description Called by BTA DM to notify collision event. +** +** +** Returns void +** +*******************************************************************************/ +void bta_sys_notify_collision (BD_ADDR_PTR p_bda) +{ + UINT8 index; + + for (index = 0; index < MAX_COLLISION_REG; index++) + { + if ((bta_sys_cb.colli_reg.id[index] != 0) && + (bta_sys_cb.colli_reg.p_coll_cback[index] != NULL)) + { + bta_sys_cb.colli_reg.p_coll_cback[index] (0, BTA_ID_SYS, 0, p_bda); + } + } +} + +/******************************************************************************* +** +** Function bta_sys_sco_register +** +** Description Called by BTA AV to register sco connection change callbacks +** +** +** Returns void +** +*******************************************************************************/ +void bta_sys_sco_register(tBTA_SYS_CONN_CBACK * p_cback) +{ + bta_sys_cb.p_sco_cb = p_cback; +} + +/******************************************************************************* +** +** Function bta_sys_pm_register +** +** Description Called by BTA DM to register power management callbacks +** +** +** Returns void +** +*******************************************************************************/ +void bta_sys_pm_register(tBTA_SYS_CONN_CBACK * p_cback) +{ + bta_sys_cb.ppm_cb = p_cback; +} + +/******************************************************************************* +** +** Function bta_sys_conn_open +** +** Description Called by BTA subsystems when a connection is made to +** the service +** +** +** Returns void +** +*******************************************************************************/ +void bta_sys_conn_open(UINT8 id, UINT8 app_id, BD_ADDR peer_addr) +{ + if(bta_sys_cb.prm_cb) + { + + bta_sys_cb.prm_cb(BTA_SYS_CONN_OPEN, id, app_id, peer_addr); + + } + + if(bta_sys_cb.ppm_cb) + { + + bta_sys_cb.ppm_cb(BTA_SYS_CONN_OPEN, id, app_id, peer_addr); + + } +} + + + +/******************************************************************************* +** +** Function bta_sys_conn_close +** +** Description Called by BTA subsystems when a connection to the service +** is closed +** +** +** Returns void +** +*******************************************************************************/ +void bta_sys_conn_close(UINT8 id, UINT8 app_id, BD_ADDR peer_addr) +{ + if(bta_sys_cb.prm_cb) + { + + bta_sys_cb.prm_cb(BTA_SYS_CONN_CLOSE, id, app_id, peer_addr); + + } + + if(bta_sys_cb.ppm_cb) + { + + bta_sys_cb.ppm_cb(BTA_SYS_CONN_CLOSE, id, app_id, peer_addr); + + } +} + + +/******************************************************************************* +** +** Function bta_sys_app_open +** +** Description Called by BTA subsystems when application initiates connection +** to a peer device +** +** +** Returns void +** +*******************************************************************************/ +void bta_sys_app_open(UINT8 id, UINT8 app_id, BD_ADDR peer_addr) +{ + if(bta_sys_cb.ppm_cb) + { + bta_sys_cb.ppm_cb(BTA_SYS_APP_OPEN, id, app_id, peer_addr); + } +} + + + +/******************************************************************************* +** +** Function bta_sys_app_close +** +** Description Called by BTA subsystems when application initiates close +** of connection to peer device +** +** Returns void +** +*******************************************************************************/ +void bta_sys_app_close(UINT8 id, UINT8 app_id, BD_ADDR peer_addr) +{ + if(bta_sys_cb.ppm_cb) + { + bta_sys_cb.ppm_cb(BTA_SYS_APP_CLOSE, id, app_id, peer_addr); + } +} + + +/******************************************************************************* +** +** Function bta_sys_sco_open +** +** Description Called by BTA subsystems when sco connection for that service +** is open +** +** Returns void +** +*******************************************************************************/ +void bta_sys_sco_open(UINT8 id, UINT8 app_id, BD_ADDR peer_addr) +{ + /* AG triggers p_sco_cb by bta_sys_sco_use. */ + if((id != BTA_ID_AG) && (bta_sys_cb.p_sco_cb)) + { + /* without querying BTM_GetNumScoLinks() */ + bta_sys_cb.p_sco_cb(BTA_SYS_SCO_OPEN, 1, app_id, peer_addr); + } + + if(bta_sys_cb.ppm_cb) + { + bta_sys_cb.ppm_cb(BTA_SYS_SCO_OPEN, id, app_id, peer_addr); + } +} + +/******************************************************************************* +** +** Function bta_sys_sco_close +** +** Description Called by BTA subsystems when sco connection for that service +** is closed +** +** Returns void +** +*******************************************************************************/ +void bta_sys_sco_close(UINT8 id, UINT8 app_id, BD_ADDR peer_addr) +{ + UINT8 num_sco_links; + + if((id != BTA_ID_AG) && (bta_sys_cb.p_sco_cb)) + { + num_sco_links = BTM_GetNumScoLinks(); + bta_sys_cb.p_sco_cb(BTA_SYS_SCO_CLOSE, num_sco_links, app_id, peer_addr); + } + + if(bta_sys_cb.ppm_cb) + { + bta_sys_cb.ppm_cb(BTA_SYS_SCO_CLOSE, id, app_id, peer_addr); + } +} + +/******************************************************************************* +** +** Function bta_sys_sco_use +** +** Description Called by BTA subsystems when that service needs to use sco. +** +** +** Returns void +** +*******************************************************************************/ +void bta_sys_sco_use(UINT8 id, UINT8 app_id, BD_ADDR peer_addr) +{ + UNUSED(id); + + /* AV streaming need to be suspended before SCO is connected. */ + if(bta_sys_cb.p_sco_cb) + { + /* without querying BTM_GetNumScoLinks() */ + bta_sys_cb.p_sco_cb(BTA_SYS_SCO_OPEN, 1, app_id, peer_addr); + } +} + +/******************************************************************************* +** +** Function bta_sys_sco_unuse +** +** Description Called by BTA subsystems when sco connection for that service +** is no longer needed. +** +** Returns void +** +*******************************************************************************/ +void bta_sys_sco_unuse(UINT8 id, UINT8 app_id, BD_ADDR peer_addr) +{ + UINT8 num_sco_links; + UNUSED(id); + + if((bta_sys_cb.p_sco_cb)) + { + num_sco_links = BTM_GetNumScoLinks(); + bta_sys_cb.p_sco_cb(BTA_SYS_SCO_CLOSE, num_sco_links, app_id, peer_addr); + } +} +/******************************************************************************* +** +** Function bta_sys_chg_ssr_config +** +** Description Called by BTA subsystems to indicate that the given app SSR setting +** need to be changed. +** +** Returns void +** +*******************************************************************************/ +#if (BTM_SSR_INCLUDED == TRUE) +void bta_sys_chg_ssr_config (UINT8 id, UINT8 app_id, UINT16 max_latency, UINT16 min_tout) +{ + if(bta_sys_cb.p_ssr_cb) + { + bta_sys_cb.p_ssr_cb(id, app_id, max_latency, min_tout); + } +} +#endif +/******************************************************************************* +** +** Function bta_sys_set_policy +** +** Description Called by BTA subsystems to indicate that the given link +** policy to peer device should be set +** +** Returns void +** +*******************************************************************************/ +void bta_sys_set_policy (UINT8 id, UINT8 policy, BD_ADDR peer_addr) +{ + if(bta_sys_cb.p_policy_cb) + { + bta_sys_cb.p_policy_cb(BTA_SYS_PLCY_SET, id, policy, peer_addr); + } +} + +/******************************************************************************* +** +** Function bta_sys_clear_policy +** +** Description Called by BTA subsystems to indicate that the given link +** policy to peer device should be clear +** +** Returns void +** +*******************************************************************************/ +void bta_sys_clear_policy (UINT8 id, UINT8 policy, BD_ADDR peer_addr) +{ + if(bta_sys_cb.p_policy_cb) + { + bta_sys_cb.p_policy_cb(BTA_SYS_PLCY_CLR, id, policy, peer_addr); + } +} + +/******************************************************************************* +** +** Function bta_sys_set_default_policy +** +** Description Called by BTA subsystems to indicate that the given default +** link policy should be set +** +** Returns void +** +*******************************************************************************/ +void bta_sys_set_default_policy (UINT8 id, UINT8 policy) +{ + if(bta_sys_cb.p_policy_cb) + { + bta_sys_cb.p_policy_cb(BTA_SYS_PLCY_DEF_SET, id, policy, NULL); + } +} + +/******************************************************************************* +** +** Function bta_sys_clear_default_policy +** +** Description Called by BTA subsystems to indicate that the given default +** link policy should be clear +** +** Returns void +** +*******************************************************************************/ +void bta_sys_clear_default_policy (UINT8 id, UINT8 policy) +{ + if(bta_sys_cb.p_policy_cb) + { + bta_sys_cb.p_policy_cb(BTA_SYS_PLCY_DEF_CLR, id, policy, NULL); + } +} + +/******************************************************************************* +** +** Function bta_sys_idle +** +** Description Called by BTA subsystems to indicate that the connection to +** peer device is idle +** +** Returns void +** +*******************************************************************************/ +void bta_sys_idle(UINT8 id, UINT8 app_id, BD_ADDR peer_addr) +{ + + if(bta_sys_cb.prm_cb) + { + + bta_sys_cb.prm_cb(BTA_SYS_CONN_IDLE, id, app_id, peer_addr); + + } + + if(bta_sys_cb.ppm_cb) + { + + bta_sys_cb.ppm_cb(BTA_SYS_CONN_IDLE, id, app_id, peer_addr); + } +} + +/******************************************************************************* +** +** Function bta_sys_busy +** +** Description Called by BTA subsystems to indicate that the connection to +** peer device is busy +** +** Returns void +** +*******************************************************************************/ +void bta_sys_busy(UINT8 id, UINT8 app_id, BD_ADDR peer_addr) +{ + if(bta_sys_cb.prm_cb) + { + + bta_sys_cb.prm_cb(BTA_SYS_CONN_BUSY, id, app_id, peer_addr); + + } + + if(bta_sys_cb.ppm_cb) + { + + bta_sys_cb.ppm_cb(BTA_SYS_CONN_BUSY, id, app_id, peer_addr); + + } +} + +#if (BTA_EIR_CANNED_UUID_LIST != TRUE) +/******************************************************************************* +** +** Function bta_sys_eir_register +** +** Description Called by BTA DM to register EIR utility function that can be +** used by the other BTA modules to add/remove UUID. +** +** Returns void +** +*******************************************************************************/ +void bta_sys_eir_register(tBTA_SYS_EIR_CBACK * p_cback) +{ + bta_sys_cb.eir_cb = p_cback; +} + +/******************************************************************************* +** +** Function bta_sys_add_uuid +** +** Description Called by BTA subsystems to indicate to DM that new service +** class UUID is added. +** +** Returns void +** +*******************************************************************************/ +void bta_sys_add_uuid(UINT16 uuid16) +{ + if(bta_sys_cb.eir_cb) + { + bta_sys_cb.eir_cb(uuid16, TRUE ); + } +} + +/******************************************************************************* +** +** Function bta_sys_remove_uuid +** +** Description Called by BTA subsystems to indicate to DM that the service +** class UUID is removed. +** +** Returns void +** +*******************************************************************************/ +void bta_sys_remove_uuid(UINT16 uuid16) +{ + if(bta_sys_cb.eir_cb) + { + bta_sys_cb.eir_cb(uuid16, FALSE); + } +} +#endif + +/******************************************************************************* +** +** Function bta_sys_vs_hdl +** +** Description Called by BTA subsystems to execute a VS event handler function +** +** Returns void +** +*******************************************************************************/ +BOOLEAN bta_sys_vs_hdl(UINT16 evt, void *p) +{ + if (bta_sys_cb.p_vs_evt_hdlr) + return (*bta_sys_cb.p_vs_evt_hdlr)(evt, p); + + return FALSE; +} + diff --git a/components/bt/bluedroid/bta/sys/bta_sys_main.c b/components/bt/bluedroid/bta/sys/bta_sys_main.c new file mode 100755 index 0000000000..8029db37c2 --- /dev/null +++ b/components/bt/bluedroid/bta/sys/bta_sys_main.c @@ -0,0 +1,754 @@ +/****************************************************************************** + * + * Copyright (C) 2003-2012 Broadcom Corporation + * + * 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 is the main implementation file for the BTA system manager. + * + ******************************************************************************/ +#define LOG_TAG "bt_bta_sys_main" + +// #include +#include + +#include "alarm.h" +#include "thread.h" +#include "btm_api.h" +#include "bta_api.h" +#include "bta_sys.h" +#include "bta_sys_int.h" + +#include "fixed_queue.h" +#include "gki.h" +#include "hash_map.h" +#include "osi.h" +#include "hash_functions.h" +// #include "osi/include/log.h" +// #include "osi/include/thread.h" +#if( defined BTA_AR_INCLUDED ) && (BTA_AR_INCLUDED == TRUE) +#include "bta_ar_api.h" +#endif +#include "utl.h" + + +/* system manager control block definition */ +#if BTA_DYNAMIC_MEMORY == FALSE +tBTA_SYS_CB bta_sys_cb; +#endif + +fixed_queue_t *btu_bta_alarm_queue; +static hash_map_t *bta_alarm_hash_map; +static const size_t BTA_ALARM_HASH_MAP_SIZE = 17; +static pthread_mutex_t bta_alarm_lock; +// extern thread_t *bt_workqueue_thread; + +/* trace level */ +/* TODO Bluedroid - Hard-coded trace levels - Needs to be configurable */ +UINT8 appl_trace_level = BT_TRACE_LEVEL_WARNING; //APPL_INITIAL_TRACE_LEVEL; +UINT8 btif_trace_level = BT_TRACE_LEVEL_WARNING; + +// Communication queue between btu_task and bta. +extern fixed_queue_t *btu_bta_msg_queue; +void btu_bta_alarm_ready(fixed_queue_t *queue); + +static const tBTA_SYS_REG bta_sys_hw_reg = +{ + bta_sys_sm_execute, + NULL +}; + + +/* type for action functions */ +typedef void (*tBTA_SYS_ACTION)(tBTA_SYS_HW_MSG *p_data); + +/* action function list */ +const tBTA_SYS_ACTION bta_sys_action[] = +{ + /* device manager local device API events - cf bta_sys.h for events */ + bta_sys_hw_api_enable, /* 0 BTA_SYS_HW_API_ENABLE_EVT */ + bta_sys_hw_evt_enabled, /* 1 BTA_SYS_HW_EVT_ENABLED_EVT */ + bta_sys_hw_evt_stack_enabled, /* 2 BTA_SYS_HW_EVT_STACK_ENABLED_EVT */ + bta_sys_hw_api_disable, /* 3 BTA_SYS_HW_API_DISABLE_EVT */ + bta_sys_hw_evt_disabled, /* 4 BTA_SYS_HW_EVT_DISABLED_EVT */ + bta_sys_hw_error /* 5 BTA_SYS_HW_ERROR_EVT */ +}; + +/* state machine action enumeration list */ +enum +{ + /* device manager local device API events */ + BTA_SYS_HW_API_ENABLE, + BTA_SYS_HW_EVT_ENABLED, + BTA_SYS_HW_EVT_STACK_ENABLED, + BTA_SYS_HW_API_DISABLE, + BTA_SYS_HW_EVT_DISABLED, + BTA_SYS_HW_ERROR +}; + +#define BTA_SYS_NUM_ACTIONS (BTA_SYS_MAX_EVT & 0x00ff) +#define BTA_SYS_IGNORE BTA_SYS_NUM_ACTIONS + +/* state table information */ +#define BTA_SYS_ACTIONS 2 /* number of actions */ +#define BTA_SYS_NEXT_STATE 2 /* position of next state */ +#define BTA_SYS_NUM_COLS 3 /* number of columns in state tables */ + + +/* state table for OFF state */ +const UINT8 bta_sys_hw_off[][BTA_SYS_NUM_COLS] = +{ +/* Event Action 1 Action 2 Next State */ +/* API_ENABLE */ {BTA_SYS_HW_API_ENABLE, BTA_SYS_IGNORE, BTA_SYS_HW_STARTING}, +/* EVT_ENABLED */ {BTA_SYS_IGNORE, BTA_SYS_IGNORE, BTA_SYS_HW_STARTING}, +/* STACK_ENABLED */ {BTA_SYS_IGNORE, BTA_SYS_IGNORE, BTA_SYS_HW_ON}, +/* API_DISABLE */ {BTA_SYS_HW_EVT_DISABLED, BTA_SYS_IGNORE, BTA_SYS_HW_OFF}, +/* EVT_DISABLED */ {BTA_SYS_IGNORE, BTA_SYS_IGNORE, BTA_SYS_HW_OFF}, +/* EVT_ERROR */ {BTA_SYS_IGNORE, BTA_SYS_IGNORE, BTA_SYS_HW_OFF} +}; + +const UINT8 bta_sys_hw_starting[][BTA_SYS_NUM_COLS] = +{ +/* Event Action 1 Action 2 Next State */ +/* API_ENABLE */ {BTA_SYS_IGNORE, BTA_SYS_IGNORE, BTA_SYS_HW_STARTING}, /* wait for completion event */ +/* EVT_ENABLED */ {BTA_SYS_HW_EVT_ENABLED, BTA_SYS_IGNORE, BTA_SYS_HW_STARTING}, +/* STACK_ENABLED */ {BTA_SYS_HW_EVT_STACK_ENABLED, BTA_SYS_IGNORE, BTA_SYS_HW_ON}, +/* API_DISABLE */ {BTA_SYS_IGNORE, BTA_SYS_IGNORE, BTA_SYS_HW_STOPPING}, /* successive disable/enable: change state wait for completion to disable */ +/* EVT_DISABLED */ {BTA_SYS_HW_EVT_DISABLED, BTA_SYS_HW_API_ENABLE, BTA_SYS_HW_STARTING}, /* successive enable/disable: notify, then restart HW */ +/* EVT_ERROR */ {BTA_SYS_HW_ERROR, BTA_SYS_IGNORE, BTA_SYS_HW_ON} +}; + +const UINT8 bta_sys_hw_on[][BTA_SYS_NUM_COLS] = +{ +/* Event Action 1 Action 2 Next State */ +/* API_ENABLE */ {BTA_SYS_HW_API_ENABLE, BTA_SYS_IGNORE, BTA_SYS_HW_ON}, +/* EVT_ENABLED */ {BTA_SYS_IGNORE, BTA_SYS_IGNORE, BTA_SYS_HW_ON}, +/* STACK_ENABLED */ {BTA_SYS_IGNORE, BTA_SYS_IGNORE, BTA_SYS_HW_ON}, +/* API_DISABLE */ {BTA_SYS_HW_API_DISABLE, BTA_SYS_IGNORE, BTA_SYS_HW_ON}, /* don't change the state here, as some other modules might be active */ +/* EVT_DISABLED */ {BTA_SYS_HW_ERROR, BTA_SYS_IGNORE, BTA_SYS_HW_ON}, +/* EVT_ERROR */ {BTA_SYS_HW_ERROR, BTA_SYS_IGNORE, BTA_SYS_HW_ON} +}; + +const UINT8 bta_sys_hw_stopping[][BTA_SYS_NUM_COLS] = +{ +/* Event Action 1 Action 2 Next State */ +/* API_ENABLE */ {BTA_SYS_IGNORE, BTA_SYS_IGNORE, BTA_SYS_HW_STARTING}, /* change state, and wait for completion event to enable */ +/* EVT_ENABLED */ {BTA_SYS_HW_EVT_ENABLED, BTA_SYS_IGNORE, BTA_SYS_HW_STOPPING}, /* successive enable/disable: finish the enable before disabling */ +/* STACK_ENABLED */ {BTA_SYS_HW_EVT_STACK_ENABLED, BTA_SYS_HW_API_DISABLE, BTA_SYS_HW_STOPPING}, /* successive enable/disable: notify, then stop */ +/* API_DISABLE */ {BTA_SYS_IGNORE, BTA_SYS_IGNORE, BTA_SYS_HW_STOPPING}, /* wait for completion event */ +/* EVT_DISABLED */ {BTA_SYS_HW_EVT_DISABLED, BTA_SYS_IGNORE, BTA_SYS_HW_OFF}, +/* EVT_ERROR */ {BTA_SYS_HW_API_DISABLE, BTA_SYS_IGNORE, BTA_SYS_HW_STOPPING} +}; + +typedef const UINT8 (*tBTA_SYS_ST_TBL)[BTA_SYS_NUM_COLS]; + +/* state table */ +const tBTA_SYS_ST_TBL bta_sys_st_tbl[] = { + bta_sys_hw_off, + bta_sys_hw_starting, + bta_sys_hw_on, + bta_sys_hw_stopping +}; + +/******************************************************************************* +** +** Function bta_sys_init +** +** Description BTA initialization; called from task initialization. +** +** +** Returns void +** +*******************************************************************************/ +void bta_sys_init(void) +{ + memset(&bta_sys_cb, 0, sizeof(tBTA_SYS_CB)); + + pthread_mutex_init(&bta_alarm_lock, NULL); + + bta_alarm_hash_map = hash_map_new(BTA_ALARM_HASH_MAP_SIZE, + hash_function_pointer, NULL, (data_free_fn)osi_alarm_free, NULL); + btu_bta_alarm_queue = fixed_queue_new(SIZE_MAX); + + fixed_queue_register_dequeue(btu_bta_alarm_queue, + btu_bta_alarm_ready); + + appl_trace_level = APPL_INITIAL_TRACE_LEVEL; + + /* register BTA SYS message handler */ + bta_sys_register( BTA_ID_SYS, &bta_sys_hw_reg); + + /* register for BTM notifications */ + BTM_RegisterForDeviceStatusNotif ((tBTM_DEV_STATUS_CB*)&bta_sys_hw_btm_cback ); + +#if( defined BTA_AR_INCLUDED ) && (BTA_AR_INCLUDED == TRUE) + bta_ar_init(); +#endif + +} + +void bta_sys_free(void) { + fixed_queue_free(btu_bta_alarm_queue, NULL); + hash_map_free(bta_alarm_hash_map); + pthread_mutex_destroy(&bta_alarm_lock); +} + +/******************************************************************************* +** +** Function bta_dm_sm_execute +** +** Description State machine event handling function for DM +** +** +** Returns void +** +*******************************************************************************/ +BOOLEAN bta_sys_sm_execute(BT_HDR *p_msg) +{ + BOOLEAN freebuf = TRUE; + tBTA_SYS_ST_TBL state_table; + UINT8 action; + int i; + + APPL_TRACE_EVENT("bta_sys_sm_execute state:%d, event:0x%x", bta_sys_cb.state, p_msg->event); + + /* look up the state table for the current state */ + state_table = bta_sys_st_tbl[bta_sys_cb.state]; + /* update state */ + bta_sys_cb.state = state_table[p_msg->event & 0x00ff][BTA_SYS_NEXT_STATE]; + + /* execute action functions */ + for (i = 0; i < BTA_SYS_ACTIONS; i++) + { + if ((action = state_table[p_msg->event & 0x00ff][i]) != BTA_SYS_IGNORE) + { + (*bta_sys_action[action])( (tBTA_SYS_HW_MSG*) p_msg); + } + else + { + break; + } + } + return freebuf; + +} + + +void bta_sys_hw_register( tBTA_SYS_HW_MODULE module, tBTA_SYS_HW_CBACK *cback) +{ + bta_sys_cb.sys_hw_cback[module]=cback; +} + + +void bta_sys_hw_unregister( tBTA_SYS_HW_MODULE module ) +{ + bta_sys_cb.sys_hw_cback[module]=NULL; +} + +/******************************************************************************* +** +** Function bta_sys_hw_btm_cback +** +** Description This function is registered by BTA SYS to BTM in order to get status notifications +** +** +** Returns +** +*******************************************************************************/ +void bta_sys_hw_btm_cback( tBTM_DEV_STATUS status ) +{ + + tBTA_SYS_HW_MSG *sys_event; + + APPL_TRACE_DEBUG(" bta_sys_hw_btm_cback was called with parameter: %i" , status ); + + /* send a message to BTA SYS */ + if ((sys_event = (tBTA_SYS_HW_MSG *) GKI_getbuf(sizeof(tBTA_SYS_HW_MSG))) != NULL) + { + if (status == BTM_DEV_STATUS_UP) + sys_event->hdr.event = BTA_SYS_EVT_STACK_ENABLED_EVT; + else if (status == BTM_DEV_STATUS_DOWN) + sys_event->hdr.event = BTA_SYS_ERROR_EVT; + else + { + /* BTM_DEV_STATUS_CMD_TOUT is ignored for now. */ + GKI_freebuf (sys_event); + sys_event = NULL; + } + + if (sys_event) + { + bta_sys_sendmsg(sys_event); + } + } + else + { + APPL_TRACE_DEBUG("ERROR bta_sys_hw_btm_cback couldn't send msg" ); + } +} + + + +/******************************************************************************* +** +** Function bta_sys_hw_error +** +** Description In case the HW device stops answering... Try to turn it off, then re-enable all +** previously active SW modules. +** +** Returns success or failure +** +*******************************************************************************/ +void bta_sys_hw_error(tBTA_SYS_HW_MSG *p_sys_hw_msg) +{ + UINT8 module_index; + UNUSED(p_sys_hw_msg); + + APPL_TRACE_DEBUG("%s", __FUNCTION__); + + for (module_index = 0; module_index < BTA_SYS_MAX_HW_MODULES; module_index++) + { + if( bta_sys_cb.sys_hw_module_active & ((UINT32)1 << module_index )) { + switch( module_index) + { + case BTA_SYS_HW_BLUETOOTH: + /* Send BTA_SYS_HW_ERROR_EVT to DM */ + if (bta_sys_cb.sys_hw_cback[module_index] != NULL) + bta_sys_cb.sys_hw_cback[module_index] (BTA_SYS_HW_ERROR_EVT); + break; + default: + /* not yet supported */ + break; + } + } + } +} + + + +/******************************************************************************* +** +** Function bta_sys_hw_enable +** +** Description this function is called after API enable and HW has been turned on +** +** +** Returns success or failure +** +*******************************************************************************/ + +void bta_sys_hw_api_enable( tBTA_SYS_HW_MSG *p_sys_hw_msg ) +{ + if ((!bta_sys_cb.sys_hw_module_active) && (bta_sys_cb.state != BTA_SYS_HW_ON)) + { + /* register which HW module was turned on */ + bta_sys_cb.sys_hw_module_active |= ((UINT32)1 << p_sys_hw_msg->hw_module ); + + tBTA_SYS_HW_MSG *p_msg; + if ((p_msg = (tBTA_SYS_HW_MSG *) GKI_getbuf(sizeof(tBTA_SYS_HW_MSG))) != NULL) + { + p_msg->hdr.event = BTA_SYS_EVT_ENABLED_EVT; + p_msg->hw_module = p_sys_hw_msg->hw_module; + + bta_sys_sendmsg(p_msg); + } + } + else + { + /* register which HW module was turned on */ + bta_sys_cb.sys_hw_module_active |= ((UINT32)1 << p_sys_hw_msg->hw_module ); + + /* HW already in use, so directly notify the caller */ + if (bta_sys_cb.sys_hw_cback[p_sys_hw_msg->hw_module ]!= NULL ) + bta_sys_cb.sys_hw_cback[p_sys_hw_msg->hw_module ]( BTA_SYS_HW_ON_EVT ); + } + + APPL_TRACE_EVENT ("bta_sys_hw_api_enable for %d, active modules 0x%04X", + p_sys_hw_msg->hw_module, bta_sys_cb.sys_hw_module_active); + +} + +/******************************************************************************* +** +** Function bta_sys_hw_disable +** +** Description if no other module is using the HW, this function will call ( if defined ) a user-macro to turn off the HW +** +** +** Returns success or failure +** +*******************************************************************************/ +void bta_sys_hw_api_disable(tBTA_SYS_HW_MSG *p_sys_hw_msg) +{ + APPL_TRACE_DEBUG("bta_sys_hw_api_disable for %d, active modules: 0x%04X", + p_sys_hw_msg->hw_module, bta_sys_cb.sys_hw_module_active ); + + /* make sure the related SW blocks were stopped */ + bta_sys_disable( p_sys_hw_msg->hw_module ); + + + /* register which module we turn off */ + bta_sys_cb.sys_hw_module_active &= ~((UINT32)1 << p_sys_hw_msg->hw_module ); + + + /* if there are still some SW modules using the HW, just provide an answer to the calling */ + if( bta_sys_cb.sys_hw_module_active != 0 ) + { + /* if there are still some SW modules using the HW, directly notify the caller */ + if( bta_sys_cb.sys_hw_cback[p_sys_hw_msg->hw_module ]!= NULL ) + bta_sys_cb.sys_hw_cback[p_sys_hw_msg->hw_module ]( BTA_SYS_HW_OFF_EVT ); + } + else + { + /* manually update the state of our system */ + bta_sys_cb.state = BTA_SYS_HW_STOPPING; + + tBTA_SYS_HW_MSG *p_msg; + if ((p_msg = (tBTA_SYS_HW_MSG *) GKI_getbuf(sizeof(tBTA_SYS_HW_MSG))) != NULL) + { + p_msg->hdr.event = BTA_SYS_EVT_DISABLED_EVT; + p_msg->hw_module = p_sys_hw_msg->hw_module; + + bta_sys_sendmsg(p_msg); + } + } + +} + + +/******************************************************************************* +** +** Function bta_sys_hw_event_enabled +** +** Description +** +** +** Returns success or failure +** +*******************************************************************************/ +void bta_sys_hw_evt_enabled(tBTA_SYS_HW_MSG *p_sys_hw_msg) +{ + APPL_TRACE_EVENT("bta_sys_hw_evt_enabled for %i", p_sys_hw_msg->hw_module); + BTM_DeviceReset( NULL ); +} + + +/******************************************************************************* +** +** Function bta_sys_hw_event_disabled +** +** Description +** +** +** Returns success or failure +** +*******************************************************************************/ +void bta_sys_hw_evt_disabled(tBTA_SYS_HW_MSG *p_sys_hw_msg) +{ + UINT8 hw_module_index; + + APPL_TRACE_DEBUG("bta_sys_hw_evt_disabled - module 0x%X", p_sys_hw_msg->hw_module); + + for (hw_module_index = 0; hw_module_index < BTA_SYS_MAX_HW_MODULES; hw_module_index++) + { + if (bta_sys_cb.sys_hw_cback[hw_module_index] != NULL) + bta_sys_cb.sys_hw_cback[hw_module_index] (BTA_SYS_HW_OFF_EVT); + } +} + +/******************************************************************************* +** +** Function bta_sys_hw_event_stack_enabled +** +** Description we receive this event once the SW side is ready ( stack, FW download,... ), +** i.e. we can really start using the device. So notify the app. +** +** Returns success or failure +** +*******************************************************************************/ +void bta_sys_hw_evt_stack_enabled(tBTA_SYS_HW_MSG *p_sys_hw_msg) +{ + UINT8 hw_module_index; + UNUSED(p_sys_hw_msg); + + APPL_TRACE_DEBUG(" bta_sys_hw_evt_stack_enabled!notify the callers"); + + for (hw_module_index = 0; hw_module_index < BTA_SYS_MAX_HW_MODULES; hw_module_index++ ) + { + if (bta_sys_cb.sys_hw_cback[hw_module_index] != NULL) + bta_sys_cb.sys_hw_cback[hw_module_index] (BTA_SYS_HW_ON_EVT); + } +} + + + + +/******************************************************************************* +** +** Function bta_sys_event +** +** Description BTA event handler; called from task event handler. +** +** +** Returns void +** +*******************************************************************************/ +void bta_sys_event(BT_HDR *p_msg) +{ + UINT8 id; + BOOLEAN freebuf = TRUE; + + APPL_TRACE_EVENT("BTA got event 0x%x", p_msg->event); + + /* get subsystem id from event */ + id = (UINT8) (p_msg->event >> 8); + + /* verify id and call subsystem event handler */ + if ((id < BTA_ID_MAX) && (bta_sys_cb.reg[id] != NULL)) + { + freebuf = (*bta_sys_cb.reg[id]->evt_hdlr)(p_msg); + } + else + { + APPL_TRACE_WARNING("BTA got unregistered event id %d", id); + } + + if (freebuf) + { + GKI_freebuf(p_msg); + } + +} + +/******************************************************************************* +** +** Function bta_sys_register +** +** Description Called by other BTA subsystems to register their event +** handler. +** +** +** Returns void +** +*******************************************************************************/ +void bta_sys_register(UINT8 id, const tBTA_SYS_REG *p_reg) +{ + bta_sys_cb.reg[id] = (tBTA_SYS_REG *) p_reg; + bta_sys_cb.is_reg[id] = TRUE; +} + +/******************************************************************************* +** +** Function bta_sys_deregister +** +** Description Called by other BTA subsystems to de-register +** handler. +** +** +** Returns void +** +*******************************************************************************/ +void bta_sys_deregister(UINT8 id) +{ + bta_sys_cb.is_reg[id] = FALSE; +} + +/******************************************************************************* +** +** Function bta_sys_is_register +** +** Description Called by other BTA subsystems to get registeration +** status. +** +** +** Returns void +** +*******************************************************************************/ +BOOLEAN bta_sys_is_register(UINT8 id) +{ + return bta_sys_cb.is_reg[id]; +} + +/******************************************************************************* +** +** Function bta_sys_sendmsg +** +** Description Send a GKI message to BTA. This function is designed to +** optimize sending of messages to BTA. It is called by BTA +** API functions and call-in functions. +** +** +** Returns void +** +*******************************************************************************/ +void bta_sys_sendmsg(void *p_msg) +{ + // There is a race condition that occurs if the stack is shut down while + // there is a procedure in progress that can schedule a task via this + // message queue. This causes |btu_bta_msg_queue| to get cleaned up before + // it gets used here; hence we check for NULL before using it. + if (btu_bta_msg_queue) { + fixed_queue_enqueue(btu_bta_msg_queue, p_msg); + //ke_event_set(KE_EVENT_BTU_TASK_THREAD); + btu_task_post(); + } +} + +/******************************************************************************* +** +** Function bta_sys_start_timer +** +** Description Start a protocol timer for the specified amount +** of time in milliseconds. +** +** Returns void +** +*******************************************************************************/ +void bta_alarm_cb(void *data) { + assert(data != NULL); + TIMER_LIST_ENT *p_tle = (TIMER_LIST_ENT *)data; + + fixed_queue_enqueue(btu_bta_alarm_queue, p_tle); +} + +void bta_sys_start_timer(TIMER_LIST_ENT *p_tle, UINT16 type, INT32 timeout_ms) { + assert(p_tle != NULL); + + // Get the alarm for this p_tle. + pthread_mutex_lock(&bta_alarm_lock); + if (!hash_map_has_key(bta_alarm_hash_map, p_tle)) { + hash_map_set(bta_alarm_hash_map, p_tle, osi_alarm_new("bta_sys", bta_alarm_cb, p_tle, 0)); + } + pthread_mutex_unlock(&bta_alarm_lock); + + osi_alarm_t *alarm = hash_map_get(bta_alarm_hash_map, p_tle); + if (alarm == NULL) { + LOG_ERROR("%s unable to create alarm.", __func__); + return; + } + + p_tle->event = type; + p_tle->ticks = timeout_ms; + //osi_alarm_set(alarm, (period_ms_t)timeout_ms, bta_alarm_cb, p_tle); + osi_alarm_set(alarm, (period_ms_t)timeout_ms); +} + +bool hash_iter_ro_cb(hash_map_entry_t *hash_map_entry, void *context) +{ + osi_alarm_t *alarm = (osi_alarm_t *)hash_map_entry->data; + period_ms_t *p_remaining_ms = (period_ms_t*)context; + *p_remaining_ms +=osi_alarm_get_remaining_ms(alarm); + return true; +} + +UINT32 bta_sys_get_remaining_ticks(TIMER_LIST_ENT *p_target_tle) +{ + period_ms_t remaining_ms = 0; + pthread_mutex_lock(&bta_alarm_lock); + // Get the alarm for this p_tle + hash_map_foreach(bta_alarm_hash_map, hash_iter_ro_cb, &remaining_ms); + pthread_mutex_unlock(&bta_alarm_lock); + return remaining_ms; +} + + +/******************************************************************************* +** +** Function bta_sys_stop_timer +** +** Description Stop a BTA timer. +** +** Returns void +** +*******************************************************************************/ +void bta_sys_stop_timer(TIMER_LIST_ENT *p_tle) { + assert(p_tle != NULL); + + osi_alarm_t *alarm = hash_map_get(bta_alarm_hash_map, p_tle); + if (alarm == NULL) { + LOG_DEBUG("%s expected alarm was not in bta alarm hash map.", __func__); + return; + } + osi_alarm_cancel(alarm); +} + +/******************************************************************************* +** +** Function bta_sys_disable +** +** Description For each registered subsystem execute its disable function. +** +** Returns void +** +*******************************************************************************/ +void bta_sys_disable(tBTA_SYS_HW_MODULE module) +{ + int bta_id = 0; + int bta_id_max = 0; + + APPL_TRACE_DEBUG("bta_sys_disable: module %i", module); + + switch( module ) + { + case BTA_SYS_HW_BLUETOOTH: + bta_id = BTA_ID_DM; + bta_id_max = BTA_ID_BLUETOOTH_MAX; + break; + default: + APPL_TRACE_WARNING("bta_sys_disable: unkown module"); + return; + } + + for ( ; bta_id <= bta_id_max; bta_id++) + { + if (bta_sys_cb.reg[bta_id] != NULL) + { + if (bta_sys_cb.is_reg[bta_id] == TRUE && bta_sys_cb.reg[bta_id]->disable != NULL) + { + (*bta_sys_cb.reg[bta_id]->disable)(); + } + } + } +} + +/******************************************************************************* +** +** Function bta_sys_set_trace_level +** +** Description Set trace level for BTA +** +** Returns void +** +*******************************************************************************/ +void bta_sys_set_trace_level(UINT8 level) +{ + appl_trace_level = level; +} + +/******************************************************************************* +** +** Function bta_sys_get_sys_features +** +** Description Returns sys_features to other BTA modules. +** +** Returns sys_features +** +*******************************************************************************/ +UINT16 bta_sys_get_sys_features (void) +{ + return bta_sys_cb.sys_features; +} diff --git a/components/bt/bluedroid/bta/sys/include/bta_sys_int.h b/components/bt/bluedroid/bta/sys/include/bta_sys_int.h new file mode 100755 index 0000000000..e9c192988a --- /dev/null +++ b/components/bt/bluedroid/bta/sys/include/bta_sys_int.h @@ -0,0 +1,104 @@ +/****************************************************************************** + * + * Copyright (C) 2003-2012 Broadcom Corporation + * + * 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 is the private interface file for the BTA system manager. + * + ******************************************************************************/ +#ifndef BTA_SYS_INT_H +#define BTA_SYS_INT_H + +/***************************************************************************** +** Constants and data types +*****************************************************************************/ + +/***************************************************************************** +** state table +*****************************************************************************/ + +/* SYS HW state */ +enum +{ + BTA_SYS_HW_OFF, + BTA_SYS_HW_STARTING, + BTA_SYS_HW_ON, + BTA_SYS_HW_STOPPING +}; +typedef UINT8 tBTA_SYS_HW_STATE; + +/* Collision callback */ +#define MAX_COLLISION_REG 5 + +typedef struct +{ + UINT8 id[MAX_COLLISION_REG]; + tBTA_SYS_CONN_CBACK *p_coll_cback[MAX_COLLISION_REG]; +} tBTA_SYS_COLLISION; + +/* system manager control block */ +typedef struct +{ + tBTA_SYS_REG *reg[BTA_ID_MAX]; /* registration structures */ + BOOLEAN is_reg[BTA_ID_MAX]; /* registration structures */ + tBTA_SYS_HW_STATE state; + tBTA_SYS_HW_CBACK *sys_hw_cback[BTA_SYS_MAX_HW_MODULES]; /* enable callback for each HW modules */ + UINT32 sys_hw_module_active; /* bitmask of all active modules */ + UINT16 sys_features; /* Bitmask of sys features */ + + tBTA_SYS_CONN_CBACK *prm_cb; /* role management callback registered by DM */ + tBTA_SYS_CONN_CBACK *ppm_cb; /* low power management callback registered by DM */ + tBTA_SYS_CONN_CBACK *p_policy_cb; /* link policy change callback registered by DM */ + tBTA_SYS_CONN_CBACK *p_sco_cb; /* SCO connection change callback registered by AV */ + tBTA_SYS_CONN_CBACK *p_role_cb; /* role change callback registered by AV */ + tBTA_SYS_COLLISION colli_reg; /* collision handling module */ +#if (BTA_EIR_CANNED_UUID_LIST != TRUE) + tBTA_SYS_EIR_CBACK *eir_cb; /* add/remove UUID into EIR */ +#endif +#if (BTM_SSR_INCLUDED == TRUE) + tBTA_SYS_SSR_CFG_CBACK *p_ssr_cb; +#endif + /* VS event handler */ + tBTA_SYS_VS_EVT_HDLR *p_vs_evt_hdlr; + +} tBTA_SYS_CB; + +/***************************************************************************** +** Global variables +*****************************************************************************/ + +/* system manager control block */ +#if BTA_DYNAMIC_MEMORY == FALSE +extern tBTA_SYS_CB bta_sys_cb; +#else +extern tBTA_SYS_CB *bta_sys_cb_ptr; +#define bta_sys_cb (*bta_sys_cb_ptr) +#endif + +/* functions used for BTA SYS HW state machine */ +void bta_sys_hw_btm_cback( tBTM_DEV_STATUS status ); +void bta_sys_hw_error(tBTA_SYS_HW_MSG *p_sys_hw_msg); +void bta_sys_hw_api_enable( tBTA_SYS_HW_MSG *p_sys_hw_msg ); +void bta_sys_hw_api_disable(tBTA_SYS_HW_MSG *p_sys_hw_msg); +void bta_sys_hw_evt_enabled(tBTA_SYS_HW_MSG *p_sys_hw_msg); +void bta_sys_hw_evt_disabled(tBTA_SYS_HW_MSG *p_sys_hw_msg); +void bta_sys_hw_evt_stack_enabled(tBTA_SYS_HW_MSG *p_sys_hw_msg); + +BOOLEAN bta_sys_sm_execute(BT_HDR *p_msg); + +#endif /* BTA_SYS_INT_H */ diff --git a/components/bt/bluedroid/bta/sys/utl.c b/components/bt/bluedroid/bta/sys/utl.c new file mode 100755 index 0000000000..0649924925 --- /dev/null +++ b/components/bt/bluedroid/bta/sys/utl.c @@ -0,0 +1,299 @@ +/****************************************************************************** + * + * Copyright (C) 2003-2012 Broadcom Corporation + * + * 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 utility functions. + * + ******************************************************************************/ +#include +#include "utl.h" +#include "gki.h" +#include "btm_api.h" + +/******************************************************************************* +** +** Function utl_str2int +** +** Description This utility function converts a character string to an +** integer. Acceptable values in string are 0-9. If invalid +** string or string value too large, -1 is returned. Leading +** spaces are skipped. +** +** +** Returns Integer value or -1 on error. +** +*******************************************************************************/ +INT16 utl_str2int(const char *p_s) +{ + INT32 val = 0; + + for (;*p_s == ' ' && *p_s != 0; p_s++); + + if (*p_s == 0) return -1; + + for (;;) + { + if ((*p_s < '0') || (*p_s > '9')) return -1; + + val += (INT32) (*p_s++ - '0'); + + if (val > 32767) return -1; + + if (*p_s == 0) + { + return (INT16) val; + } + else + { + val *= 10; + } + } +} + +/******************************************************************************* +** +** Function utl_strucmp +** +** Description This utility function compares two strings in uppercase. +** String p_s must be uppercase. String p_t is converted to +** uppercase if lowercase. If p_s ends first, the substring +** match is counted as a match. +** +** +** Returns 0 if strings match, nonzero otherwise. +** +*******************************************************************************/ +int utl_strucmp(const char *p_s, const char *p_t) +{ + char c; + + while (*p_s && *p_t) + { + c = *p_t++; + if (c >= 'a' && c <= 'z') + { + c -= 0x20; + } + if (*p_s++ != c) + { + return -1; + } + } + /* if p_t hit null first, no match */ + if (*p_t == 0 && *p_s != 0) + { + return 1; + } + /* else p_s hit null first, count as match */ + else + { + return 0; + } +} + +/******************************************************************************* +** +** Function utl_itoa +** +** Description This utility function converts a UINT16 to a string. The +** string is NULL-terminated. The length of the string is +** returned; +** +** +** Returns Length of string. +** +*******************************************************************************/ +UINT8 utl_itoa(UINT16 i, char *p_s) +{ + UINT16 j, k; + char *p = p_s; + BOOLEAN fill = FALSE; + + if (i == 0) + { + /* take care of zero case */ + *p++ = '0'; + } + else + { + for(j = 10000; j > 0; j /= 10) + { + k = i / j; + i %= j; + if (k > 0 || fill) + { + *p++ = k + '0'; + fill = TRUE; + } + } + } + *p = 0; + return (UINT8) (p - p_s); +} + +/******************************************************************************* +** +** Function utl_freebuf +** +** Description This function calls GKI_freebuf to free the buffer passed +** in, if buffer pointer is not NULL, and also initializes +** buffer pointer to NULL. +** +** +** Returns Nothing. +** +*******************************************************************************/ +void utl_freebuf(void **p) +{ + if (*p != NULL) + { + GKI_freebuf(*p); + *p = NULL; + } +} + + +/******************************************************************************* +** +** Function utl_set_device_class +** +** Description This function updates the local Device Class. +** +** Parameters: +** p_cod - Pointer to the device class to set to +** +** cmd - the fields of the device class to update. +** BTA_UTL_SET_COD_MAJOR_MINOR, - overwrite major, minor class +** BTA_UTL_SET_COD_SERVICE_CLASS - set the bits in the input +** BTA_UTL_CLR_COD_SERVICE_CLASS - clear the bits in the input +** BTA_UTL_SET_COD_ALL - overwrite major, minor, set the bits in service class +** BTA_UTL_INIT_COD - overwrite major, minor, and service class +** +** Returns TRUE if successful, Otherwise FALSE +** +*******************************************************************************/ +BOOLEAN utl_set_device_class(tBTA_UTL_COD *p_cod, UINT8 cmd) +{ + UINT8 *dev; + UINT16 service; + UINT8 minor, major; + DEV_CLASS dev_class; + + dev = BTM_ReadDeviceClass(); + BTM_COD_SERVICE_CLASS( service, dev ); + BTM_COD_MINOR_CLASS(minor, dev ); + BTM_COD_MAJOR_CLASS(major, dev ); + + switch(cmd) + { + case BTA_UTL_SET_COD_MAJOR_MINOR: + minor = p_cod->minor & BTM_COD_MINOR_CLASS_MASK; + major = p_cod->major & BTM_COD_MAJOR_CLASS_MASK; + break; + + case BTA_UTL_SET_COD_SERVICE_CLASS: + /* clear out the bits that is not SERVICE_CLASS bits */ + p_cod->service &= BTM_COD_SERVICE_CLASS_MASK; + service = service | p_cod->service; + break; + + case BTA_UTL_CLR_COD_SERVICE_CLASS: + p_cod->service &= BTM_COD_SERVICE_CLASS_MASK; + service = service & (~p_cod->service); + break; + + case BTA_UTL_SET_COD_ALL: + minor = p_cod->minor & BTM_COD_MINOR_CLASS_MASK; + major = p_cod->major & BTM_COD_MAJOR_CLASS_MASK; + p_cod->service &= BTM_COD_SERVICE_CLASS_MASK; + service = service | p_cod->service; + break; + + case BTA_UTL_INIT_COD: + minor = p_cod->minor & BTM_COD_MINOR_CLASS_MASK; + major = p_cod->major & BTM_COD_MAJOR_CLASS_MASK; + service = p_cod->service & BTM_COD_SERVICE_CLASS_MASK; + break; + + default: + return FALSE; + } + + /* convert the fields into the device class type */ + FIELDS_TO_COD(dev_class, minor, major, service); + + if (BTM_SetDeviceClass(dev_class) == BTM_SUCCESS) + return TRUE; + + return FALSE; +} + +/******************************************************************************* +** +** Function utl_isintstr +** +** Description This utility function checks if the given string is an +** integer string or not +** +** +** Returns TRUE if successful, Otherwise FALSE +** +*******************************************************************************/ +BOOLEAN utl_isintstr(const char *p_s) +{ + UINT16 i = 0; + + for(i=0; p_s[i] != 0; i++) + { + if(((p_s[i] < '0') || (p_s[i] > '9')) && (p_s[i] != ';')) + return FALSE; + } + + return TRUE; +} + +/******************************************************************************* +** +** Function utl_isdialstr +** +** Description This utility function checks if the given string contains +** only dial digits or not +** +** +** Returns TRUE if successful, Otherwise FALSE +** +*******************************************************************************/ +BOOLEAN utl_isdialstr(const char *p_s) +{ + UINT16 i = 0; + + for(i=0; p_s[i] != 0; i++) + { + if(!(((p_s[i] >= '0') && (p_s[i] <= '9')) + || (p_s[i] == '*') || (p_s[i] == '+') || (p_s[i] == '#') || (p_s[i] == ';') + || ((p_s[i] >= 'A') && (p_s[i] <= 'C')) + || ((p_s[i] == 'p') || (p_s[i] == 'P') + || (p_s[i] == 'w') || (p_s[i] == 'W')))) + return FALSE; + } + + return TRUE; +} + + diff --git a/components/bt/bluedroid/btcore/bdaddr.c b/components/bt/bluedroid/btcore/bdaddr.c new file mode 100755 index 0000000000..0f0c68ef93 --- /dev/null +++ b/components/bt/bluedroid/btcore/bdaddr.c @@ -0,0 +1,107 @@ +/****************************************************************************** + * + * Copyright (C) 2014 Google, Inc. + * + * 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. + * + ******************************************************************************/ + +#include +#include +#include "bt_trace.h" +#include "bdaddr.h" + +static inline bool ets_isxdigit(char c) { + if ((c >= '0') && (c <= '9')) + return true; + if ((c >= 'a') && (c <= 'f')) + return true; + return ((c >= 'A') && (c <= 'F')); +} + +bool bdaddr_is_empty(const bt_bdaddr_t *addr) { + assert(addr != NULL); + + uint8_t zero[sizeof(bt_bdaddr_t)] = { 0 }; + return memcmp(addr, &zero, sizeof(bt_bdaddr_t)) == 0; +} + +bool bdaddr_equals(const bt_bdaddr_t *first, const bt_bdaddr_t *second) { + assert(first != NULL); + assert(second != NULL); + + return memcmp(first, second, sizeof(bt_bdaddr_t)) == 0; +} + +bt_bdaddr_t *bdaddr_copy(bt_bdaddr_t *dest, const bt_bdaddr_t *src) { + assert(dest != NULL); + assert(src != NULL); + + return (bt_bdaddr_t *)memcpy(dest, src, sizeof(bt_bdaddr_t)); +} + +const char *bdaddr_to_string(const bt_bdaddr_t *addr, char *string, size_t size) { + assert(addr != NULL); + assert(string != NULL); + + if (size < 18) + return NULL; + + const uint8_t *ptr = addr->address; + sprintf(string, "%02x:%02x:%02x:%02x:%02x:%02x", + ptr[0], ptr[1], ptr[2], + ptr[3], ptr[4], ptr[5]); + return string; +} + +bool string_is_bdaddr(const char *string) { + assert(string != NULL); + + size_t len = strlen(string); + if (len != 17) + return false; + + for (size_t i = 0; i < len; ++i) { + // Every 3rd char must be ':'. + if (((i + 1) % 3) == 0 && string[i] != ':') + return false; + + // All other chars must be a hex digit. + if (((i + 1) % 3) != 0 && !ets_isxdigit(string[i])) + return false; + } + return true; +} + +bool string_to_bdaddr(const char *string, bt_bdaddr_t *addr) { + assert(string != NULL); + assert(addr != NULL); + + bt_bdaddr_t new_addr; + uint8_t *ptr = new_addr.address; + bool ret = sscanf(string, "%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx", + &ptr[0], &ptr[1], &ptr[2], &ptr[3], &ptr[4], &ptr[5]) == 6; + + if (ret) + memcpy(addr, &new_addr, sizeof(bt_bdaddr_t)); + + return ret; +} + +hash_index_t hash_function_bdaddr(const void *key) { + hash_index_t hash = 5381; + const char *bytes = (const char *)key; + for (size_t i = 0; i < sizeof(bt_bdaddr_t); ++i) + hash = ((hash << 5) + hash) + bytes[i]; + return hash; +} diff --git a/components/bt/bluedroid/btcore/include/bdaddr.h b/components/bt/bluedroid/btcore/include/bdaddr.h new file mode 100755 index 0000000000..87acad2e00 --- /dev/null +++ b/components/bt/bluedroid/btcore/include/bdaddr.h @@ -0,0 +1,63 @@ +/****************************************************************************** + * + * Copyright (C) 2014 Google, Inc. + * + * 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. + * + ******************************************************************************/ + +#ifndef _BDADDR_H_ +#define _BDADDR_H_ + +#include +#include + +#include "bt_defs.h" +#include "hash_map.h" + +// Note: the string representation of a bdaddr is expected to have the format +// xx:xx:xx:xx:xx:xx +// where each 'x' is a hex digit. The API presented in this header will accept +// both uppercase and lowercase digits but will only ever produce lowercase +// digits. + +// Returns true if |addr| is the empty address (00:00:00:00:00:00). +// |addr| may not be NULL. +bool bdaddr_is_empty(const bt_bdaddr_t *addr); + +// Returns true if |first| and |second| refer to the same address. Neither +// may be NULL. +bool bdaddr_equals(const bt_bdaddr_t *first, const bt_bdaddr_t *second); + +// Returns destination bdaddr |dest| after copying |src| to |dest|. +// |dest| and |src| must not be NULL. +bt_bdaddr_t *bdaddr_copy(bt_bdaddr_t *dest, const bt_bdaddr_t *src); + +// Makes a string representation of |addr| and places it into |string|. |size| +// refers to the size of |string|'s buffer and must be >= 18. On success, this +// function returns |string|, otherwise it returns NULL. Neither |addr| nor |string| +// may be NULL. +const char *bdaddr_to_string(const bt_bdaddr_t *addr, char *string, size_t size); + +// Returns true if |string| represents a Bluetooth address. |string| may not be NULL. +bool string_is_bdaddr(const char *string); + +// Converts |string| to bt_bdaddr_t and places it in |addr|. If |string| does not +// represent a Bluetooth address, |addr| is not modified and this function returns +// false. Otherwise, it returns true. Neither |string| nor |addr| may be NULL. +bool string_to_bdaddr(const char *string, bt_bdaddr_t *addr); + +// A hash function tailored for bdaddrs. +hash_index_t hash_function_bdaddr(const void *key); + +#endif diff --git a/components/bt/bluedroid/btcore/include/device_features.h b/components/bt/bluedroid/btcore/include/device_features.h new file mode 100755 index 0000000000..e501a0b578 --- /dev/null +++ b/components/bt/bluedroid/btcore/include/device_features.h @@ -0,0 +1,29 @@ +/****************************************************************************** + * + * Copyright (C) 2014 Google, Inc. + * + * 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. + * + ******************************************************************************/ +#ifndef _DEVICE_FEATURES_H_ +#define _DEVICE_FEATURES_H_ + +#include + +// Represents a page of device feature enabled/disabled bits returned +// by the local controller. See the bluetooth spec for bit indexes. +typedef struct { + uint8_t as_array[8]; +} bt_device_features_t; + +#endif /*_DEVICE_FEATURES_H_*/ diff --git a/components/bt/bluedroid/btcore/include/event_mask.h b/components/bt/bluedroid/btcore/include/event_mask.h new file mode 100755 index 0000000000..6226676cbd --- /dev/null +++ b/components/bt/bluedroid/btcore/include/event_mask.h @@ -0,0 +1,30 @@ +/****************************************************************************** + * + * Copyright (C) 2014 Google, Inc. + * + * 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. + * + ******************************************************************************/ +#ifndef _EVENT_MASK_H_ +#define _EVENT_MASK_H_ + +#include + +// Represents a mask which can be used to tell the controller which +// HCI events the stack wishes to be informed about. See the bluetooth +// spec for more information on what each bit means. +typedef struct { + uint8_t as_array[8]; +} bt_event_mask_t; + +#endif /*_EVENT_MASK_H_*/ diff --git a/components/bt/bluedroid/btcore/include/version.h b/components/bt/bluedroid/btcore/include/version.h new file mode 100755 index 0000000000..9d92a8f218 --- /dev/null +++ b/components/bt/bluedroid/btcore/include/version.h @@ -0,0 +1,31 @@ +/****************************************************************************** + * + * Copyright (C) 2014 Google, Inc. + * + * 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. + * + ******************************************************************************/ +#ifndef _VERSION_H_ +#define _VERSION_H_ + +#include + +typedef struct { + uint8_t hci_version; + uint16_t hci_revision; + uint8_t lmp_version; + uint16_t manufacturer; + uint16_t lmp_subversion; +} bt_version_t; + +#endif /*_VERSION_H_*/ diff --git a/components/bt/bluedroid/btif/bta_dm_co.c b/components/bt/bluedroid/btif/bta_dm_co.c new file mode 100755 index 0000000000..a31f5b71a2 --- /dev/null +++ b/components/bt/bluedroid/btif/bta_dm_co.c @@ -0,0 +1,464 @@ +/****************************************************************************** + * + * Copyright (C) 2009-2012 Broadcom Corporation + * + * 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. + * + ******************************************************************************/ +#include +#include + +#include "bta_api.h" +#include "bta_sys.h" +#include "bta_dm_co.h" +#include "bta_dm_ci.h" +#if (defined(BTIF_INCLUDED) && BTIF_INCLUDED == TRUE) +#include "bt_utils.h" +#if (BTM_OOB_INCLUDED == TRUE) +#include "btif_dm.h" +#endif +#endif /* #if (defined(BTIF_INCLUDED) && BTIF_INCLUDED == TRUE) */ +#if (defined BLE_INCLUDED && BLE_INCLUDED == TRUE) +#include "bte_appl.h" + +tBTE_APPL_CFG bte_appl_cfg = +{ +#if SMP_INCLUDED == TRUE + BTA_LE_AUTH_REQ_SC_MITM_BOND, // Authentication requirements +#else + BTM_AUTH_SPGB_YES, // Authentication requirements +#endif + BTM_LOCAL_IO_CAPS_BLE, + BTM_BLE_INITIATOR_KEY_SIZE, + BTM_BLE_RESPONDER_KEY_SIZE, + BTM_BLE_MAX_KEY_SIZE +}; +#endif + +/******************************************************************************* +** +** Function bta_dm_co_get_compress_memory +** +** Description This callout function is executed by DM to get memory for compression + +** Parameters id - BTA SYS ID +** memory_p - memory return by callout +** memory_size - memory size +** +** Returns TRUE for success, FALSE for fail. +** +*******************************************************************************/ +BOOLEAN bta_dm_co_get_compress_memory(tBTA_SYS_ID id, UINT8 **memory_p, UINT32 *memory_size) +{ + UNUSED(id); + UNUSED(memory_p); + UNUSED(memory_size); + return TRUE; +} + +/******************************************************************************* +** +** Function bta_dm_co_io_req +** +** Description This callout function is executed by DM to get IO capabilities +** of the local device for the Simple Pairing process +** +** Parameters bd_addr - The peer device +** *p_io_cap - The local Input/Output capabilities +** *p_oob_data - TRUE, if OOB data is available for the peer device. +** *p_auth_req - TRUE, if MITM protection is required. +** +** Returns void. +** +*******************************************************************************/ +void bta_dm_co_io_req(BD_ADDR bd_addr, tBTA_IO_CAP *p_io_cap, tBTA_OOB_DATA *p_oob_data, + tBTA_AUTH_REQ *p_auth_req, BOOLEAN is_orig) +{ + UNUSED(bd_addr); +#if (defined(BTIF_INCLUDED) && BTIF_INCLUDED == TRUE) +#if (BTM_OOB_INCLUDED == TRUE) + btif_dm_set_oob_for_io_req(p_oob_data); +#endif + btif_dm_proc_io_req(bd_addr, p_io_cap, p_oob_data, p_auth_req, is_orig); +#else + LOG_ERROR("bta_dm_co_io_req: func not ported\n"); +#endif /* #if (defined(BTIF_INCLUDED) && BTIF_INCLUDED == TRUE) */ + BTIF_TRACE_DEBUG("bta_dm_co_io_req *p_oob_data = %d", *p_oob_data); + BTIF_TRACE_DEBUG("bta_dm_co_io_req *p_io_cap = %d", *p_io_cap); + BTIF_TRACE_DEBUG("bta_dm_co_io_req *p_auth_req = %d", *p_auth_req); + BTIF_TRACE_DEBUG("bta_dm_co_io_req is_orig = %d", is_orig); +} + +/******************************************************************************* +** +** Function bta_dm_co_io_rsp +** +** Description This callout function is executed by DM to report IO capabilities +** of the peer device for the Simple Pairing process +** +** Parameters bd_addr - The peer device +** io_cap - The remote Input/Output capabilities +** oob_data - TRUE, if OOB data is available for the peer device. +** auth_req - TRUE, if MITM protection is required. +** +** Returns void. +** +*******************************************************************************/ +void bta_dm_co_io_rsp(BD_ADDR bd_addr, tBTA_IO_CAP io_cap, + tBTA_OOB_DATA oob_data, tBTA_AUTH_REQ auth_req) +{ +#if (defined(BTIF_INCLUDED) && BTIF_INCLUDED == TRUE) + btif_dm_proc_io_rsp(bd_addr, io_cap, oob_data, auth_req); +#else + LOG_ERROR("bta_dm_co_io_rsp: func not ported\n"); +#endif /* #if (defined(BTIF_INCLUDED) && BTIF_INCLUDED == TRUE) */ +} + +/******************************************************************************* +** +** Function bta_dm_co_lk_upgrade +** +** Description This callout function is executed by DM to check if the +** platform wants allow link key upgrade +** +** Parameters bd_addr - The peer device +** *p_upgrade - TRUE, if link key upgrade is desired. +** +** Returns void. +** +*******************************************************************************/ +void bta_dm_co_lk_upgrade(BD_ADDR bd_addr, BOOLEAN *p_upgrade ) +{ + UNUSED(bd_addr); + UNUSED(p_upgrade); +} + +#if (BTM_OOB_INCLUDED == TRUE) +/******************************************************************************* +** +** Function bta_dm_co_loc_oob +** +** Description This callout function is executed by DM to report the OOB +** data of the local device for the Simple Pairing process +** +** Parameters valid - TRUE, if the local OOB data is retrieved from LM +** c - Simple Pairing Hash C +** r - Simple Pairing Randomnizer R +** +** Returns void. +** +*******************************************************************************/ +void bta_dm_co_loc_oob(BOOLEAN valid, BT_OCTET16 c, BT_OCTET16 r) +{ +#if (defined(BTIF_INCLUDED) && BTIF_INCLUDED == TRUE) + BTIF_TRACE_DEBUG("bta_dm_co_loc_oob, valid = %d", valid); +#ifdef BTIF_DM_OOB_TEST + btif_dm_proc_loc_oob(valid, c, r); +#endif +#else + LOG_ERROR("bta_dm_co_loc_oob: func not ported\n"); +#endif /* #if (defined(BTIF_INCLUDED) && BTIF_INCLUDED == TRUE) */ +} + +/******************************************************************************* +** +** Function bta_dm_co_rmt_oob +** +** Description This callout function is executed by DM to request the OOB +** data for the remote device for the Simple Pairing process +** Need to call bta_dm_ci_rmt_oob() in response +** +** Parameters bd_addr - The peer device +** +** Returns void. +** +*******************************************************************************/ +void bta_dm_co_rmt_oob(BD_ADDR bd_addr) +{ + BT_OCTET16 p_c; + BT_OCTET16 p_r; + BOOLEAN result = FALSE; + +#ifdef BTIF_DM_OOB_TEST +#if (defined(BTIF_INCLUDED) && BTIF_INCLUDED == TRUE) + result = btif_dm_proc_rmt_oob(bd_addr, p_c, p_r); +#else + LOG_ERROR("bta_dm_rmt_oob: func not ported\n"); +#endif /* #if (defined(BTIF_INCLUDED) && BTIF_INCLUDED == TRUE) */ +#endif + + BTIF_TRACE_DEBUG("bta_dm_co_rmt_oob: result=%d",result); + bta_dm_ci_rmt_oob(result, bd_addr, p_c, p_r); +} + +#endif /* BTM_OOB_INCLUDED */ + + +// REMOVE FOR BLUEDROID ? + +#if (BTM_SCO_HCI_INCLUDED == TRUE ) && (BTM_SCO_INCLUDED == TRUE) +#if (defined(BTIF_INCLUDED) && BTIF_INCLUDED == TRUE) +/******************************************************************************* +** +** Function btui_sco_codec_callback +** +** Description Callback for btui codec. +** +** +** Returns void +** +*******************************************************************************/ +static void btui_sco_codec_callback(UINT16 event, UINT16 sco_handle) +{ + bta_dm_sco_ci_data_ready(event, sco_handle); +} +/******************************************************************************* +** +** Function bta_dm_sco_co_init +** +** Description This function can be used by the phone to initialize audio +** codec or for other initialization purposes before SCO connection +** is opened. +** +** +** Returns tBTA_DM_SCO_ROUTE_TYPE: SCO routing configuration type. +** +*******************************************************************************/ +tBTA_DM_SCO_ROUTE_TYPE bta_dm_sco_co_init(UINT32 rx_bw, UINT32 tx_bw, + tBTA_CODEC_INFO * p_codec_type, UINT8 app_id) +{ + tBTM_SCO_ROUTE_TYPE route = BTA_DM_SCO_ROUTE_PCM; + + BTIF_TRACE_DEBUG("bta_dm_sco_co_init"); + + /* set up SCO routing configuration if SCO over HCI app ID is used and run time + configuration is set to SCO over HCI */ + /* HS invoke this call-out */ + if ( +#if (BTA_HS_INCLUDED == TRUE ) && (BTA_HS_INCLUDED == TRUE) + (app_id == BTUI_DM_SCO_4_HS_APP_ID && btui_cfg.hs_sco_over_hci) || +#endif + /* AG invoke this call-out */ + (app_id != BTUI_DM_SCO_4_HS_APP_ID && btui_cfg.ag_sco_over_hci )) + { + route = btui_cb.sco_hci = BTA_DM_SCO_ROUTE_HCI; + } + /* no codec is is used for the SCO data */ + if (p_codec_type->codec_type == BTA_SCO_CODEC_PCM && route == BTA_DM_SCO_ROUTE_HCI) + { + /* initialize SCO codec */ + if (!btui_sco_codec_init(rx_bw, tx_bw)) + { + BTIF_TRACE_ERROR("codec initialization exception!"); + } + } + + return route; +} + + + +/******************************************************************************* +** +** Function bta_dm_sco_co_open +** +** Description This function is executed when a SCO connection is open. +** +** +** Returns void +** +*******************************************************************************/ +void bta_dm_sco_co_open(UINT16 handle, UINT8 pkt_size, UINT16 event) +{ + tBTUI_SCO_CODEC_CFG cfg; + + if (btui_cb.sco_hci) + { + BTIF_TRACE_DEBUG("bta_dm_sco_co_open handle:%d pkt_size:%d", handle, pkt_size); + /* use dedicated SCO buffer pool for SCO TX data */ + cfg.pool_id = HCI_SCO_POOL_ID; + cfg.p_cback = btui_sco_codec_callback; + cfg.pkt_size = pkt_size; + cfg.cb_event = event; + /* open and start the codec */ + btui_sco_codec_open(&cfg); + btui_sco_codec_start(handle); + } +} + +/******************************************************************************* +** +** Function bta_dm_sco_co_close +** +** Description This function is called when a SCO connection is closed +** +** +** Returns void +** +*******************************************************************************/ +void bta_dm_sco_co_close(void) +{ + if (btui_cb.sco_hci) + { + BTIF_TRACE_DEBUG("bta_dm_sco_co_close close codec"); + /* close sco codec */ + btui_sco_codec_close(); + + btui_cb.sco_hci = FALSE; + } +} + +/******************************************************************************* +** +** Function bta_dm_sco_co_in_data +** +** Description This function is called to send incoming SCO data to application. +** +** Returns void +** +*******************************************************************************/ +void bta_dm_sco_co_in_data(BT_HDR *p_buf) +{ + if (btui_cfg.sco_use_mic) + btui_sco_codec_inqdata (p_buf); + else + GKI_freebuf(p_buf); +} + +/******************************************************************************* +** +** Function bta_dm_sco_co_out_data +** +** Description This function is called to send SCO data over HCI. +** +** Returns void +** +*******************************************************************************/ +void bta_dm_sco_co_out_data(BT_HDR **p_buf) +{ + btui_sco_codec_readbuf(p_buf); +} + +#endif /* #if (defined(BTIF_INCLUDED) && BTIF_INCLUDED == TRUE) */ +#endif /* #if (BTM_SCO_HCI_INCLUDED == TRUE ) && (BTM_SCO_INCLUDED == TRUE)*/ + + +#if (defined BLE_INCLUDED && BLE_INCLUDED == TRUE) +/******************************************************************************* +** +** Function bta_dm_co_le_io_key_req +** +** Description This callout function is executed by DM to get BLE key information +** before SMP pairing gets going. +** +** Parameters bd_addr - The peer device +** *p_max_key_size - max key size local device supported. +** *p_init_key - initiator keys. +** *p_resp_key - responder keys. +** +** Returns void. +** +*******************************************************************************/ +void bta_dm_co_le_io_key_req(BD_ADDR bd_addr, UINT8 *p_max_key_size, + tBTA_LE_KEY_TYPE *p_init_key, + tBTA_LE_KEY_TYPE *p_resp_key ) +{ + UNUSED(bd_addr); + BTIF_TRACE_ERROR("##################################"); + BTIF_TRACE_ERROR("bta_dm_co_le_io_key_req: only setting max size to 16"); + BTIF_TRACE_ERROR("##################################"); + *p_max_key_size = 16; + *p_init_key = *p_resp_key = + (BTA_LE_KEY_PENC|BTA_LE_KEY_PID|BTA_LE_KEY_PCSRK|BTA_LE_KEY_LENC|BTA_LE_KEY_LID|BTA_LE_KEY_LCSRK); +} + + +/******************************************************************************* +** +** Function bta_dm_co_ble_local_key_reload +** +** Description This callout function is to load the local BLE keys if available +** on the device. +** +** Parameters none +** +** Returns void. +** +*******************************************************************************/ +void bta_dm_co_ble_load_local_keys(tBTA_DM_BLE_LOCAL_KEY_MASK *p_key_mask, BT_OCTET16 er, + tBTA_BLE_LOCAL_ID_KEYS *p_id_keys) +{ +#if (defined(BTIF_INCLUDED) && BTIF_INCLUDED == TRUE) + BTIF_TRACE_DEBUG("##################################"); + BTIF_TRACE_DEBUG("bta_dm_co_ble_load_local_keys: Load local keys if any are persisted"); + BTIF_TRACE_DEBUG("##################################"); + btif_dm_get_ble_local_keys( p_key_mask, er, p_id_keys); +#else + LOG_ERROR("bta_dm_co_ble_load_local_keys: func not ported\n"); +#endif +} + +/******************************************************************************* +** +** Function bta_dm_co_ble_io_req +** +** Description This callout function is executed by DM to get BLE IO capabilities +** before SMP pairing gets going. +** +** Parameters bd_addr - The peer device +** *p_io_cap - The local Input/Output capabilities +** *p_oob_data - TRUE, if OOB data is available for the peer device. +** *p_auth_req - Auth request setting (Bonding and MITM required or not) +** *p_max_key_size - max key size local device supported. +** *p_init_key - initiator keys. +** *p_resp_key - responder keys. +** +** Returns void. +** +*******************************************************************************/ +void bta_dm_co_ble_io_req(BD_ADDR bd_addr, tBTA_IO_CAP *p_io_cap, + tBTA_OOB_DATA *p_oob_data, + tBTA_LE_AUTH_REQ *p_auth_req, + UINT8 *p_max_key_size, + tBTA_LE_KEY_TYPE *p_init_key, + tBTA_LE_KEY_TYPE *p_resp_key ) +{ + UNUSED(bd_addr); + /* if OOB is not supported, this call-out function does not need to do anything + * otherwise, look for the OOB data associated with the address and set *p_oob_data accordingly + * If the answer can not be obtained right away, + * set *p_oob_data to BTA_OOB_UNKNOWN and call bta_dm_ci_io_req() when the answer is available */ + + *p_oob_data = FALSE; + + /* *p_auth_req by default is FALSE for devices with NoInputNoOutput; TRUE for other devices. */ + + if (bte_appl_cfg.ble_auth_req) + *p_auth_req = bte_appl_cfg.ble_auth_req | (bte_appl_cfg.ble_auth_req & 0x04) | ((*p_auth_req) & 0x04); + + if (bte_appl_cfg.ble_io_cap <=4) + *p_io_cap = bte_appl_cfg.ble_io_cap; + + if (bte_appl_cfg.ble_init_key <= BTM_BLE_INITIATOR_KEY_SIZE) + *p_init_key = bte_appl_cfg.ble_init_key; + + if (bte_appl_cfg.ble_resp_key <= BTM_BLE_RESPONDER_KEY_SIZE) + *p_resp_key = bte_appl_cfg.ble_resp_key; + + if (bte_appl_cfg.ble_max_key_size > 7 && bte_appl_cfg.ble_max_key_size <= 16) + *p_max_key_size = bte_appl_cfg.ble_max_key_size; +} + + +#endif + diff --git a/components/bt/bluedroid/btif/bta_gattc_co.c b/components/bt/bluedroid/btif/bta_gattc_co.c new file mode 100755 index 0000000000..3d0acd9e73 --- /dev/null +++ b/components/bt/bluedroid/btif/bta_gattc_co.c @@ -0,0 +1,217 @@ +/****************************************************************************** + * + * Copyright (C) 2009-2013 Broadcom Corporation + * + * 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. + * + ******************************************************************************/ +#ifdef BT_SUPPORT_NVM +#include +#include +#endif /* BT_SUPPORT_NVM */ + +#include "gki.h" +#include "bta_gattc_co.h" +#include "bta_gattc_ci.h" +// #include "btif_util.h" +#include "btm_int.h" + +#if( defined BLE_INCLUDED ) && (BLE_INCLUDED == TRUE) +#if( defined BTA_GATT_INCLUDED ) && (BTA_GATT_INCLUDED == TRUE) + +#define GATT_CACHE_PREFIX "/data/misc/bluedroid/gatt_cache_" + +#ifdef BT_SUPPORT_NVM +static FILE* sCacheFD = 0; + +static void getFilename(char *buffer, BD_ADDR bda) +{ + sprintf(buffer, "%s%02x%02x%02x%02x%02x%02x", GATT_CACHE_PREFIX + , bda[0], bda[1], bda[2], bda[3], bda[4], bda[5]); +} + +static void cacheClose() +{ + if (sCacheFD != 0) + { + fclose(sCacheFD); + sCacheFD = 0; + } +} + +static bool cacheOpen(BD_ADDR bda, bool to_save) +{ + char fname[255] = {0}; + getFilename(fname, bda); + + cacheClose(); + sCacheFD = fopen(fname, to_save ? "w" : "r"); + + return (sCacheFD != 0); +} + +static void cacheReset(BD_ADDR bda) +{ + char fname[255] = {0}; + getFilename(fname, bda); + unlink(fname); +} + +#endif /* BT_SUPPORT_NVM */ +/***************************************************************************** +** Function Declarations +*****************************************************************************/ + +/******************************************************************************* +** +** Function bta_gattc_co_cache_open +** +** Description This callout function is executed by GATTC when a GATT server +** cache is ready to be sent. +** +** Parameter server_bda: server bd address of this cache belongs to +** evt: call in event to be passed in when cache open is done. +** conn_id: connection ID of this cache operation attach to. +** to_save: open cache to save or to load. +** +** Returns void. +** +*******************************************************************************/ +void bta_gattc_co_cache_open(BD_ADDR server_bda, UINT16 evt, UINT16 conn_id, BOOLEAN to_save) +{ +#ifdef BT_SUPPORT_NVM + /* open NV cache and send call in */ + tBTA_GATT_STATUS status = BTA_GATT_OK; + if (!btm_sec_is_a_bonded_dev(server_bda) || !cacheOpen(server_bda, to_save)) + status = BTA_GATT_ERROR; + + BTIF_TRACE_DEBUG("%s() - status=%d", __FUNCTION__, status); + bta_gattc_ci_cache_open(server_bda, evt, status, conn_id); +#else + bta_gattc_ci_cache_open(server_bda, evt, BTA_GATT_ERROR, conn_id); +#endif /* BT_SUPPORT_NVM */ +} + +/******************************************************************************* +** +** Function bta_gattc_co_cache_load +** +** Description This callout function is executed by GATT when server cache +** is required to load. +** +** Parameter server_bda: server bd address of this cache belongs to +** evt: call in event to be passed in when cache save is done. +** num_attr: number of attribute to be save. +** attr_index: starting attribute index of the save operation. +** conn_id: connection ID of this cache operation attach to. +** Returns +** +*******************************************************************************/ +void bta_gattc_co_cache_load(BD_ADDR server_bda, UINT16 evt, UINT16 start_index, UINT16 conn_id) +{ + UINT16 num_attr = 0; + tBTA_GATTC_NV_ATTR attr[BTA_GATTC_NV_LOAD_MAX]; + tBTA_GATT_STATUS status = BTA_GATT_ERROR; +#ifdef BT_SUPPORT_NVM + if (sCacheFD && (0 == fseek(sCacheFD, start_index * sizeof(tBTA_GATTC_NV_ATTR), SEEK_SET))) + { + num_attr = fread(attr, sizeof(tBTA_GATTC_NV_ATTR), BTA_GATTC_NV_LOAD_MAX, sCacheFD); + status = (num_attr < BTA_GATTC_NV_LOAD_MAX ? BTA_GATT_OK : BTA_GATT_MORE); + } + BTIF_TRACE_DEBUG("%s() - sCacheFD=%p, start_index=%d, read=%d, status=%d", + __FUNCTION__, sCacheFD, start_index, num_attr, status); +#endif /* BT_SUPPORT_NVM */ + + bta_gattc_ci_cache_load(server_bda, evt, num_attr, attr, status, conn_id); +} + +/******************************************************************************* +** +** Function bta_gattc_co_cache_save +** +** Description This callout function is executed by GATT when a server cache +** is available to save. +** +** Parameter server_bda: server bd address of this cache belongs to +** evt: call in event to be passed in when cache save is done. +** num_attr: number of attribute to be save. +** p_attr: pointer to the list of attributes to save. +** attr_index: starting attribute index of the save operation. +** conn_id: connection ID of this cache operation attach to. +** Returns +** +*******************************************************************************/ +void bta_gattc_co_cache_save (BD_ADDR server_bda, UINT16 evt, UINT16 num_attr, + tBTA_GATTC_NV_ATTR *p_attr_list, UINT16 attr_index, UINT16 conn_id) +{ + tBTA_GATT_STATUS status = BTA_GATT_OK; + UNUSED(attr_index); +#ifdef BT_SUPPORT_NVM + if (sCacheFD != 0) + { + int num = fwrite(p_attr_list, sizeof(tBTA_GATTC_NV_ATTR), num_attr, sCacheFD); + BTIF_TRACE_DEBUG("%s() wrote %d", __FUNCTION__, num); + } +#endif /* BT_SUPPORT_NVM */ + bta_gattc_ci_cache_save(server_bda, evt, status, conn_id); +} + +/******************************************************************************* +** +** Function bta_gattc_co_cache_close +** +** Description This callout function is executed by GATTC when a GATT server +** cache is written completely. +** +** Parameter server_bda: server bd address of this cache belongs to +** conn_id: connection ID of this cache operation attach to. +** +** Returns void. +** +*******************************************************************************/ +void bta_gattc_co_cache_close(BD_ADDR server_bda, UINT16 conn_id) +{ + UNUSED(server_bda); + UNUSED(conn_id); +#ifdef BT_SUPPORT_NVM + cacheClose(); +#endif /* BT_SUPPORT_NVM */ + /* close NV when server cache is done saving or loading, + does not need to do anything for now on Insight */ + + BTIF_TRACE_DEBUG("%s()", __FUNCTION__); +} + +/******************************************************************************* +** +** Function bta_gattc_co_cache_reset +** +** Description This callout function is executed by GATTC to reset cache in +** application +** +** Parameter server_bda: server bd address of this cache belongs to +** +** Returns void. +** +*******************************************************************************/ +void bta_gattc_co_cache_reset(BD_ADDR server_bda) +{ + BTIF_TRACE_DEBUG("%s()", __FUNCTION__); +#ifdef BT_SUPPORT_NVM + cacheReset(server_bda); +#endif /* BT_SUPPORT_NVM */ +} + +#endif /* #if( defined BLE_INCLUDED ) && (BLE_INCLUDED == TRUE) */ +#endif /* #if( defined BTA_GATT_INCLUDED ) && (BTA_GATT_INCLUDED == TRUE) */ + diff --git a/components/bt/bluedroid/btif/bta_gatts_co.c b/components/bt/bluedroid/btif/bta_gatts_co.c new file mode 100755 index 0000000000..160c1ed473 --- /dev/null +++ b/components/bt/bluedroid/btif/bta_gatts_co.c @@ -0,0 +1,170 @@ +/****************************************************************************** + * + * Copyright (C) 2009-2013 Broadcom Corporation + * + * 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. + * + ******************************************************************************/ + +#include "bta_api.h" + +#if( defined BLE_INCLUDED ) && (BLE_INCLUDED == TRUE) +#if( defined BTA_GATT_INCLUDED ) && (BTA_GATT_INCLUDED == TRUE) + +#include +#include +#include "gki.h" +#include "bta_gatts_co.h" +// #include "btif_util.h" + +#if (defined(BTIF_INCLUDED) && BTIF_INCLUDED == TRUE) +/***************************************************************************** +** Local type definitions +*****************************************************************************/ + +#define BTIF_GATTS_MAX_SRV_CHG_CLT_SIZE 50 + +typedef struct +{ + BOOLEAN enable; + UINT8 num_clients; + tBTA_GATTS_SRV_CHG srv_chg[BTIF_GATTS_MAX_SRV_CHG_CLT_SIZE]; +} __attribute__((packed)) btif_gatts_srv_chg_cb_t; + +/***************************************************************************** +** Static variables +*****************************************************************************/ + +static btif_gatts_srv_chg_cb_t btif_gatts_srv_chg_cb; + +/***************************************************************************** +** Static functions +*****************************************************************************/ + +static void btif_gatts_check_init(void) +{ + btif_gatts_srv_chg_cb_t *p_cb= &btif_gatts_srv_chg_cb; + + if (!p_cb->enable) + { + memset(p_cb, 0, sizeof(btif_gatts_srv_chg_cb_t)); + p_cb->enable = TRUE; + } +} + +/***************************************************************************** +** Externally called functions +*****************************************************************************/ + +void btif_gatts_add_bonded_dev_from_nv(BD_ADDR bda) +{ + btif_gatts_srv_chg_cb_t *p_cb= &btif_gatts_srv_chg_cb; + BOOLEAN found = FALSE; + UINT8 i; + + btif_gatts_check_init(); + + for (i=0; i != p_cb->num_clients; ++i) + { + if (!memcmp(p_cb->srv_chg[i].bda, bda, sizeof(BD_ADDR))) + { + found = TRUE; + break; + } + } + + if (!found) + { + if (p_cb->num_clients < BTIF_GATTS_MAX_SRV_CHG_CLT_SIZE) + { + bdcpy(p_cb->srv_chg[p_cb->num_clients].bda, bda); + p_cb->srv_chg[p_cb->num_clients].srv_changed = FALSE; + p_cb->num_clients++; + } + } +} + +#endif /* #if (defined(BTIF_INCLUDED) && BTIF_INCLUDED == TRUE) */ +/***************************************************************************** +** Call-out functions +*****************************************************************************/ + +/******************************************************************************* +** +** Function bta_gatts_co_update_handle_range +** +** Description This callout function is executed by GATTS when a GATT server +** handle range ios to be added or removed. +** +** Parameter is_add: true is to add a handle range; otherwise is to delete. +** p_hndl_range: handle range. +** +** Returns void. +** +*******************************************************************************/ +void bta_gatts_co_update_handle_range(BOOLEAN is_add, tBTA_GATTS_HNDL_RANGE *p_hndl_range) +{ + UNUSED(is_add); + UNUSED(p_hndl_range); +} + +/******************************************************************************* +** +** Function bta_gatts_co_srv_chg +** +** Description This call-out is to read/write/remove service change related +** informaiton. The request consists of the cmd and p_req and the +** response is returned in p_rsp +** +** Parameter cmd - request command +** p_req - request paramters +** p_rsp - response data for the request +** +** Returns TRUE - if the request is processed successfully and +** the response is returned in p_rsp. +** FASLE - if the request can not be processed +** +*******************************************************************************/ +BOOLEAN bta_gatts_co_srv_chg(tBTA_GATTS_SRV_CHG_CMD cmd, + tBTA_GATTS_SRV_CHG_REQ *p_req, + tBTA_GATTS_SRV_CHG_RSP *p_rsp) +{ + UNUSED(cmd); + UNUSED(p_req); + UNUSED(p_rsp); + + return FALSE; +} + +/******************************************************************************* +** +** Function bta_gatts_co_load_handle_range +** +** Description This callout function is executed by GATTS when a GATT server +** handle range is requested to be loaded from NV. +** +** Parameter +** +** Returns void. +** +*******************************************************************************/ +BOOLEAN bta_gatts_co_load_handle_range(UINT8 index, + tBTA_GATTS_HNDL_RANGE *p_handle_range) +{ + UNUSED(index); + UNUSED(p_handle_range); + + return FALSE; +} +#endif +#endif diff --git a/components/bt/bluedroid/device/controller.c b/components/bt/bluedroid/device/controller.c new file mode 100755 index 0000000000..4721f4057d --- /dev/null +++ b/components/bt/bluedroid/device/controller.c @@ -0,0 +1,589 @@ +/****************************************************************************** + * + * Copyright (C) 2014 Google, Inc. + * + * 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. + * + ******************************************************************************/ +#include +#include "bt_trace.h" +#include "bdaddr.h" +#include "bt_types.h" +#include "controller.h" +#include "event_mask.h" +#include "hcimsgs.h" +#include "hci_layer.h" +#include "hci_packet_factory.h" +#include "hci_packet_parser.h" +#include "btm_ble_api.h" +#include "version.h" + +//#include "bluedroid_test.h" /*FOr Test Case*/ +const bt_event_mask_t BLE_EVENT_MASK = { "\x00\x00\x00\x00\x00\x00\x06\x7f" }; + +#if (BLE_INCLUDED) +const bt_event_mask_t CLASSIC_EVENT_MASK = { HCI_DUMO_EVENT_MASK_EXT }; +#else +const bt_event_mask_t CLASSIC_EVENT_MASK = { HCI_LISBON_EVENT_MASK_EXT }; +#endif + +// TODO(zachoverflow): factor out into common module +const uint8_t SCO_HOST_BUFFER_SIZE = 0xff; + +#define HCI_SUPPORTED_COMMANDS_ARRAY_SIZE 64 +#define MAX_FEATURES_CLASSIC_PAGE_COUNT 3 +#define BLE_SUPPORTED_STATES_SIZE 8 +#define BLE_SUPPORTED_FEATURES_SIZE 8 + +static const hci_t *hci; +static const hci_packet_factory_t *packet_factory; +static const hci_packet_parser_t *packet_parser; + +static bt_bdaddr_t address; +static bt_version_t bt_version; + +static uint8_t supported_commands[HCI_SUPPORTED_COMMANDS_ARRAY_SIZE]; +static bt_device_features_t features_classic[MAX_FEATURES_CLASSIC_PAGE_COUNT]; +static uint8_t last_features_classic_page_index; + +static uint16_t acl_data_size_classic; +static uint16_t acl_data_size_ble; +static uint16_t acl_buffer_count_classic; +static uint8_t acl_buffer_count_ble; + +static uint8_t ble_white_list_size; +static uint8_t ble_resolving_list_max_size; +static uint8_t ble_supported_states[BLE_SUPPORTED_STATES_SIZE]; +static bt_device_features_t features_ble; +static uint16_t ble_suggested_default_data_length; + +static bool readable; +static bool ble_supported; +static bool simple_pairing_supported; +static bool secure_connections_supported; + +devctl_reset_callback reset_cb; +static uint8_t page_number = 0; +static void devctl_hdl_cmd_complete(BT_HDR *response, void *context) { + BT_HDR *command = NULL; + command_opcode_t opcode; + uint8_t *stream = response->data + response->offset; + + STREAM_SKIP_UINT16(stream); //skip event_code and total length field + STREAM_SKIP_UINT8(stream); //skip command_credits field + STREAM_TO_UINT16(opcode, stream); + + switch (opcode) { + case HCI_RESET: + packet_parser->parse_generic_command_complete(response); + command = packet_factory->make_read_buffer_size(); + break; + case HCI_READ_BUFFER_SIZE: + packet_parser->parse_read_buffer_size_response( + response, &acl_data_size_classic, &acl_buffer_count_classic); + command = packet_factory->make_host_buffer_size( + L2CAP_MTU_SIZE, SCO_HOST_BUFFER_SIZE, L2CAP_HOST_FC_ACL_BUFS, 10); + break; + case HCI_HOST_BUFFER_SIZE: + packet_parser->parse_generic_command_complete(response); + command = packet_factory->make_read_local_version_info(); + break; + case HCI_READ_LOCAL_VERSION_INFO: + packet_parser->parse_read_local_version_info_response(response, &bt_version); + command = packet_factory->make_read_bd_addr(); + break; + case HCI_READ_BD_ADDR: + packet_parser->parse_read_bd_addr_response(response, &address); + command = packet_factory->make_read_local_supported_commands(); + break; + case HCI_READ_LOCAL_SUPPORTED_CMDS: + packet_parser->parse_read_local_supported_commands_response( + response, supported_commands, HCI_SUPPORTED_COMMANDS_ARRAY_SIZE); + page_number = 0; + command = packet_factory->make_read_local_extended_features(page_number); + break; + case HCI_READ_LOCAL_EXT_FEATURES: + if (response) { + packet_parser->parse_read_local_extended_features_response( + response, &page_number,&last_features_classic_page_index, + features_classic, MAX_FEATURES_CLASSIC_PAGE_COUNT); + response = NULL; + page_number++; + } + if (1 == page_number) { + simple_pairing_supported = HCI_SIMPLE_PAIRING_SUPPORTED(features_classic[0].as_array); + if (simple_pairing_supported) { + command = packet_factory->make_write_simple_pairing_mode(HCI_SP_MODE_ENABLED); + break; + } + // BLOCK_BEGIN +#if (BLE_INCLUDED == TRUE) + if (HCI_LE_SPT_SUPPORTED(features_classic[0].as_array)) { + uint8_t simultaneous_le_host = HCI_SIMUL_LE_BREDR_SUPPORTED(features_classic[0].as_array) ? BTM_BLE_SIMULTANEOUS_HOST : 0; + command = packet_factory->make_ble_write_host_support(BTM_BLE_HOST_SUPPORT, simultaneous_le_host); + break; + } +#endif + } + + if (page_number <= last_features_classic_page_index && + page_number < MAX_FEATURES_CLASSIC_PAGE_COUNT) { + command = packet_factory->make_read_local_extended_features(page_number); + break; + } else { +#if (SC_MODE_INCLUDED == TRUE) + secure_connections_supported = HCI_SC_CTRLR_SUPPORTED(features_classic[2].as_array); + if (secure_connections_supported) { + command = packet_factory->make_write_secure_connections_host_support(HCI_SC_MODE_ENABLED); + break; + } +#endif +#if (BLE_INCLUDED == TRUE) + ble_supported = last_features_classic_page_index >= 1 && HCI_LE_HOST_SUPPORTED(features_classic[1].as_array); + if (ble_supported) { + // Request the ble white list size next + command = packet_factory->make_ble_read_white_list_size(); + break; + } +#endif + if (simple_pairing_supported) { + command = packet_factory->make_set_event_mask(&CLASSIC_EVENT_MASK); + break; + } + } + // BLOCK_END + + case HCI_WRITE_SIMPLE_PAIRING_MODE: + if (response) { + packet_parser->parse_generic_command_complete(response); + response = NULL; + } + // BLOCK_BEGIN +#if (BLE_INCLUDED == TRUE) + if (HCI_LE_SPT_SUPPORTED(features_classic[0].as_array)) { + uint8_t simultaneous_le_host = HCI_SIMUL_LE_BREDR_SUPPORTED(features_classic[0].as_array) ? BTM_BLE_SIMULTANEOUS_HOST : 0; + command = packet_factory->make_ble_write_host_support(BTM_BLE_HOST_SUPPORT, simultaneous_le_host); + break; + } +#endif + if (page_number <= last_features_classic_page_index && + page_number < MAX_FEATURES_CLASSIC_PAGE_COUNT) { + command = packet_factory->make_read_local_extended_features(page_number); + break; + } else { +#if (SC_MODE_INCLUDED == TRUE) + secure_connections_supported = HCI_SC_CTRLR_SUPPORTED(features_classic[2].as_array); + if (secure_connections_supported) { + command = packet_factory->make_write_secure_connections_host_support(HCI_SC_MODE_ENABLED); + break; + } +#endif +#if (BLE_INCLUDED == TRUE) + ble_supported = last_features_classic_page_index >= 1 && HCI_LE_HOST_SUPPORTED(features_classic[1].as_array); + if (ble_supported) { + // Request the ble white list size next + command = packet_factory->make_ble_read_white_list_size(); + break; + } +#endif + if (simple_pairing_supported) { + command = packet_factory->make_set_event_mask(&CLASSIC_EVENT_MASK); + break; + } + } + +#if (SC_MODE_INCLUDED == TRUE) + case HCI_WRITE_SECURE_CONNS_SUPPORT: + if (response) { + packet_parser->parse_generic_command_complete(response); + response = NULL; + } +#if (BLE_INCLUDED == TRUE) + ble_supported = last_features_classic_page_index >= 1 && HCI_LE_HOST_SUPPORTED(features_classic[1].as_array); + if (ble_supported) { + // Request the ble white list size next + command = packet_factory->make_ble_read_white_list_size(); + break; + } +#endif /* (BLE_INCLUDED == TRUE) */ + if (simple_pairing_supported) { + command = packet_factory->make_set_event_mask(&CLASSIC_EVENT_MASK); + break; + } +#endif /* (SC_MODE_INCLUDED == TRUE) */ + +#if (BLE_INCLUDED == TRUE) + case HCI_WRITE_LE_HOST_SUPPORT: + if (response) { + packet_parser->parse_generic_command_complete(response); + response = NULL; + } + if (page_number <= last_features_classic_page_index && + page_number < MAX_FEATURES_CLASSIC_PAGE_COUNT) { + command = packet_factory->make_read_local_extended_features(page_number); + break; + } else { +#if (SC_MODE_INCLUDED == TRUE) + secure_connections_supported = HCI_SC_CTRLR_SUPPORTED(features_classic[2].as_array); + if (secure_connections_supported) { + command = packet_factory->make_write_secure_connections_host_support(HCI_SC_MODE_ENABLED); + break; + } +#endif + ble_supported = last_features_classic_page_index >= 1 && HCI_LE_HOST_SUPPORTED(features_classic[1].as_array); + if (ble_supported) { + // Request the ble white list size next + command = packet_factory->make_ble_read_white_list_size(); + break; + } + if (simple_pairing_supported) { + command = packet_factory->make_set_event_mask(&CLASSIC_EVENT_MASK); + break; + } + } + case HCI_BLE_READ_WHITE_LIST_SIZE: + if (response) { + packet_parser->parse_ble_read_white_list_size_response(response, &ble_white_list_size); + response = NULL; + } + if (ble_supported) { + // Request the ble buffer size next + command = packet_factory->make_ble_read_buffer_size(); + break; + } + // Fall Through if no next command generated + case HCI_BLE_READ_BUFFER_SIZE: + if (response) { + packet_parser->parse_ble_read_buffer_size_response( + response, &acl_data_size_ble, &acl_buffer_count_ble); + response = NULL; + } + // Response of 0 indicates ble has the same buffer size as classic + if (acl_data_size_ble == 0) + acl_data_size_ble = acl_data_size_classic; + if (ble_supported) { + // Request the ble supported states next + command = packet_factory->make_ble_read_supported_states(); + break; + } + // Fall Through if no next command generated + case HCI_BLE_READ_SUPPORTED_STATES: + if (response) { + packet_parser->parse_ble_read_supported_states_response( + response, ble_supported_states, sizeof(ble_supported_states)); + response = NULL; + } + + if (ble_supported) { + // Request the ble supported features next + command = packet_factory->make_ble_read_local_supported_features(); + break; + } + // Fall Through if no next command generated + case HCI_BLE_READ_LOCAL_SPT_FEAT: + if (response) { + packet_parser->parse_ble_read_local_supported_features_response( + response, &features_ble); + response = NULL; + } + + if (ble_supported && + HCI_LE_ENHANCED_PRIVACY_SUPPORTED(features_ble.as_array)) { + command = packet_factory->make_ble_read_resolving_list_size(); + break; + } + case HCI_BLE_READ_RESOLVING_LIST_SIZE: + if (response) { + packet_parser->parse_ble_read_resolving_list_size_response( + response, &ble_resolving_list_max_size); + response = NULL; + } + + if (ble_supported && + HCI_LE_DATA_LEN_EXT_SUPPORTED(features_ble.as_array)) { + command = packet_factory->make_ble_read_suggested_default_data_length(); + break; + } + case HCI_BLE_READ_DEFAULT_DATA_LENGTH: + if (response) { + packet_parser->parse_ble_read_suggested_default_data_length_response( + response, &ble_suggested_default_data_length); + response = NULL; + } + + if (ble_supported) { + // Set the ble event mask next + command = packet_factory->make_ble_set_event_mask(&BLE_EVENT_MASK); + break; + } + case HCI_BLE_SET_EVENT_MASK: + if (response) { + packet_parser->parse_generic_command_complete(response); + response = NULL; + } + if (simple_pairing_supported) { + command = packet_factory->make_set_event_mask(&CLASSIC_EVENT_MASK); + break; + } +#endif + case HCI_SET_EVENT_MASK: + if (response) { + packet_parser->parse_generic_command_complete(response); + response = command = NULL; + } + //At this point, Reset Thread should be completed well. + readable = true; + page_number = 0; + if (reset_cb) + reset_cb(); + + break; + default: + LOG_ERROR("%s: No available opcode matched.", __func__); + break; + } + + if (command) + hci->transmit_command(command, devctl_hdl_cmd_complete, NULL, NULL); +} + +// Interface functions +static void devctl_reset(devctl_reset_callback reset_callback) { + reset_cb = reset_callback; + BT_HDR *command = packet_factory->make_read_buffer_size(); + //BT_HDR *command = packet_factory->make_reset(); + LOG_ERROR("Device Control Send Device Read Buffer Size Command\n"); + page_number = 0; + if (command) + hci->transmit_command(command, devctl_hdl_cmd_complete, NULL, NULL); +} + +static void devctl_shutdown(void) { + reset_cb = NULL; + readable = false; +} + +static bool get_is_ready(void) { + return readable; +} + +static const bt_bdaddr_t *get_address(void) { + assert(readable); + return &address; +} + +static const bt_version_t *get_bt_version(void) { + assert(readable); + return &bt_version; +} + +// TODO(zachoverflow): hide inside, move decoder inside too +static const bt_device_features_t *get_features_classic(int index) { + assert(readable); + assert(index < MAX_FEATURES_CLASSIC_PAGE_COUNT); + return &features_classic[index]; +} + +static uint8_t get_last_features_classic_index(void) { + assert(readable); + return last_features_classic_page_index; +} + +static const bt_device_features_t *get_features_ble(void) { + assert(readable); + assert(ble_supported); + return &features_ble; +} + +static const uint8_t *get_ble_supported_states(void) { + assert(readable); + assert(ble_supported); + return ble_supported_states; +} + +static bool supports_simple_pairing(void) { + assert(readable); + return simple_pairing_supported; +} + +static bool supports_secure_connections(void) { + assert(readable); + return secure_connections_supported; +} + +static bool supports_simultaneous_le_bredr(void) { + assert(readable); + return HCI_SIMUL_LE_BREDR_SUPPORTED(features_classic[0].as_array); +} + +static bool supports_reading_remote_extended_features(void) { + assert(readable); + return HCI_READ_REMOTE_EXT_FEATURES_SUPPORTED(supported_commands); +} + +static bool supports_interlaced_inquiry_scan(void) { + assert(readable); + return HCI_LMP_INTERLACED_INQ_SCAN_SUPPORTED(features_classic[0].as_array); +} + +static bool supports_rssi_with_inquiry_results(void) { + assert(readable); + return HCI_LMP_INQ_RSSI_SUPPORTED(features_classic[0].as_array); +} + +static bool supports_extended_inquiry_response(void) { + assert(readable); + return HCI_EXT_INQ_RSP_SUPPORTED(features_classic[0].as_array); +} + +static bool supports_master_slave_role_switch(void) { + assert(readable); + return HCI_SWITCH_SUPPORTED(features_classic[0].as_array); +} + +static bool supports_ble(void) { + assert(readable); + return ble_supported; +} + +static bool supports_ble_privacy(void) { + assert(readable); + assert(ble_supported); + return HCI_LE_ENHANCED_PRIVACY_SUPPORTED(features_ble.as_array); +} + +static bool supports_ble_packet_extension(void) { + assert(readable); + assert(ble_supported); + return HCI_LE_DATA_LEN_EXT_SUPPORTED(features_ble.as_array); +} + +static bool supports_ble_connection_parameters_request(void) { + assert(readable); + assert(ble_supported); + return HCI_LE_CONN_PARAM_REQ_SUPPORTED(features_ble.as_array); +} + +static uint16_t get_acl_data_size_classic(void) { + assert(readable); + return acl_data_size_classic; +} + +static uint16_t get_acl_data_size_ble(void) { + assert(readable); + assert(ble_supported); + return acl_data_size_ble; +} + +static uint16_t get_acl_packet_size_classic(void) { + assert(readable); + return acl_data_size_classic + HCI_DATA_PREAMBLE_SIZE; +} + +static uint16_t get_acl_packet_size_ble(void) { + assert(readable); + return acl_data_size_ble + HCI_DATA_PREAMBLE_SIZE; +} + +static uint16_t get_ble_suggested_default_data_length(void) { + assert(readable); + assert(ble_supported); + return ble_suggested_default_data_length; +} + +static uint16_t get_acl_buffer_count_classic(void) { + assert(readable); + return acl_buffer_count_classic; +} + +static uint8_t get_acl_buffer_count_ble(void) { + assert(readable); + assert(ble_supported); + return acl_buffer_count_ble; +} + +static uint8_t get_ble_white_list_size(void) { + assert(readable); + assert(ble_supported); + return ble_white_list_size; +} + +static uint8_t get_ble_resolving_list_max_size(void) { + assert(readable); + assert(ble_supported); + return ble_resolving_list_max_size; +} + +static void set_ble_resolving_list_max_size(int resolving_list_max_size) { + assert(readable); + assert(ble_supported); + ble_resolving_list_max_size = resolving_list_max_size; +} + +static const controller_t interface = { + devctl_reset, + devctl_shutdown, + get_is_ready, + + get_address, + get_bt_version, + + get_features_classic, + get_last_features_classic_index, + + get_features_ble, + get_ble_supported_states, + + supports_simple_pairing, + supports_secure_connections, + supports_simultaneous_le_bredr, + supports_reading_remote_extended_features, + supports_interlaced_inquiry_scan, + supports_rssi_with_inquiry_results, + supports_extended_inquiry_response, + supports_master_slave_role_switch, + + supports_ble, + supports_ble_packet_extension, + supports_ble_connection_parameters_request, + supports_ble_privacy, + + get_acl_data_size_classic, + get_acl_data_size_ble, + + get_acl_packet_size_classic, + get_acl_packet_size_ble, + get_ble_suggested_default_data_length, + + get_acl_buffer_count_classic, + get_acl_buffer_count_ble, + + get_ble_white_list_size, + + get_ble_resolving_list_max_size, + set_ble_resolving_list_max_size +}; + +const controller_t *controller_get_interface() { + static bool loaded = false; + if (!loaded) { + loaded = true; + + hci = hci_layer_get_interface(); + packet_factory = hci_packet_factory_get_interface(); + packet_parser = hci_packet_parser_get_interface(); + } + + return &interface; +} + diff --git a/components/bt/bluedroid/device/include/controller.h b/components/bt/bluedroid/device/include/controller.h new file mode 100755 index 0000000000..939853ab08 --- /dev/null +++ b/components/bt/bluedroid/device/include/controller.h @@ -0,0 +1,87 @@ +/****************************************************************************** + * + * Copyright (C) 2014 Google, Inc. + * + * 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. + * + ******************************************************************************/ + +#ifndef _CONTROLLER_H_ +#define _CONTROLLER_H_ + +#include +#include + +#include "bt_target.h" +#include "bdaddr.h" +#include "device_features.h" +#include "hci_layer.h" +#include "hci_packet_factory.h" +#include "hci_packet_parser.h" + +typedef void (*devctl_reset_callback)(void); + +typedef struct controller_t { + void (*devctl_reset)(devctl_reset_callback reset_callback); + void (*devctl_shutdown)(void); + bool (*get_is_ready)(void); + + const bt_bdaddr_t *(*get_address)(void); + const bt_version_t *(*get_bt_version)(void); + + const bt_device_features_t *(*get_features_classic)(int index); + + uint8_t (*get_last_features_classic_index)(void); + + const bt_device_features_t *(*get_features_ble)(void); + const uint8_t *(*get_ble_supported_states)(void); + + bool (*supports_simple_pairing)(void); + bool (*supports_secure_connections)(void); + bool (*supports_simultaneous_le_bredr)(void); + bool (*supports_reading_remote_extended_features)(void); + bool (*supports_interlaced_inquiry_scan)(void); + bool (*supports_rssi_with_inquiry_results)(void); + bool (*supports_extended_inquiry_response)(void); + bool (*supports_master_slave_role_switch)(void); + + bool (*supports_ble)(void); + bool (*supports_ble_packet_extension)(void); + bool (*supports_ble_connection_parameters_request)(void); + bool (*supports_ble_privacy)(void); + + // Get the cached acl data sizes for the controller. + uint16_t (*get_acl_data_size_classic)(void); + uint16_t (*get_acl_data_size_ble)(void); + + // Get the cached acl packet sizes for the controller. + // This is a convenience function for the respective + // acl data size + size of the acl header. + uint16_t (*get_acl_packet_size_classic)(void); + uint16_t (*get_acl_packet_size_ble)(void); + + uint16_t (*get_ble_default_data_packet_length)(void); + + // Get the number of acl packets the controller can buffer. + uint16_t (*get_acl_buffer_count_classic)(void); + uint8_t (*get_acl_buffer_count_ble)(void); + + uint8_t (*get_ble_white_list_size)(void); + + uint8_t (*get_ble_resolving_list_max_size)(void); + void (*set_ble_resolving_list_max_size)(int resolving_list_max_size); +} controller_t; + +const controller_t *controller_get_interface(); + +#endif /*_CONTROLLER_H_*/ diff --git a/components/bt/bluedroid/device/include/interop.h b/components/bt/bluedroid/device/include/interop.h new file mode 100755 index 0000000000..76ba93ad54 --- /dev/null +++ b/components/bt/bluedroid/device/include/interop.h @@ -0,0 +1,44 @@ +/****************************************************************************** + * + * Copyright (C) 2015 Google, Inc. + * + * 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. + * + ******************************************************************************/ + +#ifndef _INTEROP_H_ +#define _INTEROP_H_ + +#include +#include "bt_defs.h" + +typedef enum { + // Disable secure connections + // This is for pre BT 4.1/2 devices that do not handle secure mode + // very well. + INTEROP_DISABLE_LE_SECURE_CONNECTIONS, + + // Some devices have proven problematic during the pairing process, often + // requiring multiple retries to complete pairing. To avoid degrading the user + // experience for those devices, automatically re-try pairing if page + // timeouts are received during pairing. + INTEROP_AUTO_RETRY_PAIRING +} interop_feature_t; + +// Check if a given |addr| matches a known interoperability workaround as identified +// by the |interop_feature_t| enum. This API is used for simple address based lookups +// where more information is not available. No look-ups or random address resolution +// is performed on |addr|. +bool interop_match(const interop_feature_t feature, const bt_bdaddr_t *addr); + +#endif /*_INTEROP_H_*/ diff --git a/components/bt/bluedroid/device/include/interop_database.h b/components/bt/bluedroid/device/include/interop_database.h new file mode 100755 index 0000000000..1619c7ba20 --- /dev/null +++ b/components/bt/bluedroid/device/include/interop_database.h @@ -0,0 +1,50 @@ +/****************************************************************************** + * + * Copyright (C) 2015 Google, Inc. + * + * 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. + * + ******************************************************************************/ + +#ifndef _INTEROP_DATABASE_H_ +#define _INTEROP_DATABASE_H_ + +#include "interop.h" + +typedef struct { + bt_bdaddr_t addr; + uint8_t len; + interop_feature_t feature; +} interop_entry_t; + +static const interop_entry_t interop_database[] = { + // Nexus Remote (Spike) + // Note: May affect other Asus brand devices + {{0x08, 0x62, 0x66, 0,0,0}, 3, INTEROP_DISABLE_LE_SECURE_CONNECTIONS}, + {{0x38, 0x2c, 0x4a, 0xc9, 0,0}, 4, INTEROP_DISABLE_LE_SECURE_CONNECTIONS}, + {{0x38, 0x2c, 0x4a, 0xe6, 0,0}, 4, INTEROP_DISABLE_LE_SECURE_CONNECTIONS}, + {{0x54, 0xa0, 0x50, 0xd9, 0,0}, 4, INTEROP_DISABLE_LE_SECURE_CONNECTIONS}, + {{0xac, 0x9e, 0x17, 0,0,0}, 3, INTEROP_DISABLE_LE_SECURE_CONNECTIONS}, + {{0xf0, 0x79, 0x59, 0,0,0}, 3, INTEROP_DISABLE_LE_SECURE_CONNECTIONS}, + + // Motorola Key Link + {{0x1c, 0x96, 0x5a, 0,0,0}, 3, INTEROP_DISABLE_LE_SECURE_CONNECTIONS}, + + // Flic smart button + {{0x80, 0xe4, 0xda, 0x70, 0,0}, 4, INTEROP_DISABLE_LE_SECURE_CONNECTIONS}, + + // BMW car kits (Harman/Becker) + {{0x9c, 0xdf, 0x03, 0,0,0}, 3, INTEROP_AUTO_RETRY_PAIRING} +}; + +#endif /*_INTEROP_DATABASE_H_*/ diff --git a/components/bt/bluedroid/device/interop.c b/components/bt/bluedroid/device/interop.c new file mode 100755 index 0000000000..ff3c9704fc --- /dev/null +++ b/components/bt/bluedroid/device/interop.c @@ -0,0 +1,56 @@ +/****************************************************************************** + * + * Copyright (C) 2015 Google, Inc. + * + * 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. + * + ******************************************************************************/ +/* +#define LOG_TAG "bt_device_interop" +*/ +#include // For memcmp +#include "bt_trace.h" +#include "bdaddr.h" +#include "interop.h" +#include "interop_database.h" + +#define CASE_RETURN_STR(const) case const: return #const; + +static const char* interop_feature_string(const interop_feature_t feature) { + switch (feature) { + CASE_RETURN_STR(INTEROP_DISABLE_LE_SECURE_CONNECTIONS) + CASE_RETURN_STR(INTEROP_AUTO_RETRY_PAIRING) + } + + return "UNKNOWN"; +} + +// Interface functions + +bool interop_match(const interop_feature_t feature, const bt_bdaddr_t *addr) { + assert(addr); + + const size_t db_size = sizeof(interop_database) / sizeof(interop_entry_t); + + for (size_t i = 0; i != db_size; ++i) { + if (feature == interop_database[i].feature && + memcmp(addr, &interop_database[i].addr, interop_database[i].len) == 0) { + char bdstr[20] = {0}; + LOG_WARN("%s() Device %s is a match for interop workaround %s", __func__, + bdaddr_to_string(addr, bdstr, sizeof(bdstr)), interop_feature_string(feature)); + return true; + } + } + + return false; +} diff --git a/components/bt/bluedroid/gki/gki_buffer.c b/components/bt/bluedroid/gki/gki_buffer.c new file mode 100755 index 0000000000..29ac5b43e7 --- /dev/null +++ b/components/bt/bluedroid/gki/gki_buffer.c @@ -0,0 +1,563 @@ +/****************************************************************************** + * + * Copyright (C) 1999-2012 Broadcom Corporation + * + * 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. + * + ******************************************************************************/ + +#include "bt_trace.h" +#include "allocator.h" +#include "gki_int.h" + +#define ALIGN_POOL(pl_size) ( (((pl_size) + 3) / sizeof(UINT32)) * sizeof(UINT32)) +#define BUFFER_HDR_SIZE (sizeof(BUFFER_HDR_T)) /* Offset past header */ +#define BUFFER_PADDING_SIZE (sizeof(BUFFER_HDR_T) + sizeof(UINT32)) /* Header + Magic Number */ +#define MAGIC_NO 0xDDBADDBA + +#define BUF_STATUS_FREE 0 +#define BUF_STATUS_UNLINKED 1 +#define BUF_STATUS_QUEUED 2 + +/******************************************************************************* +** +** Function gki_init_free_queue +** +** Description Internal function called at startup to initialize a free +** queue. It is called once for each free queue. +** +** Returns void +** +*******************************************************************************/ +static void gki_init_free_queue (UINT8 id, UINT16 size, UINT16 total, void *p_mem) +{ + UINT16 i; + UINT16 act_size; + BUFFER_HDR_T *hdr; + BUFFER_HDR_T *hdr1 = NULL; + UINT32 *magic; + INT32 tempsize = size; + tGKI_COM_CB *p_cb = &gki_cb.com; + + /* Ensure an even number of longwords */ + tempsize = (INT32)ALIGN_POOL(size); + act_size = (UINT16)(tempsize + BUFFER_PADDING_SIZE); + + /* Remember pool start and end addresses */ + if(p_mem) + { + p_cb->pool_start[id] = (UINT8 *)p_mem; + p_cb->pool_end[id] = (UINT8 *)p_mem + (act_size * total); + } + + p_cb->pool_size[id] = act_size; + + p_cb->freeq[id].size = (UINT16) tempsize; + p_cb->freeq[id].total = total; + p_cb->freeq[id].cur_cnt = 0; + p_cb->freeq[id].max_cnt = 0; + + /* Initialize index table */ + if(p_mem) + { + hdr = (BUFFER_HDR_T *)p_mem; + p_cb->freeq[id]._p_first = hdr; + for (i = 0; i < total; i++) + { + hdr->q_id = id; + hdr->status = BUF_STATUS_FREE; + magic = (UINT32 *)((UINT8 *)hdr + BUFFER_HDR_SIZE + tempsize); + *magic = MAGIC_NO; + hdr1 = hdr; + hdr = (BUFFER_HDR_T *)((UINT8 *)hdr + act_size); + hdr1->p_next = hdr; + } + hdr1->p_next = NULL; + p_cb->freeq[id]._p_last = hdr1; + } +} + +void gki_buffer_cleanup(void) +{ + UINT8 i; + tGKI_COM_CB *p_cb = &gki_cb.com; + + for (i=0; i < GKI_NUM_FIXED_BUF_POOLS; i++) + { + if ( 0 < p_cb->freeq[i].max_cnt ) + { + osi_free(p_cb->pool_start[i]); + + p_cb->freeq[i].cur_cnt = 0; + p_cb->freeq[i].max_cnt = 0; + p_cb->freeq[i]._p_first = NULL; + p_cb->freeq[i]._p_last = NULL; + + p_cb->pool_start[i] = NULL; + p_cb->pool_end[i] = NULL; + p_cb->pool_size[i] = 0; + } + } +} + +/******************************************************************************* +** +** Function gki_buffer_init +** +** Description Called once internally by GKI at startup to initialize all +** buffers and free buffer pools. +** +** Returns void +** +*******************************************************************************/ +void gki_buffer_init(void) +{ + static const struct { + uint16_t size; + uint16_t count; + } buffer_info[GKI_NUM_FIXED_BUF_POOLS] = { + { GKI_BUF0_SIZE, GKI_BUF0_MAX }, + { GKI_BUF1_SIZE, GKI_BUF1_MAX }, + { GKI_BUF2_SIZE, GKI_BUF2_MAX }, + { GKI_BUF3_SIZE, GKI_BUF3_MAX }, + { GKI_BUF4_SIZE, GKI_BUF4_MAX }, + { GKI_BUF5_SIZE, GKI_BUF5_MAX }, + { GKI_BUF6_SIZE, GKI_BUF6_MAX }, + { GKI_BUF7_SIZE, GKI_BUF7_MAX }, + { GKI_BUF8_SIZE, GKI_BUF8_MAX }, + { GKI_BUF9_SIZE, GKI_BUF9_MAX }, + }; + + tGKI_COM_CB *p_cb = &gki_cb.com; + + for (int i = 0; i < GKI_NUM_TOTAL_BUF_POOLS; i++) + { + p_cb->pool_start[i] = NULL; + p_cb->pool_end[i] = NULL; + p_cb->pool_size[i] = 0; + + p_cb->freeq[i]._p_first = 0; + p_cb->freeq[i]._p_last = 0; + p_cb->freeq[i].size = 0; + p_cb->freeq[i].total = 0; + p_cb->freeq[i].cur_cnt = 0; + p_cb->freeq[i].max_cnt = 0; + } + + /* Use default from target.h */ + p_cb->pool_access_mask = GKI_DEF_BUFPOOL_PERM_MASK; + + for (int i = 0; i < GKI_NUM_FIXED_BUF_POOLS; ++i) { + gki_init_free_queue(i, buffer_info[i].size, buffer_info[i].count, NULL); + } +} + +/******************************************************************************* +** +** Function GKI_init_q +** +** Description Called by an application to initialize a buffer queue. +** +** Returns void +** +*******************************************************************************/ +void GKI_init_q (BUFFER_Q *p_q) +{ + p_q->_p_first = p_q->_p_last = NULL; + p_q->_count = 0; +} + +/******************************************************************************* +** +** Function GKI_getbuf +** +** Description Called by an application to get a free buffer which +** is of size greater or equal to the requested size. +** +** Note: This routine only takes buffers from public pools. +** It will not use any buffers from pools +** marked GKI_RESTRICTED_POOL. +** +** Parameters size - (input) number of bytes needed. +** +** Returns A pointer to the buffer, or NULL if none available +** +*******************************************************************************/ +void *GKI_getbuf (UINT16 size) +{ + BUFFER_HDR_T *header = osi_malloc(size + BUFFER_HDR_SIZE); + header->status = BUF_STATUS_UNLINKED; + header->p_next = NULL; + header->Type = 0; + header->size = size; + + return header + 1; +} + + +/******************************************************************************* +** +** Function GKI_getpoolbuf +** +** Description Called by an application to get a free buffer from +** a specific buffer pool. +** +** Note: If there are no more buffers available from the pool, +** the public buffers are searched for an available buffer. +** +** Parameters pool_id - (input) pool ID to get a buffer out of. +** +** Returns A pointer to the buffer, or NULL if none available +** +*******************************************************************************/ +void *GKI_getpoolbuf (UINT8 pool_id) +{ + return GKI_getbuf(gki_cb.com.pool_size[pool_id]); +} + +/******************************************************************************* +** +** Function GKI_freebuf +** +** Description Called by an application to return a buffer to the free pool. +** +** Parameters p_buf - (input) address of the beginning of a buffer. +** +** Returns void +** +*******************************************************************************/ +void GKI_freebuf (void *p_buf) +{ + osi_free((BUFFER_HDR_T *)p_buf - 1); +} + + +/******************************************************************************* +** +** Function GKI_get_buf_size +** +** Description Called by an application to get the size of a buffer. +** +** Parameters p_buf - (input) address of the beginning of a buffer. +** +** Returns the size of the buffer +** +*******************************************************************************/ +UINT16 GKI_get_buf_size (void *p_buf) +{ + BUFFER_HDR_T *header = (BUFFER_HDR_T *)p_buf - 1; + return header->size; +} + +/******************************************************************************* +** +** Function GKI_enqueue +** +** Description Enqueue a buffer at the tail of the queue +** +** Parameters: p_q - (input) pointer to a queue. +** p_buf - (input) address of the buffer to enqueue +** +** Returns void +** +*******************************************************************************/ +void GKI_enqueue (BUFFER_Q *p_q, void *p_buf) +{ + BUFFER_HDR_T *p_hdr = (BUFFER_HDR_T *) ((UINT8 *) p_buf - BUFFER_HDR_SIZE); + assert(p_hdr->status == BUF_STATUS_UNLINKED); + + GKI_disable(); + + /* Since the queue is exposed (C vs C++), keep the pointers in exposed format */ + if (p_q->_p_last) + { + BUFFER_HDR_T *_p_last_hdr = (BUFFER_HDR_T *)((UINT8 *)p_q->_p_last - BUFFER_HDR_SIZE); + _p_last_hdr->p_next = p_hdr; + } + else + p_q->_p_first = p_buf; + + p_q->_p_last = p_buf; + p_q->_count++; + + p_hdr->p_next = NULL; + p_hdr->status = BUF_STATUS_QUEUED; + + GKI_enable(); +} + +/******************************************************************************* +** +** Function GKI_dequeue +** +** Description Dequeues a buffer from the head of a queue +** +** Parameters: p_q - (input) pointer to a queue. +** +** Returns NULL if queue is empty, else buffer +** +*******************************************************************************/ +void *GKI_dequeue (BUFFER_Q *p_q) +{ + BUFFER_HDR_T *p_hdr; + + GKI_disable(); + + if (!p_q || !p_q->_count) + { + GKI_enable(); + return (NULL); + } + + p_hdr = (BUFFER_HDR_T *)((UINT8 *)p_q->_p_first - BUFFER_HDR_SIZE); + + /* Keep buffers such that GKI header is invisible + */ + if (p_hdr->p_next) + p_q->_p_first = ((UINT8 *)p_hdr->p_next + BUFFER_HDR_SIZE); + else + { + p_q->_p_first = NULL; + p_q->_p_last = NULL; + } + + p_q->_count--; + + p_hdr->p_next = NULL; + p_hdr->status = BUF_STATUS_UNLINKED; + + GKI_enable(); + + return ((UINT8 *)p_hdr + BUFFER_HDR_SIZE); +} + +/******************************************************************************* +** +** Function GKI_remove_from_queue +** +** Description Dequeue a buffer from the middle of the queue +** +** Parameters: p_q - (input) pointer to a queue. +** p_buf - (input) address of the buffer to enqueue +** +** Returns NULL if queue is empty, else buffer +** +*******************************************************************************/ +void *GKI_remove_from_queue (BUFFER_Q *p_q, void *p_buf) +{ + BUFFER_HDR_T *p_prev; + BUFFER_HDR_T *p_buf_hdr; + + GKI_disable(); + + if (p_buf == p_q->_p_first) + { + GKI_enable(); + return (GKI_dequeue (p_q)); + } + + p_buf_hdr = (BUFFER_HDR_T *)((UINT8 *)p_buf - BUFFER_HDR_SIZE); + p_prev = (BUFFER_HDR_T *)((UINT8 *)p_q->_p_first - BUFFER_HDR_SIZE); + + for ( ; p_prev; p_prev = p_prev->p_next) + { + /* If the previous points to this one, move the pointers around */ + if (p_prev->p_next == p_buf_hdr) + { + p_prev->p_next = p_buf_hdr->p_next; + + /* If we are removing the last guy in the queue, update _p_last */ + if (p_buf == p_q->_p_last) + p_q->_p_last = p_prev + 1; + + /* One less in the queue */ + p_q->_count--; + + /* The buffer is now unlinked */ + p_buf_hdr->p_next = NULL; + p_buf_hdr->status = BUF_STATUS_UNLINKED; + + GKI_enable(); + return (p_buf); + } + } + + GKI_enable(); + return (NULL); +} + +/******************************************************************************* +** +** Function GKI_getfirst +** +** Description Return a pointer to the first buffer in a queue +** +** Parameters: p_q - (input) pointer to a queue. +** +** Returns NULL if queue is empty, else buffer address +** +*******************************************************************************/ +void *GKI_getfirst (BUFFER_Q *p_q) +{ + return (p_q->_p_first); +} + +/******************************************************************************* +** +** Function GKI_getlast +** +** Description Return a pointer to the last buffer in a queue +** +** Parameters: p_q - (input) pointer to a queue. +** +** Returns NULL if queue is empty, else buffer address +** +*******************************************************************************/ +void *GKI_getlast (BUFFER_Q *p_q) +{ + return (p_q->_p_last); +} + +/******************************************************************************* +** +** Function GKI_getnext +** +** Description Return a pointer to the next buffer in a queue +** +** Parameters: p_buf - (input) pointer to the buffer to find the next one from. +** +** Returns NULL if no more buffers in the queue, else next buffer address +** +*******************************************************************************/ +void *GKI_getnext (void *p_buf) +{ + BUFFER_HDR_T *p_hdr; + + p_hdr = (BUFFER_HDR_T *) ((UINT8 *) p_buf - BUFFER_HDR_SIZE); + + if (p_hdr->p_next) + return ((UINT8 *)p_hdr->p_next + BUFFER_HDR_SIZE); + else + return (NULL); +} + +/******************************************************************************* +** +** Function GKI_queue_is_empty +** +** Description Check the status of a queue. +** +** Parameters: p_q - (input) pointer to a queue. +** +** Returns TRUE if queue is empty, else FALSE +** +*******************************************************************************/ +BOOLEAN GKI_queue_is_empty(BUFFER_Q *p_q) +{ + return ((BOOLEAN) (p_q->_count == 0)); +} + +UINT16 GKI_queue_length(BUFFER_Q *p_q) +{ + return p_q->_count; +} + +/******************************************************************************* +** +** Function GKI_poolcount +** +** Description Called by an application to get the total number of buffers +** in the specified buffer pool. +** +** Parameters pool_id - (input) pool ID to get the free count of. +** +** Returns the total number of buffers in the pool +** +*******************************************************************************/ +UINT16 GKI_poolcount (UINT8 pool_id) +{ + if (pool_id >= GKI_NUM_TOTAL_BUF_POOLS) + return (0); + + return (gki_cb.com.freeq[pool_id].total); +} + +/******************************************************************************* +** +** Function GKI_poolfreecount +** +** Description Called by an application to get the number of free buffers +** in the specified buffer pool. +** +** Parameters pool_id - (input) pool ID to get the free count of. +** +** Returns the number of free buffers in the pool +** +*******************************************************************************/ +UINT16 GKI_poolfreecount (UINT8 pool_id) +{ + FREE_QUEUE_T *Q; + + if (pool_id >= GKI_NUM_TOTAL_BUF_POOLS) + return (0); + + Q = &gki_cb.com.freeq[pool_id]; + + return ((UINT16)(Q->total - Q->cur_cnt)); +} + +/******************************************************************************* +** +** Function GKI_get_pool_bufsize +** +** Description Called by an application to get the size of buffers in a pool +** +** Parameters Pool ID. +** +** Returns the size of buffers in the pool +** +*******************************************************************************/ +UINT16 GKI_get_pool_bufsize (UINT8 pool_id) +{ + if (pool_id < GKI_NUM_TOTAL_BUF_POOLS) + return (gki_cb.com.freeq[pool_id].size); + + return (0); +} + +/******************************************************************************* +** +** Function GKI_poolutilization +** +** Description Called by an application to get the buffer utilization +** in the specified buffer pool. +** +** Parameters pool_id - (input) pool ID to get the free count of. +** +** Returns % of buffers used from 0 to 100 +** +*******************************************************************************/ +UINT16 GKI_poolutilization (UINT8 pool_id) +{ + FREE_QUEUE_T *Q; + + if (pool_id >= GKI_NUM_TOTAL_BUF_POOLS) + return (100); + + Q = &gki_cb.com.freeq[pool_id]; + + if (Q->total == 0) + return (100); + + return ((Q->cur_cnt * 100) / Q->total); +} diff --git a/components/bt/bluedroid/gki/gki_ulinux.c b/components/bt/bluedroid/gki/gki_ulinux.c new file mode 100755 index 0000000000..058b9a23a8 --- /dev/null +++ b/components/bt/bluedroid/gki/gki_ulinux.c @@ -0,0 +1,62 @@ +/****************************************************************************** + * + * Copyright (C) 2009-2012 Broadcom Corporation + * + * 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. + * + ******************************************************************************/ +#include +#include "bt_trace.h" +#include "gki_int.h" +#include "osi.h" +#include "osi_arch.h" +#include "alarm.h" +#include "bt_defs.h" + +tGKI_CB gki_cb; + +int gki_init(void) { + memset(&gki_cb, 0, sizeof(gki_cb)); + + //pthread_mutexattr_t attr; + //pthread_mutexattr_init(&attr); + //pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE_NP); + pthread_mutex_init(&gki_cb.lock, NULL);//&attr); + + gki_buffer_init(); + return 0; +} + +void gki_clean_up(void) { + gki_buffer_cleanup(); + + pthread_mutex_destroy(&gki_cb.lock); +} + +UINT32 GKI_get_os_tick_count(void) { + return osi_alarm_now(); +} + +// Sleep the calling thread unconditionally for |timeout_ms| milliseconds. +void GKI_delay(UINT32 timeout_ms) { + osi_delay_ms(timeout_ms); + /*TODO:*/ +} + +void GKI_enable(void) { + pthread_mutex_unlock(&gki_cb.lock); +} + +void GKI_disable(void) { + pthread_mutex_lock(&gki_cb.lock); +} diff --git a/components/bt/bluedroid/gki/include/gki.h b/components/bt/bluedroid/gki/include/gki.h new file mode 100755 index 0000000000..cbcb77151f --- /dev/null +++ b/components/bt/bluedroid/gki/include/gki.h @@ -0,0 +1,101 @@ +/****************************************************************************** + * + * Copyright (C) 1999-2012 Broadcom Corporation + * + * 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. + * + ******************************************************************************/ + +#ifndef _GKI_H_ +#define _GKI_H_ + +#include "bt_target.h" +#include "bt_types.h" + +//static const char GKI_MODULE[] = "gki_module"; + +/* Timer list entry callback type +*/ +typedef void (TIMER_CBACK)(void *p_tle); +#ifndef TIMER_PARAM_TYPE +#define TIMER_PARAM_TYPE UINT32 +#endif +/* Define a timer list entry +*/ +typedef struct _tle +{ + struct _tle *p_next; + struct _tle *p_prev; + TIMER_CBACK *p_cback; + INT32 ticks; + INT32 ticks_initial; + TIMER_PARAM_TYPE param; + TIMER_PARAM_TYPE data; + UINT16 event; + UINT8 in_use; +} TIMER_LIST_ENT; + +/*********************************************************************** +** This queue is a general purpose buffer queue, for application use. +*/ +typedef struct +{ + void *_p_first; + void *_p_last; + UINT16 _count; +} BUFFER_Q; + +#define GKI_PUBLIC_POOL 0 /* General pool accessible to GKI_getbuf() */ +#define GKI_RESTRICTED_POOL 1 /* Inaccessible pool to GKI_getbuf() */ + +/*********************************************************************** +** Function prototypes +*/ + +/* To get and release buffers, change owner and get size +*/ +void GKI_freebuf (void *); +void *GKI_getbuf (UINT16); +UINT16 GKI_get_buf_size (void *); +void *GKI_getpoolbuf (UINT8); +UINT16 GKI_poolcount (UINT8); +UINT16 GKI_poolfreecount (UINT8); +UINT16 GKI_poolutilization (UINT8); + + +/* User buffer queue management +*/ +void *GKI_dequeue (BUFFER_Q *); +void GKI_enqueue (BUFFER_Q *, void *); +void *GKI_getfirst (BUFFER_Q *); +void *GKI_getlast (BUFFER_Q *); +void *GKI_getnext (void *); +void GKI_init_q (BUFFER_Q *); +UINT16 GKI_queue_length(BUFFER_Q *); +BOOLEAN GKI_queue_is_empty(BUFFER_Q *); +void *GKI_remove_from_queue (BUFFER_Q *, void *); +UINT16 GKI_get_pool_bufsize (UINT8); + +/* Timer management +*/ +void GKI_delay(UINT32); + +/* Disable Interrupts, Enable Interrupts +*/ +void GKI_enable(void); +void GKI_disable(void); + +/* os timer operation */ +UINT32 GKI_get_os_tick_count(void); + +#endif /*_GKI_H_*/ diff --git a/components/bt/bluedroid/gki/include/gki_common.h b/components/bt/bluedroid/gki/include/gki_common.h new file mode 100755 index 0000000000..9416a1c697 --- /dev/null +++ b/components/bt/bluedroid/gki/include/gki_common.h @@ -0,0 +1,68 @@ +/****************************************************************************** + * + * Copyright (C) 1999-2012 Broadcom Corporation + * + * 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. + * + ******************************************************************************/ + +#ifndef _GKI_COMMON_H_ +#define _GKI_COMMON_H_ + +#include "gki.h" + +typedef struct _buffer_hdr +{ + struct _buffer_hdr *p_next; /* next buffer in the queue */ + UINT8 q_id; /* id of the queue */ + UINT8 status; /* FREE, UNLINKED or QUEUED */ + UINT8 Type; + UINT16 size; +} BUFFER_HDR_T; + +typedef struct _free_queue +{ + BUFFER_HDR_T *_p_first; /* first buffer in the queue */ + BUFFER_HDR_T *_p_last; /* last buffer in the queue */ + UINT16 size; /* size of the buffers in the pool */ + UINT16 total; /* toatal number of buffers */ + UINT16 cur_cnt; /* number of buffers currently allocated */ + UINT16 max_cnt; /* maximum number of buffers allocated at any time */ +} FREE_QUEUE_T; + +/* Put all GKI variables into one control block +*/ +typedef struct +{ + /* Define the buffer pool management variables + */ + FREE_QUEUE_T freeq[GKI_NUM_TOTAL_BUF_POOLS]; + + UINT16 pool_buf_size[GKI_NUM_TOTAL_BUF_POOLS]; + + /* Define the buffer pool start addresses + */ + UINT8 *pool_start[GKI_NUM_TOTAL_BUF_POOLS]; /* array of pointers to the start of each buffer pool */ + UINT8 *pool_end[GKI_NUM_TOTAL_BUF_POOLS]; /* array of pointers to the end of each buffer pool */ + UINT16 pool_size[GKI_NUM_TOTAL_BUF_POOLS]; /* actual size of the buffers in a pool */ + + /* Define the buffer pool access control variables */ + UINT16 pool_access_mask; /* Bits are set if the corresponding buffer pool is a restricted pool */ +} tGKI_COM_CB; + +/* Internal GKI function prototypes +*/ +void gki_buffer_init(void); +void gki_buffer_cleanup(void); + +#endif /*_GKI_COMMON_H_*/ diff --git a/components/bt/bluedroid/gki/include/gki_int.h b/components/bt/bluedroid/gki/include/gki_int.h new file mode 100755 index 0000000000..55768795dc --- /dev/null +++ b/components/bt/bluedroid/gki/include/gki_int.h @@ -0,0 +1,35 @@ +/****************************************************************************** + * + * Copyright (C) 1999-2012 Broadcom Corporation + * + * 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. + * + ******************************************************************************/ + +#ifndef _GKI_INT_H_ +#define _GKI_INT_H_ + +//#include +#include "bt_defs.h" + +#include "gki_common.h" + +typedef struct +{ + pthread_mutex_t lock; + tGKI_COM_CB com; +} tGKI_CB; + +extern tGKI_CB gki_cb; + +#endif /*_GKI_INT_H_*/ diff --git a/components/bt/bluedroid/hci/buffer_allocator.c b/components/bt/bluedroid/hci/buffer_allocator.c new file mode 100755 index 0000000000..e92101bcd3 --- /dev/null +++ b/components/bt/bluedroid/hci/buffer_allocator.c @@ -0,0 +1,33 @@ +/****************************************************************************** + * + * Copyright (C) 2014 Google, Inc. + * + * 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. + * + ******************************************************************************/ +#include "buffer_allocator.h" +#include "gki.h" + +// TODO(zachoverflow): move the assertion into GKI_getbuf in the future +static void *buffer_alloc(size_t size) { + return GKI_getbuf((uint16_t)size); +} + +static const allocator_t interface = { + buffer_alloc, + GKI_freebuf +}; + +const allocator_t *buffer_allocator_get_interface() { + return &interface; +} diff --git a/components/bt/bluedroid/hci/hci_hal_h4.c b/components/bt/bluedroid/hci/hci_hal_h4.c new file mode 100755 index 0000000000..2a9ee3e331 --- /dev/null +++ b/components/bt/bluedroid/hci/hci_hal_h4.c @@ -0,0 +1,288 @@ +/****************************************************************************** + * + * Copyright (C) 2014 Google, Inc. + * + * 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. + * + ******************************************************************************/ +#include +#include "bt_defs.h" +#include "bt_trace.h" +#include "bt_types.h" +#include "buffer_allocator.h" +#include "fixed_queue.h" +#include "hci_hal.h" +#include "hci_internals.h" +#include "hci_layer.h" + +#include "thread.h" + +#define HCI_HAL_SERIAL_BUFFER_SIZE 1026 +#define HCI_BLE_EVENT 0x3e +#define PACKET_TYPE_TO_INBOUND_INDEX(type) ((type) - 2) +#define PACKET_TYPE_TO_INDEX(type) ((type) - 1) + + +static const uint8_t preamble_sizes[] = { + HCI_COMMAND_PREAMBLE_SIZE, + HCI_ACL_PREAMBLE_SIZE, + HCI_SCO_PREAMBLE_SIZE, + HCI_EVENT_PREAMBLE_SIZE +}; + +static const uint16_t outbound_event_types[] = { + MSG_HC_TO_STACK_HCI_ERR, + MSG_HC_TO_STACK_HCI_ACL, + MSG_HC_TO_STACK_HCI_SCO, + MSG_HC_TO_STACK_HCI_EVT +}; + +typedef struct { + const allocator_t *allocator; + size_t buffer_size; + fixed_queue_t *rx_q; +} hci_hal_env_t; + + +static hci_hal_env_t hci_hal_env; +static const hci_hal_t interface; +static const hci_hal_callbacks_t *callbacks; +static const vhci_host_callback_t vhci_host_cb; + +static xTaskHandle xHciH4TaskHandle; +static xQueueHandle xHciH4Queue; + +static void host_send_pkt_available_cb(void); +static int host_recv_pkt_cb(uint8_t *data, uint16_t len); + +static void hci_hal_h4_rx_handler(void *arg); +static void event_uart_has_bytes(fixed_queue_t *queue); + + +static void hci_hal_env_init( + size_t buffer_size, + size_t max_buffer_count) { + assert(buffer_size > 0); + assert(max_buffer_count > 0); + + hci_hal_env.allocator = buffer_allocator_get_interface(); + hci_hal_env.buffer_size = buffer_size; + + hci_hal_env.rx_q = fixed_queue_new(max_buffer_count); + if (hci_hal_env.rx_q) + fixed_queue_register_dequeue(hci_hal_env.rx_q, event_uart_has_bytes); + else + LOG_ERROR("%s unable to create rx queue.", __func__); + + return; +} + +static void hci_hal_env_deinit(void) { + fixed_queue_free(hci_hal_env.rx_q, hci_hal_env.allocator->free); +} + +static bool hal_open(const hci_hal_callbacks_t *upper_callbacks) { + assert(upper_callbacks != NULL); + callbacks = upper_callbacks; + + hci_hal_env_init(HCI_HAL_SERIAL_BUFFER_SIZE, SIZE_MAX); + + xHciH4Queue = xQueueCreate(3, sizeof(void *)); + xTaskCreate(hci_hal_h4_rx_handler, "HciH4T", 4096+2048, NULL, configMAX_PRIORITIES - 3, &xHciH4TaskHandle); + + //register vhci host cb + API_vhci_host_register_callback(&vhci_host_cb); + + + return true; + +error: + interface.close(); + return false; +} + +static void hal_close() { + hci_hal_env_deinit(); + + /* delete task and queue */ + vTaskDelete(xHciH4TaskHandle); + vQueueDelete(xHciH4Queue); +} + +/** + * Function: transmit_data -TX data to low-layer + * It is ported from Bluedroid source code, so it is not + * needed to use write() to send data. + * TODO: Just use firmware API to send data. + */ +static uint16_t transmit_data(serial_data_type_t type, + uint8_t *data, uint16_t length) +{ + uint8_t previous_byte; + + assert(data != NULL); + assert(length > 0); + + if (type < DATA_TYPE_COMMAND || type > DATA_TYPE_SCO) { + LOG_ERROR("%s invalid data type: %d", __func__, type); + return 0; + } + + // Write the signal byte right before the data + --data; + previous_byte = *data; + *(data) = type; + ++length; + + BTTRC_DUMP_BUFFER("Transmit Pkt", data, length); + + // TX Data to target + API_vhci_host_send_packet(data, length); + + // Be nice and restore the old value of that byte + *(data) = previous_byte; + + return length - 1; +} + +// Internal functions +static void hci_hal_h4_rx_handler(void *arg) { + TaskEvt_t *e; + + for (;;) { + if (pdTRUE == xQueueReceive(xHciH4Queue, &e, (portTickType)portMAX_DELAY)) { + if (e->sig == 0xff) { + fixed_queue_process(hci_hal_env.rx_q); + } + osi_free(e); + } + } +} + +void hci_hal_h4_task_post(void) +{ + TaskEvt_t *evt = (TaskEvt_t *)osi_malloc(sizeof(TaskEvt_t)); + if (evt == NULL) + return; + + evt->sig = 0xff; + evt->par = 0; + + if (xQueueSend(xHciH4Queue, &evt, 10/portTICK_RATE_MS) != pdTRUE) { + ets_printf("xHciH4Queue failed\n"); + } +} + +static void hci_hal_h4_hdl_rx_packet(BT_HDR *packet) { + uint8_t type, hdr_size; + uint16_t length; + uint8_t *stream = packet->data + packet->offset; + + if (!packet) + return; + STREAM_TO_UINT8(type, stream); + packet->offset++; + packet->len--; + if (type == HCI_BLE_EVENT) { + uint8_t len; + STREAM_TO_UINT8(len, stream); + LOG_ERROR("Workround stream corrupted during LE SCAN: pkt_len=%d ble_event_len=%d", + packet->len, len); + hci_hal_env.allocator->free(packet); + return; + } + if (type < DATA_TYPE_ACL || type > DATA_TYPE_EVENT) { + LOG_ERROR("%d Unknown HCI message type. Dropping this byte 0x%x," + " min %x, max %x", __func__, type, + DATA_TYPE_ACL, DATA_TYPE_EVENT); + hci_hal_env.allocator->free(packet); + return; + } + hdr_size = preamble_sizes[type - 1]; + if (packet->len < hdr_size) { + LOG_ERROR("Wrong packet length type=%s pkt_len=%d hdr_len=%d", + type, packet->len, hdr_size); + hci_hal_env.allocator->free(packet); + return; + } + if (type == DATA_TYPE_ACL) { + stream += hdr_size - 2; + STREAM_TO_UINT16(length, stream); + } else { + stream += hdr_size - 1; + STREAM_TO_UINT8(length, stream); + } + + if ((length + hdr_size) != packet->len) { + LOG_ERROR("Wrong packet length type=%d hdr_len=%d pd_len=%d " + "pkt_len=%d", type, hdr_size, length, packet->len); + hci_hal_env.allocator->free(packet); + return; + } + + packet->event = outbound_event_types[PACKET_TYPE_TO_INDEX(type)]; + callbacks->packet_ready(packet); +} + +static void event_uart_has_bytes(fixed_queue_t *queue) { + BT_HDR *packet; + while (!fixed_queue_is_empty(queue)) { + packet = fixed_queue_dequeue(queue); + hci_hal_h4_hdl_rx_packet(packet); + } +} + +static void host_send_pkt_available_cb(void) { + //Controller rx cache buffer is ready for receiving new host packet + //Just Call Host main thread task to process pending packets. + hci_host_task_post(); +} + +static int host_recv_pkt_cb(uint8_t *data, uint16_t len) { + //Target has packet to host, malloc new buffer for packet + BT_HDR *pkt; + size_t pkt_size; + + pkt_size = BT_HDR_SIZE + len; + pkt = (BT_HDR *)hci_hal_env.allocator->alloc(pkt_size); + if (!pkt) { + LOG_ERROR("%s couldn't aquire memory for inbound data buffer.", __func__); + return -1; + } + pkt->offset = 0; + pkt->len = len; + pkt->layer_specific = 0; + memcpy(pkt->data, data, len); + fixed_queue_enqueue(hci_hal_env.rx_q, pkt); + hci_hal_h4_task_post(); + + BTTRC_DUMP_BUFFER("Recv Pkt", pkt->data, len); + + return 0; +} + +static const vhci_host_callback_t vhci_host_cb = { + .notify_host_send_available = host_send_pkt_available_cb, + .notify_host_recv = host_recv_pkt_cb, +}; + +static const hci_hal_t interface = { + hal_open, + hal_close, + transmit_data, +}; + +const hci_hal_t *hci_hal_h4_get_interface() { + return &interface; +} + diff --git a/components/bt/bluedroid/hci/hci_layer.c b/components/bt/bluedroid/hci/hci_layer.c new file mode 100755 index 0000000000..9f368f8325 --- /dev/null +++ b/components/bt/bluedroid/hci/hci_layer.c @@ -0,0 +1,574 @@ +/****************************************************************************** + * + * Copyright (C) 2014 Google, Inc. + * + * 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. + * + ******************************************************************************/ +#include + +#include "bt_defs.h" +#include "bt_trace.h" +#include "hcidefs.h" +#include "hcimsgs.h" +#include "bt_vendor_lib.h" +#include "hci_internals.h" +#include "hci_hal.h" +#include "hci_layer.h" +#include "allocator.h" +#include "packet_fragmenter.h" +#include "buffer_allocator.h" +#include "list.h" +#include "alarm.h" +#include "thread.h" + +typedef struct { + uint16_t opcode; + command_complete_cb complete_callback; + command_status_cb status_callback; + void *context; + uint32_t sent_time; + BT_HDR *command; +} waiting_command_t; + +typedef struct { + bool timer_is_set; + osi_alarm_t *command_response_timer; + list_t *commands_pending_response; + pthread_mutex_t commands_pending_response_lock; +} command_waiting_response_t; + +typedef struct { + int command_credits; + fixed_queue_t *command_queue; + fixed_queue_t *packet_queue; + + // The hand-off point for data going to a higher layer, set by the higher layer + fixed_queue_t *upwards_data_queue; + + command_waiting_response_t cmd_waiting_q; + +/* + non_repeating_timer_t *command_response_timer; + list_t *commands_pending_response; + pthread_mutex_t commands_pending_response_lock; +*/ +} hci_host_env_t; + +// Using a define here, because it can be stringified for the property lookup +static const uint32_t COMMAND_PENDING_TIMEOUT = 8000; + +// Our interface +static bool interface_created; +static hci_t interface; +static hci_host_env_t hci_host_env; + +static xTaskHandle xHciHostTaskHandle; +static xQueueHandle xHciHostQueue; + +static bool hci_host_startup_flag; + +// Modules we import and callbacks we export +static const allocator_t *buffer_allocator; +static const hci_hal_t *hal; +static const hci_hal_callbacks_t hal_callbacks; +static const packet_fragmenter_t *packet_fragmenter; +static const packet_fragmenter_callbacks_t packet_fragmenter_callbacks; + +static int hci_layer_init_env(void); +static void hci_layer_deinit_env(void); +static void hci_host_thread_handler(void *arg); +static int hci_send_async_command(bt_vendor_opcode_t opcode, void *param); +static void event_finish_startup(void *context); +static void firmware_config_callback(bool success); +static void event_postload(void); +static void sco_config_callback(bool success); +static void event_command_ready(fixed_queue_t *queue); +static void event_packet_ready(fixed_queue_t *queue); +static void restart_comamnd_waiting_response_timer( + command_waiting_response_t *cmd_wait_q, + bool tigger_by_sending_command); +static void command_timed_out(void *context); +static void hal_says_packet_ready(BT_HDR *packet); +static bool filter_incoming_event(BT_HDR *packet); +static serial_data_type_t event_to_data_type(uint16_t event); +static waiting_command_t *get_waiting_command(command_opcode_t opcode); +static void dispatch_reassembled(BT_HDR *packet); + +// Module lifecycle functions +int hci_start_up(void) { + if (hci_layer_init_env()) + goto error; + + xHciHostQueue = xQueueCreate(3, sizeof(void *)); + xTaskCreate(hci_host_thread_handler, "HciHostT", (4096+2048), NULL, configMAX_PRIORITIES - 3, &xHciHostTaskHandle); + + packet_fragmenter->init(&packet_fragmenter_callbacks); + hal->open(&hal_callbacks); + + hci_host_startup_flag = true; + return 0; +error: + hci_shut_down(); + return -1; +} + +void hci_shut_down(void) { + hci_host_startup_flag = false; + hci_layer_deinit_env(); + + packet_fragmenter->cleanup(); + + //low_power_manager->cleanup(); + hal->close(); + vTaskDelete(xHciHostTaskHandle); + vQueueDelete(xHciHostQueue); +} + + +void hci_host_task_post(void) +{ + if (hci_host_startup_flag == false) + return; + + TaskEvt_t *evt = (TaskEvt_t *)osi_malloc(sizeof(TaskEvt_t)); + if (evt == NULL) + return; + + evt->sig = 0xff; + evt->par = 0; + + if (xQueueSend(xHciHostQueue, &evt, 10/portTICK_RATE_MS) != pdTRUE) { + ets_printf("xHciHostQueue failed\n"); + } +} + +static int hci_layer_init_env(void) +{ + command_waiting_response_t *cmd_wait_q; + + // The host is only allowed to send at most one command initially, + // as per the Bluetooth spec, Volume 2, Part E, 4.4 (Command Flow Control) + // This value can change when you get a command complete or command status event. + hci_host_env.command_credits = 1; + hci_host_env.command_queue = fixed_queue_new(SIZE_MAX); + if (hci_host_env.command_queue) + fixed_queue_register_dequeue(hci_host_env.command_queue, event_command_ready); + else { + LOG_ERROR("%s unable to create pending command queue.", __func__); + return -1; + } + + hci_host_env.packet_queue = fixed_queue_new(SIZE_MAX); + if (hci_host_env.packet_queue) + fixed_queue_register_dequeue(hci_host_env.packet_queue, event_packet_ready); + else { + LOG_ERROR("%s unable to create pending packet queue.", __func__); + return -1; + } + + // Init Commands waiting response list and timer + cmd_wait_q = &hci_host_env.cmd_waiting_q; + cmd_wait_q->timer_is_set = false; + cmd_wait_q->commands_pending_response = list_new(NULL); + if (!cmd_wait_q->commands_pending_response) { + LOG_ERROR("%s unable to create list for commands pending response.", __func__); + return -1; + } + pthread_mutex_init(&cmd_wait_q->commands_pending_response_lock, NULL); + cmd_wait_q->command_response_timer = osi_alarm_new("cmd_rsp_to", command_timed_out, cmd_wait_q, COMMAND_PENDING_TIMEOUT); + if (!cmd_wait_q->command_response_timer) { + LOG_ERROR("%s unable to create command response timer.", __func__); + return -1; + } + + return 0; +} + +static void hci_layer_deinit_env(void) +{ + command_waiting_response_t *cmd_wait_q; + + if (hci_host_env.command_queue) + fixed_queue_free(hci_host_env.command_queue, osi_free); + if (hci_host_env.packet_queue) + fixed_queue_free(hci_host_env.packet_queue, buffer_allocator->free); + + cmd_wait_q = &hci_host_env.cmd_waiting_q; + list_free(cmd_wait_q->commands_pending_response); + pthread_mutex_destroy(&cmd_wait_q->commands_pending_response_lock); + osi_alarm_free(cmd_wait_q->command_response_timer); + cmd_wait_q->command_response_timer = NULL; +} + +static void hci_host_thread_handler(void *arg) +{ + /* + * Previous task handles RX queue and two TX Queues, Since there is + * a RX Thread Task in H4 layer which receives packet from driver layer. + * Now HCI Host Task has been optimized to only process TX Queue + * including command and data queue. And command queue has high priority, + * All packets will be directly copied to single queue in driver layer with + * H4 type header added (1 byte). + */ + + TaskEvt_t *e; + + for (;;) { + if (pdTRUE == xQueueReceive(xHciHostQueue, &e, (portTickType)portMAX_DELAY)) { + + if (e->sig == 0xff) { + if (API_vhci_host_check_send_available()) { + /*Now Target only allowed one packet per TX*/ + BT_HDR *pkt = packet_fragmenter->fragment_current_packet(); + if (pkt != NULL) { + packet_fragmenter->fragment_and_dispatch(pkt); + } else { + if (!fixed_queue_is_empty(hci_host_env.command_queue) && + hci_host_env.command_credits > 0) + fixed_queue_process(hci_host_env.command_queue); + else if (!fixed_queue_is_empty(hci_host_env.packet_queue)) + fixed_queue_process(hci_host_env.packet_queue); + } + } + } + } + osi_free(e); + } +} + +static void set_data_queue(fixed_queue_t *queue) { + hci_host_env.upwards_data_queue = queue; +} + +static void transmit_command( + BT_HDR *command, + command_complete_cb complete_callback, + command_status_cb status_callback, + void *context) { + uint8_t *stream; + waiting_command_t *wait_entry = osi_calloc(sizeof(waiting_command_t)); + if (!wait_entry) { + LOG_ERROR("%s couldn't allocate space for wait entry.", __func__); + return; + } + + stream = command->data + command->offset; + STREAM_TO_UINT16(wait_entry->opcode, stream); + wait_entry->complete_callback = complete_callback; + wait_entry->status_callback = status_callback; + wait_entry->command = command; + wait_entry->context = context; + + // Store the command message type in the event field + // in case the upper layer didn't already + command->event = MSG_STACK_TO_HC_HCI_CMD; + LOG_DEBUG("HCI Enqueue Comamnd opcode=0x%x\n", wait_entry->opcode); + BTTRC_DUMP_BUFFER(NULL, command->data + command->offset, command->len); + + fixed_queue_enqueue(hci_host_env.command_queue, wait_entry); + hci_host_task_post(); +} + +static void transmit_downward(uint16_t type, void *data) { + BT_HDR *tmp = (BT_HDR *)data; + if (type == MSG_STACK_TO_HC_HCI_CMD) { + transmit_command((BT_HDR *)data, NULL, NULL, NULL); + LOG_WARN("%s legacy transmit of command. Use transmit_command instead.\n", __func__); + } else { + fixed_queue_enqueue(hci_host_env.packet_queue, data); + } + //ke_event_set(KE_EVENT_HCI_HOST_THREAD); + hci_host_task_post(); +} + +// Postload functions +static void event_postload(void) { + if (hci_send_async_command(BT_VND_OP_SCO_CFG, NULL) == -1) { + // If couldn't configure sco, we won't get the sco configuration callback + // so go pretend to do it now + sco_config_callback(false); + + } +} + +static void sco_config_callback(UNUSED_ATTR bool success) { + LOG_INFO("%s postload finished.", __func__); +} + +// Command/packet transmitting functions + +static void event_command_ready(fixed_queue_t *queue) { + waiting_command_t *wait_entry = NULL; + command_waiting_response_t *cmd_wait_q = &hci_host_env.cmd_waiting_q; + + wait_entry = fixed_queue_dequeue(queue); + hci_host_env.command_credits--; + + // Move it to the list of commands awaiting response + pthread_mutex_lock(&cmd_wait_q->commands_pending_response_lock); + //ets_printf("%s\n", __func__); + list_append(cmd_wait_q->commands_pending_response, wait_entry); + pthread_mutex_unlock(&cmd_wait_q->commands_pending_response_lock); + + // Send it off + packet_fragmenter->fragment_and_dispatch(wait_entry->command); + + wait_entry->sent_time = osi_alarm_now(); + restart_comamnd_waiting_response_timer(cmd_wait_q, true); +} + +static void event_packet_ready(fixed_queue_t *queue) { + BT_HDR *packet = (BT_HDR *)fixed_queue_dequeue(queue); + // The queue may be the command queue or the packet queue, we don't care + + packet_fragmenter->fragment_and_dispatch(packet); +} + +// Callback for the fragmenter to send a fragment +static void transmit_fragment(BT_HDR *packet, bool send_transmit_finished) { + uint16_t event = packet->event & MSG_EVT_MASK; + serial_data_type_t type = event_to_data_type(event); + + hal->transmit_data(type, packet->data + packet->offset, packet->len); + + if (event != MSG_STACK_TO_HC_HCI_CMD && send_transmit_finished) + buffer_allocator->free(packet); +} + +static void fragmenter_transmit_finished(BT_HDR *packet, bool all_fragments_sent) { + if (all_fragments_sent) { + buffer_allocator->free(packet); + } else { + // This is kind of a weird case, since we're dispatching a partially sent packet + // up to a higher layer. + // TODO(zachoverflow): rework upper layer so this isn't necessary. + dispatch_reassembled(packet); + //data_dispatcher_dispatch(interface.event_dispatcher, packet->event & MSG_EVT_MASK, packet); + } +} + +static void restart_comamnd_waiting_response_timer( + command_waiting_response_t *cmd_wait_q, + bool tigger_by_sending_command) +{ + uint32_t timeout; + waiting_command_t *wait_entry; + if (!cmd_wait_q) + return; + + if (cmd_wait_q->timer_is_set) { + if (tigger_by_sending_command) + return; + + //Cancel Previous command timeout timer setted when sending command + osi_alarm_cancel(cmd_wait_q->command_response_timer); + cmd_wait_q->timer_is_set = false; + } + + pthread_mutex_lock(&cmd_wait_q->commands_pending_response_lock); + wait_entry = (list_is_empty(cmd_wait_q->commands_pending_response) ? + NULL : list_front(cmd_wait_q->commands_pending_response)); + pthread_mutex_unlock(&cmd_wait_q->commands_pending_response_lock); + + if (wait_entry == NULL) + return; + + timeout =osi_alarm_time_diff(osi_alarm_now(), wait_entry->sent_time); + timeout =osi_alarm_time_diff(COMMAND_PENDING_TIMEOUT, timeout); + timeout = (timeout <= COMMAND_PENDING_TIMEOUT) ? timeout : COMMAND_PENDING_TIMEOUT; + + osi_alarm_set(cmd_wait_q->command_response_timer, timeout); + cmd_wait_q->timer_is_set = true; +} + +static void command_timed_out(void *context) { + command_waiting_response_t *cmd_wait_q = (command_waiting_response_t *)context; + waiting_command_t *wait_entry; + + pthread_mutex_lock(&cmd_wait_q->commands_pending_response_lock); + wait_entry = (list_is_empty(cmd_wait_q->commands_pending_response) ? + NULL : list_front(cmd_wait_q->commands_pending_response)); + pthread_mutex_unlock(&cmd_wait_q->commands_pending_response_lock); + + if (wait_entry == NULL) + LOG_ERROR("%s with no commands pending response", __func__); + else + // We shouldn't try to recover the stack from this command timeout. + // If it's caused by a software bug, fix it. If it's a hardware bug, fix it. + LOG_ERROR("%s hci layer timeout waiting for response to a command. opcode: 0x%x", __func__, wait_entry->opcode); +} + +// Event/packet receiving functions +static void hal_says_packet_ready(BT_HDR *packet) { + if (packet->event != MSG_HC_TO_STACK_HCI_EVT) { + packet_fragmenter->reassemble_and_dispatch(packet); + } else if (!filter_incoming_event(packet)) { + dispatch_reassembled(packet); + } +} + +// Returns true if the event was intercepted and should not proceed to +// higher layers. Also inspects an incoming event for interesting +// information, like how many commands are now able to be sent. +static bool filter_incoming_event(BT_HDR *packet) { + waiting_command_t *wait_entry = NULL; + uint8_t *stream = packet->data + packet->offset; + uint8_t event_code; + command_opcode_t opcode; + + STREAM_TO_UINT8(event_code, stream); + STREAM_SKIP_UINT8(stream); // Skip the parameter total length field + + LOG_DEBUG("Receive packet event_code=0x%x\n", event_code); + + if (event_code == HCI_COMMAND_COMPLETE_EVT) { + STREAM_TO_UINT8(hci_host_env.command_credits, stream); + STREAM_TO_UINT16(opcode, stream); + + wait_entry = get_waiting_command(opcode); + if (!wait_entry) + LOG_WARN("%s command complete event with no matching command. opcode: 0x%x.", __func__, opcode); + else if (wait_entry->complete_callback) + wait_entry->complete_callback(packet, wait_entry->context); + + goto intercepted; + } else if (event_code == HCI_COMMAND_STATUS_EVT) { + uint8_t status; + STREAM_TO_UINT8(status, stream); + STREAM_TO_UINT8(hci_host_env.command_credits, stream); + STREAM_TO_UINT16(opcode, stream); + + // If a command generates a command status event, it won't be getting a command complete event + + wait_entry = get_waiting_command(opcode); + if (!wait_entry) + LOG_WARN("%s command status event with no matching command. opcode: 0x%x", __func__, opcode); + else if (wait_entry->status_callback) + wait_entry->status_callback(status, wait_entry->command, wait_entry->context); + + goto intercepted; + } + + return false; +intercepted: + /*Tell HCI Host Task to continue TX Pending commands*/ + if (hci_host_env.command_credits && + !fixed_queue_is_empty(hci_host_env.command_queue)) + hci_host_task_post(); + //ke_event_set(KE_EVENT_HCI_HOST_THREAD); + + restart_comamnd_waiting_response_timer(&hci_host_env.cmd_waiting_q, false); + + if (wait_entry) { + // If it has a callback, it's responsible for freeing the packet + if (event_code == HCI_COMMAND_STATUS_EVT || + !wait_entry->complete_callback) + buffer_allocator->free(packet); + + // If it has a callback, it's responsible for freeing the command + if (event_code == HCI_COMMAND_COMPLETE_EVT || !wait_entry->status_callback) + buffer_allocator->free(wait_entry->command); + + osi_free(wait_entry); + } else { + buffer_allocator->free(packet); + } + + return true; +} + +// Callback for the fragmenter to dispatch up a completely reassembled packet +static void dispatch_reassembled(BT_HDR *packet) { + // Events should already have been dispatched before this point + + if (hci_host_env.upwards_data_queue) { + fixed_queue_enqueue(hci_host_env.upwards_data_queue, packet); + btu_task_post(); + //Tell Up-layer received packet. + } else { + LOG_DEBUG("%s had no queue to place upwards data packet in. Dropping it on the floor.", __func__); + buffer_allocator->free(packet); + } +} + +// Misc internal functions + +// TODO(zachoverflow): we seem to do this a couple places, like the HCI inject module. #centralize +static serial_data_type_t event_to_data_type(uint16_t event) { + if (event == MSG_STACK_TO_HC_HCI_ACL) + return DATA_TYPE_ACL; + else if (event == MSG_STACK_TO_HC_HCI_SCO) + return DATA_TYPE_SCO; + else if (event == MSG_STACK_TO_HC_HCI_CMD) + return DATA_TYPE_COMMAND; + else + LOG_ERROR("%s invalid event type, could not translate 0x%x", __func__, event); + + return 0; +} + +static waiting_command_t *get_waiting_command(command_opcode_t opcode) { + command_waiting_response_t *cmd_wait_q = &hci_host_env.cmd_waiting_q; + pthread_mutex_lock(&cmd_wait_q->commands_pending_response_lock); + + for (const list_node_t *node = list_begin(cmd_wait_q->commands_pending_response); + node != list_end(cmd_wait_q->commands_pending_response); + node = list_next(node)) { + waiting_command_t *wait_entry = list_node(node); + //ets_printf("wait_entry %08x\n", wait_entry); + if (!wait_entry || wait_entry->opcode != opcode) + continue; + + list_remove(cmd_wait_q->commands_pending_response, wait_entry); + + pthread_mutex_unlock(&cmd_wait_q->commands_pending_response_lock); + return wait_entry; + } + + pthread_mutex_unlock(&cmd_wait_q->commands_pending_response_lock); + return NULL; +} + +static int hci_send_async_command(bt_vendor_opcode_t opcode, void *param) +{ +} + +static void init_layer_interface() { + if (!interface_created) { + interface.set_data_queue = set_data_queue; + interface.transmit_command = transmit_command; + interface.transmit_downward = transmit_downward; + interface_created = true; + } +} + +static const hci_hal_callbacks_t hal_callbacks = { + hal_says_packet_ready +}; + +static const packet_fragmenter_callbacks_t packet_fragmenter_callbacks = { + transmit_fragment, + dispatch_reassembled, + fragmenter_transmit_finished +}; + +const hci_t *hci_layer_get_interface() { + buffer_allocator = buffer_allocator_get_interface(); + hal = hci_hal_h4_get_interface(); + packet_fragmenter = packet_fragmenter_get_interface(); + + init_layer_interface(); + return &interface; +} + diff --git a/components/bt/bluedroid/hci/hci_packet_factory.c b/components/bt/bluedroid/hci/hci_packet_factory.c new file mode 100755 index 0000000000..ba1e35ce33 --- /dev/null +++ b/components/bt/bluedroid/hci/hci_packet_factory.c @@ -0,0 +1,202 @@ +/****************************************************************************** + * + * Copyright (C) 2014 Google, Inc. + * + * 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. + * + ******************************************************************************/ + +#include "bt_defs.h" + +#include "allocator.h" +#include "bt_types.h" +#include "buffer_allocator.h" +#include "hcidefs.h" +#include "hcimsgs.h" +#include "hci_internals.h" +#include "hci_layer.h" +#include "hci_packet_factory.h" + +static const allocator_t *buffer_allocator; + +static BT_HDR *make_packet(size_t data_size); +static BT_HDR *make_command_no_params(uint16_t opcode); +static BT_HDR *make_command(uint16_t opcode, size_t parameter_size, uint8_t **stream_out); + +// Interface functions + +static BT_HDR *make_reset(void) { + return make_command_no_params(HCI_RESET); +} + +static BT_HDR *make_read_buffer_size(void) { + return make_command_no_params(HCI_READ_BUFFER_SIZE); +} + +static BT_HDR *make_host_buffer_size(uint16_t acl_size, uint8_t sco_size, uint16_t acl_count, uint16_t sco_count) { + uint8_t *stream; + const uint8_t parameter_size = 2 + 1 + 2 + 2; // from each of the parameters + BT_HDR *packet = make_command(HCI_HOST_BUFFER_SIZE, parameter_size, &stream); + + UINT16_TO_STREAM(stream, acl_size); + UINT8_TO_STREAM(stream, sco_size); + UINT16_TO_STREAM(stream, acl_count); + UINT16_TO_STREAM(stream, sco_count); + return packet; +} + +static BT_HDR *make_read_local_version_info(void) { + return make_command_no_params(HCI_READ_LOCAL_VERSION_INFO); +} + +static BT_HDR *make_read_bd_addr(void) { + return make_command_no_params(HCI_READ_BD_ADDR); +} + +static BT_HDR *make_read_local_supported_commands(void) { + return make_command_no_params(HCI_READ_LOCAL_SUPPORTED_CMDS); +} + +static BT_HDR *make_read_local_extended_features(uint8_t page_number) { + uint8_t *stream; + const uint8_t parameter_size = 1; + BT_HDR *packet = make_command(HCI_READ_LOCAL_EXT_FEATURES, parameter_size, &stream); + + UINT8_TO_STREAM(stream, page_number); + return packet; +} + +static BT_HDR *make_write_simple_pairing_mode(uint8_t mode) { + uint8_t *stream; + const uint8_t parameter_size = 1; + BT_HDR *packet = make_command(HCI_WRITE_SIMPLE_PAIRING_MODE, parameter_size, &stream); + + UINT8_TO_STREAM(stream, mode); + return packet; +} + +static BT_HDR *make_write_secure_connections_host_support(uint8_t mode) { + uint8_t *stream; + const uint8_t parameter_size = 1; + BT_HDR *packet = make_command(HCI_WRITE_SECURE_CONNS_SUPPORT, parameter_size, &stream); + + UINT8_TO_STREAM(stream, mode); + return packet; +} + +static BT_HDR *make_set_event_mask(const bt_event_mask_t *event_mask) { + uint8_t *stream; + uint8_t parameter_size = sizeof(bt_event_mask_t); + BT_HDR *packet = make_command(HCI_SET_EVENT_MASK, parameter_size, &stream); + + ARRAY8_TO_STREAM(stream, event_mask->as_array); + return packet; +} + +static BT_HDR *make_ble_write_host_support(uint8_t supported_host, uint8_t simultaneous_host) { + uint8_t *stream; + const uint8_t parameter_size = 1 + 1; + BT_HDR *packet = make_command(HCI_WRITE_LE_HOST_SUPPORT, parameter_size, &stream); + + UINT8_TO_STREAM(stream, supported_host); + UINT8_TO_STREAM(stream, simultaneous_host); + return packet; +} + +static BT_HDR *make_ble_read_white_list_size(void) { + return make_command_no_params(HCI_BLE_READ_WHITE_LIST_SIZE); +} + +static BT_HDR *make_ble_read_buffer_size(void) { + return make_command_no_params(HCI_BLE_READ_BUFFER_SIZE); +} + +static BT_HDR *make_ble_read_supported_states(void) { + return make_command_no_params(HCI_BLE_READ_SUPPORTED_STATES); +} + +static BT_HDR *make_ble_read_local_supported_features(void) { + return make_command_no_params(HCI_BLE_READ_LOCAL_SPT_FEAT); +} + +static BT_HDR *make_ble_read_resolving_list_size(void) { + return make_command_no_params(HCI_BLE_READ_RESOLVING_LIST_SIZE); +} + +static BT_HDR *make_ble_read_suggested_default_data_length(void) { + return make_command_no_params(HCI_BLE_READ_DEFAULT_DATA_LENGTH); +} + +static BT_HDR *make_ble_set_event_mask(const bt_event_mask_t *event_mask) { + uint8_t *stream; + uint8_t parameter_size = sizeof(bt_event_mask_t); + BT_HDR *packet = make_command(HCI_BLE_SET_EVENT_MASK, parameter_size, &stream); + + ARRAY8_TO_STREAM(stream, event_mask->as_array); + return packet; +} + +// Internal functions + +static BT_HDR *make_command_no_params(uint16_t opcode) { + return make_command(opcode, 0, NULL); +} + +static BT_HDR *make_command(uint16_t opcode, size_t parameter_size, uint8_t **stream_out) { + BT_HDR *packet = make_packet(HCI_COMMAND_PREAMBLE_SIZE + parameter_size); + + uint8_t *stream = packet->data; + UINT16_TO_STREAM(stream, opcode); + UINT8_TO_STREAM(stream, parameter_size); + + if (stream_out != NULL) + *stream_out = stream; + + return packet; +} + +static BT_HDR *make_packet(size_t data_size) { + BT_HDR *ret = (BT_HDR *)buffer_allocator->alloc(sizeof(BT_HDR) + data_size); + assert(ret); + ret->event = 0; + ret->offset = 0; + ret->layer_specific = 0; + ret->len = data_size; + return ret; +} + +static const hci_packet_factory_t interface = { + make_reset, + make_read_buffer_size, + make_host_buffer_size, + make_read_local_version_info, + make_read_bd_addr, + make_read_local_supported_commands, + make_read_local_extended_features, + make_write_simple_pairing_mode, + make_write_secure_connections_host_support, + make_set_event_mask, + make_ble_write_host_support, + make_ble_read_white_list_size, + make_ble_read_buffer_size, + make_ble_read_supported_states, + make_ble_read_local_supported_features, + make_ble_read_resolving_list_size, + make_ble_read_suggested_default_data_length, + make_ble_set_event_mask +}; + +const hci_packet_factory_t *hci_packet_factory_get_interface() { + buffer_allocator = buffer_allocator_get_interface(); + return &interface; +} diff --git a/components/bt/bluedroid/hci/hci_packet_parser.c b/components/bt/bluedroid/hci/hci_packet_parser.c new file mode 100755 index 0000000000..9f9d68fab5 --- /dev/null +++ b/components/bt/bluedroid/hci/hci_packet_parser.c @@ -0,0 +1,243 @@ +/****************************************************************************** + * + * Copyright (C) 2014 Google, Inc. + * + * 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. + * + ******************************************************************************/ + +#include "bt_defs.h" + +#include "buffer_allocator.h" +#include "bt_types.h" +#include "hcimsgs.h" +#include "hci_layer.h" +#include "hci_packet_parser.h" + +static const command_opcode_t NO_OPCODE_CHECKING = 0; + +static const allocator_t *buffer_allocator; + +static uint8_t *read_command_complete_header( + BT_HDR *response, + command_opcode_t expected_opcode, + size_t minimum_bytes_after); + +static void parse_generic_command_complete(BT_HDR *response) { + read_command_complete_header(response, NO_OPCODE_CHECKING, 0 /* bytes after */); + + buffer_allocator->free(response); +} + +static void parse_read_buffer_size_response( + BT_HDR *response, + uint16_t *data_size_ptr, + uint16_t *acl_buffer_count_ptr) { + + uint8_t *stream = read_command_complete_header(response, HCI_READ_BUFFER_SIZE, 5 /* bytes after */); + assert(stream != NULL); + STREAM_TO_UINT16(*data_size_ptr, stream); + STREAM_SKIP_UINT8(stream); // skip the sco packet length + STREAM_TO_UINT16(*acl_buffer_count_ptr, stream); + + buffer_allocator->free(response); +} + +static void parse_read_local_version_info_response( + BT_HDR *response, + bt_version_t *bt_version) { + + uint8_t *stream = read_command_complete_header(response, HCI_READ_LOCAL_VERSION_INFO, 8 /* bytes after */); + assert(stream != NULL); + STREAM_TO_UINT8(bt_version->hci_version, stream); + STREAM_TO_UINT16(bt_version->hci_revision, stream); + STREAM_TO_UINT8(bt_version->lmp_version, stream); + STREAM_TO_UINT16(bt_version->manufacturer, stream); + STREAM_TO_UINT16(bt_version->lmp_subversion, stream); + + buffer_allocator->free(response); +} + +static void parse_read_bd_addr_response( + BT_HDR *response, + bt_bdaddr_t *address_ptr) { + + uint8_t *stream = read_command_complete_header(response, HCI_READ_BD_ADDR, sizeof(bt_bdaddr_t) /* bytes after */); + assert(stream != NULL); + STREAM_TO_BDADDR(address_ptr->address, stream); + + buffer_allocator->free(response); +} + +static void parse_read_local_supported_commands_response( + BT_HDR *response, + uint8_t *supported_commands_ptr, + size_t supported_commands_length) { + + uint8_t *stream = read_command_complete_header(response, HCI_READ_LOCAL_SUPPORTED_CMDS, supported_commands_length /* bytes after */); + assert(stream != NULL); + STREAM_TO_ARRAY(supported_commands_ptr, stream, (int)supported_commands_length); + + buffer_allocator->free(response); +} + +static void parse_read_local_extended_features_response( + BT_HDR *response, + uint8_t *page_number_ptr, + uint8_t *max_page_number_ptr, + bt_device_features_t *feature_pages, + size_t feature_pages_count) { + + uint8_t *stream = read_command_complete_header(response, HCI_READ_LOCAL_EXT_FEATURES, 2 + sizeof(bt_device_features_t) /* bytes after */); + if (stream != NULL) { + STREAM_TO_UINT8(*page_number_ptr, stream); + STREAM_TO_UINT8(*max_page_number_ptr, stream); + + assert(*page_number_ptr < feature_pages_count); + STREAM_TO_ARRAY(feature_pages[*page_number_ptr].as_array, stream, (int)sizeof(bt_device_features_t)); + } else { + LOG_ERROR("%s() - WARNING: READING EXTENDED FEATURES FAILED. " + "THIS MAY INDICATE A FIRMWARE/CONTROLLER ISSUE.", __func__); + } + + buffer_allocator->free(response); +} + +static void parse_ble_read_white_list_size_response( + BT_HDR *response, + uint8_t *white_list_size_ptr) { + + uint8_t *stream = read_command_complete_header(response, HCI_BLE_READ_WHITE_LIST_SIZE, 1 /* byte after */); + assert(stream != NULL); + STREAM_TO_UINT8(*white_list_size_ptr, stream); + + buffer_allocator->free(response); +} + +static void parse_ble_read_buffer_size_response( + BT_HDR *response, + uint16_t *data_size_ptr, + uint8_t *acl_buffer_count_ptr) { + + uint8_t *stream = read_command_complete_header(response, HCI_BLE_READ_BUFFER_SIZE, 3 /* bytes after */); + assert(stream != NULL); + STREAM_TO_UINT16(*data_size_ptr, stream); + STREAM_TO_UINT8(*acl_buffer_count_ptr, stream); + + buffer_allocator->free(response); +} + +static void parse_ble_read_supported_states_response( + BT_HDR *response, + uint8_t *supported_states, + size_t supported_states_size) { + + uint8_t *stream = read_command_complete_header(response, HCI_BLE_READ_SUPPORTED_STATES, supported_states_size /* bytes after */); + assert(stream != NULL); + STREAM_TO_ARRAY(supported_states, stream, (int)supported_states_size); + + buffer_allocator->free(response); +} + +static void parse_ble_read_local_supported_features_response( + BT_HDR *response, + bt_device_features_t *supported_features) { + + uint8_t *stream = read_command_complete_header(response, HCI_BLE_READ_LOCAL_SPT_FEAT, sizeof(bt_device_features_t) /* bytes after */); + assert(stream != NULL); + STREAM_TO_ARRAY(supported_features->as_array, stream, (int)sizeof(bt_device_features_t)); + + buffer_allocator->free(response); +} + +static void parse_ble_read_resolving_list_size_response( + BT_HDR *response, + uint8_t *resolving_list_size_ptr) { + + uint8_t *stream = read_command_complete_header(response, HCI_BLE_READ_RESOLVING_LIST_SIZE, 1 /* bytes after */); + STREAM_TO_UINT8(*resolving_list_size_ptr, stream); + + buffer_allocator->free(response); +} + +static void parse_ble_read_suggested_default_data_length_response( + BT_HDR *response, + uint16_t *ble_default_packet_length_ptr) { + + uint8_t *stream = read_command_complete_header(response, HCI_BLE_READ_DEFAULT_DATA_LENGTH, 2 /* bytes after */); + STREAM_TO_UINT8(*ble_default_packet_length_ptr, stream); + + buffer_allocator->free(response); +} + +// Internal functions + +static uint8_t *read_command_complete_header( + BT_HDR *response, + command_opcode_t expected_opcode, + size_t minimum_bytes_after) { + + uint8_t *stream = response->data + response->offset; + + // Read the event header + uint8_t event_code; + uint8_t parameter_length; + STREAM_TO_UINT8(event_code, stream); + STREAM_TO_UINT8(parameter_length, stream); + + const size_t parameter_bytes_we_read_here = 4; + + // Check the event header values against what we expect + assert(event_code == HCI_COMMAND_COMPLETE_EVT); + assert(parameter_length >= (parameter_bytes_we_read_here + minimum_bytes_after)); + + // Read the command complete header + command_opcode_t opcode; + uint8_t status; + STREAM_SKIP_UINT8(stream); // skip the number of hci command packets field + STREAM_TO_UINT16(opcode, stream); + + // Check the command complete header values against what we expect + if (expected_opcode != NO_OPCODE_CHECKING) { + assert(opcode == expected_opcode); + } + + // Assume the next field is the status field + STREAM_TO_UINT8(status, stream); + + if (status != HCI_SUCCESS) + return NULL; + + return stream; +} + +static const hci_packet_parser_t interface = { + parse_generic_command_complete, + parse_read_buffer_size_response, + parse_read_local_version_info_response, + parse_read_bd_addr_response, + parse_read_local_supported_commands_response, + parse_read_local_extended_features_response, + parse_ble_read_white_list_size_response, + parse_ble_read_buffer_size_response, + parse_ble_read_supported_states_response, + parse_ble_read_local_supported_features_response, + parse_ble_read_resolving_list_size_response, + parse_ble_read_suggested_default_data_length_response +}; + +const hci_packet_parser_t *hci_packet_parser_get_interface() { + buffer_allocator = buffer_allocator_get_interface(); + return &interface; +} + diff --git a/components/bt/bluedroid/hci/include/bt_vendor_lib.h b/components/bt/bluedroid/hci/include/bt_vendor_lib.h new file mode 100755 index 0000000000..3d563e1bed --- /dev/null +++ b/components/bt/bluedroid/hci/include/bt_vendor_lib.h @@ -0,0 +1,362 @@ +/****************************************************************************** + * + * Copyright (C) 2009-2012 Broadcom Corporation + * + * 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. + * + ******************************************************************************/ + +#ifndef BT_VENDOR_LIB_H +#define BT_VENDOR_LIB_H + +#include +//#include +//#include + +/** Struct types */ + + +/** Typedefs and defines */ + +/** Vendor specific operations OPCODE */ +typedef enum { +/* [operation] + * Power on or off the BT Controller. + * [input param] + * A pointer to int type with content of bt_vendor_power_state_t. + * Typecasting conversion: (int *) param. + * [return] + * 0 - default, don't care. + * [callback] + * None. + */ + BT_VND_OP_POWER_CTRL, + +/* [operation] + * Perform any vendor specific initialization or configuration + * on the BT Controller. This is called before stack initialization. + * [input param] + * None. + * [return] + * 0 - default, don't care. + * [callback] + * Must call fwcfg_cb to notify the stack of the completion of vendor + * specific initialization once it has been done. + */ + BT_VND_OP_FW_CFG, + +/* [operation] + * Perform any vendor specific SCO/PCM configuration on the BT Controller. + * This is called after stack initialization. + * [input param] + * None. + * [return] + * 0 - default, don't care. + * [callback] + * Must call scocfg_cb to notify the stack of the completion of vendor + * specific SCO configuration once it has been done. + */ + BT_VND_OP_SCO_CFG, + +/* [operation] + * Open UART port on where the BT Controller is attached. + * This is called before stack initialization. + * [input param] + * A pointer to int array type for open file descriptors. + * The mapping of HCI channel to fd slot in the int array is given in + * bt_vendor_hci_channels_t. + * And, it requires the vendor lib to fill up the content before returning + * the call. + * Typecasting conversion: (int (*)[]) param. + * [return] + * Numbers of opened file descriptors. + * Valid number: + * 1 - CMD/EVT/ACL-In/ACL-Out via the same fd (e.g. UART) + * 2 - CMD/EVT on one fd, and ACL-In/ACL-Out on the other fd + * 4 - CMD, EVT, ACL-In, ACL-Out are on their individual fd + * [callback] + * None. + */ + BT_VND_OP_USERIAL_OPEN, + +/* [operation] + * Close the previously opened UART port. + * [input param] + * None. + * [return] + * 0 - default, don't care. + * [callback] + * None. + */ + BT_VND_OP_USERIAL_CLOSE, + +/* [operation] + * Get the LPM idle timeout in milliseconds. + * The stack uses this information to launch a timer delay before it + * attempts to de-assert LPM WAKE signal once downstream HCI packet + * has been delivered. + * [input param] + * A pointer to uint32_t type which is passed in by the stack. And, it + * requires the vendor lib to fill up the content before returning + * the call. + * Typecasting conversion: (uint32_t *) param. + * [return] + * 0 - default, don't care. + * [callback] + * None. + */ + BT_VND_OP_GET_LPM_IDLE_TIMEOUT, + +/* [operation] + * Enable or disable LPM mode on BT Controller. + * [input param] + * A pointer to uint8_t type with content of bt_vendor_lpm_mode_t. + * Typecasting conversion: (uint8_t *) param. + * [return] + * 0 - default, don't care. + * [callback] + * Must call lpm_cb to notify the stack of the completion of LPM + * disable/enable process once it has been done. + */ + BT_VND_OP_LPM_SET_MODE, + +/* [operation] + * Assert or Deassert LPM WAKE on BT Controller. + * [input param] + * A pointer to uint8_t type with content of bt_vendor_lpm_wake_state_t. + * Typecasting conversion: (uint8_t *) param. + * [return] + * 0 - default, don't care. + * [callback] + * None. + */ + BT_VND_OP_LPM_WAKE_SET_STATE, + +/* [operation] + * Perform any vendor specific commands related to audio state changes. + * [input param] + * a pointer to bt_vendor_op_audio_state_t indicating what audio state is + * set. + * [return] + * 0 - default, don't care. + * [callback] + * None. + */ + BT_VND_OP_SET_AUDIO_STATE, + +/* [operation] + * The epilog call to the vendor module so that it can perform any + * vendor-specific processes (e.g. send a HCI_RESET to BT Controller) + * before the caller calls for cleanup(). + * [input param] + * None. + * [return] + * 0 - default, don't care. + * [callback] + * Must call epilog_cb to notify the stack of the completion of vendor + * specific epilog process once it has been done. + */ + BT_VND_OP_EPILOG, +} bt_vendor_opcode_t; + +/** Power on/off control states */ +typedef enum { + BT_VND_PWR_OFF, + BT_VND_PWR_ON, +} bt_vendor_power_state_t; + +/** Define HCI channel identifier in the file descriptors array + used in BT_VND_OP_USERIAL_OPEN operation. + */ +typedef enum { + CH_CMD, // HCI Command channel + CH_EVT, // HCI Event channel + CH_ACL_OUT, // HCI ACL downstream channel + CH_ACL_IN, // HCI ACL upstream channel + + CH_MAX // Total channels +} bt_vendor_hci_channels_t; + +/** LPM disable/enable request */ +typedef enum { + BT_VND_LPM_DISABLE, + BT_VND_LPM_ENABLE, +} bt_vendor_lpm_mode_t; + +/** LPM WAKE set state request */ +typedef enum { + BT_VND_LPM_WAKE_ASSERT, + BT_VND_LPM_WAKE_DEASSERT, +} bt_vendor_lpm_wake_state_t; + +/** Callback result values */ +typedef enum { + BT_VND_OP_RESULT_SUCCESS, + BT_VND_OP_RESULT_FAIL, +} bt_vendor_op_result_t; + +/** audio (SCO) state changes triggering VS commands for configuration */ +typedef struct { + uint16_t handle; + uint16_t peer_codec; + uint16_t state; +} bt_vendor_op_audio_state_t; + +/* + * Bluetooth Host/Controller Vendor callback structure. + */ + +/* vendor initialization/configuration callback */ +typedef void (*cfg_result_cb)(bt_vendor_op_result_t result); + +/* datapath buffer allocation callback (callout) + * + * Vendor lib needs to request a buffer through the alloc callout function + * from HCI lib if the buffer is for constructing a HCI Command packet which + * will be sent through xmit_cb to BT Controller. + * + * For each buffer allocation, the requested size needs to be big enough to + * accommodate the below header plus a complete HCI packet -- + * typedef struct + * { + * uint16_t event; + * uint16_t len; + * uint16_t offset; + * uint16_t layer_specific; + * } HC_BT_HDR; + * + * HCI lib returns a pointer to the buffer where Vendor lib should use to + * construct a HCI command packet as below format: + * + * -------------------------------------------- + * | HC_BT_HDR | HCI command | + * -------------------------------------------- + * where + * HC_BT_HDR.event = 0x2000; + * HC_BT_HDR.len = Length of HCI command; + * HC_BT_HDR.offset = 0; + * HC_BT_HDR.layer_specific = 0; + * + * For example, a HCI_RESET Command will be formed as + * ------------------------ + * | HC_BT_HDR |03|0c|00| + * ------------------------ + * with + * HC_BT_HDR.event = 0x2000; + * HC_BT_HDR.len = 3; + * HC_BT_HDR.offset = 0; + * HC_BT_HDR.layer_specific = 0; + */ +typedef void* (*malloc_cb)(int size); + +/* datapath buffer deallocation callback (callout) */ +typedef void (*mdealloc_cb)(void *p_buf); + +/* define callback of the cmd_xmit_cb + * + * The callback function which HCI lib will call with the return of command + * complete packet. Vendor lib is responsible for releasing the buffer passed + * in at the p_mem parameter by calling dealloc callout function. + */ +typedef void (*tINT_CMD_CBACK)(void *p_mem); + +/* hci command packet transmit callback (callout) + * + * Vendor lib calls xmit_cb callout function in order to send a HCI Command + * packet to BT Controller. The buffer carrying HCI Command packet content + * needs to be first allocated through the alloc callout function. + * HCI lib will release the buffer for Vendor lib once it has delivered the + * packet content to BT Controller. + * + * Vendor lib needs also provide a callback function (p_cback) which HCI lib + * will call with the return of command complete packet. + * + * The opcode parameter gives the HCI OpCode (combination of OGF and OCF) of + * HCI Command packet. For example, opcode = 0x0c03 for the HCI_RESET command + * packet. + */ +typedef uint8_t (*cmd_xmit_cb)(uint16_t opcode, void *p_buf, tINT_CMD_CBACK p_cback); + +typedef struct { + /** set to sizeof(bt_vendor_callbacks_t) */ + size_t size; + + /* + * Callback and callout functions have implemented in HCI libray + * (libbt-hci.so). + */ + + /* notifies caller result of firmware configuration request */ + cfg_result_cb fwcfg_cb; + + /* notifies caller result of sco configuration request */ + cfg_result_cb scocfg_cb; + + /* notifies caller result of lpm enable/disable */ + cfg_result_cb lpm_cb; + + /* notifies the result of codec setting */ + cfg_result_cb audio_state_cb; + + /* buffer allocation request */ + malloc_cb alloc; + + /* buffer deallocation request */ + mdealloc_cb dealloc; + + /* hci command packet transmit request */ + cmd_xmit_cb xmit_cb; + + /* notifies caller completion of epilog process */ + cfg_result_cb epilog_cb; +} bt_vendor_callbacks_t; + +/* + * Bluetooth Host/Controller VENDOR Interface + */ +typedef struct { + /** Set to sizeof(bt_vndor_interface_t) */ + size_t size; + + /* + * Functions need to be implemented in Vendor libray (libbt-vendor.so). + */ + + /** + * Caller will open the interface and pass in the callback routines + * to the implemenation of this interface. + */ + int (*init)(const bt_vendor_callbacks_t* p_cb, unsigned char *local_bdaddr); + + /** Vendor specific operations */ + int (*op)(bt_vendor_opcode_t opcode, void *param); + + /** Closes the interface */ + void (*cleanup)(void); +} bt_vendor_interface_t; + + +/* + * External shared lib functions/data + */ + +/* Entry point of DLib -- + * Vendor library needs to implement the body of bt_vendor_interface_t + * structure and uses the below name as the variable name. HCI library + * will use this symbol name to get address of the object through the + * dlsym call. + */ +//extern const bt_vendor_interface_t BLUETOOTH_VENDOR_LIB_INTERFACE; + +#endif /* BT_VENDOR_LIB_H */ + diff --git a/components/bt/bluedroid/hci/include/buffer_allocator.h b/components/bt/bluedroid/hci/include/buffer_allocator.h new file mode 100755 index 0000000000..9dd7ba7c45 --- /dev/null +++ b/components/bt/bluedroid/hci/include/buffer_allocator.h @@ -0,0 +1,25 @@ +/****************************************************************************** + * + * Copyright (C) 2014 Google, Inc. + * + * 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. + * + ******************************************************************************/ + +#ifndef _BUFFER_ALLOCATOR_H_ + +#include "allocator.h" + +const allocator_t *buffer_allocator_get_interface(); + +#endif /*_BUFFER_ALLOCATOR_H_*/ diff --git a/components/bt/bluedroid/hci/include/hci_hal.h b/components/bt/bluedroid/hci/include/hci_hal.h new file mode 100755 index 0000000000..6e8b1a66af --- /dev/null +++ b/components/bt/bluedroid/hci/include/hci_hal.h @@ -0,0 +1,85 @@ +/****************************************************************************** + * + * Copyright (C) 2014 Google, Inc. + * + * 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. + * + ******************************************************************************/ + +#ifndef _HCI_HAL_H_ +#define _HCI_HAL_H_ + +#include +#include + +#include "bt_types.h" + +typedef enum { + DATA_TYPE_COMMAND = 1, + DATA_TYPE_ACL = 2, + DATA_TYPE_SCO = 3, + DATA_TYPE_EVENT = 4 +} serial_data_type_t; + +typedef void (*packet_ready_cb)(BT_HDR *packet); + +typedef struct { + // Called when the HAL detects inbound data. + // Data |type| may be ACL, SCO, or EVENT. + // Executes in the context of the thread supplied to |init|. + packet_ready_cb packet_ready; + + /* + // Called when the HAL detects inbound astronauts named Dave. + // HAL will deny all requests to open the pod bay doors after this. + dave_ready_cb dave_ready; + */ +} hci_hal_callbacks_t; + +typedef struct hci_hal_t { + // Initialize the HAL, with |upper_callbacks| and |upper_thread| to run in the context of. + //bool (*init)(const hci_hal_callbacks_t *upper_callbacks); + + // Connect to the underlying hardware, and let data start flowing. + bool (*open)(const hci_hal_callbacks_t *upper_callbacks); + // Disconnect from the underlying hardware, and close the HAL. + // "Daisy, Daisy..." + void (*close)(void); + + // Retrieve up to |max_size| bytes for ACL, SCO, or EVENT data packets into + // |buffer|, blocking until max_size bytes read if |block| is true. + // Only guaranteed to be correct in the context of a data_ready callback + // of the corresponding type. + //size_t (*read_data)(serial_data_type_t type, uint8_t *buffer, size_t max_size); + // The upper layer must call this to notify the HAL that it has finished + // reading a packet of the specified |type|. Underlying implementations that + // use shared channels for multiple data types depend on this to know when + // to reinterpret the data stream. + //void (*packet_finished)(serial_data_type_t type); + // Transmit COMMAND, ACL, or SCO data packets. + // |data| may not be NULL. |length| must be greater than zero. + // + // IMPORTANT NOTE: + // Depending on the underlying implementation, the byte right + // before the beginning of |data| may be borrowed during this call + // and then restored to its original value. + // This is safe in the bluetooth context, because there is always a buffer + // header that prefixes data you're sending. + uint16_t (*transmit_data)(serial_data_type_t type, uint8_t *data, uint16_t length); +} hci_hal_t; + + +// Gets the correct hal implementation, as compiled for. +const hci_hal_t *hci_hal_h4_get_interface(void); + +#endif /* _HCI_HAL_H */ diff --git a/components/bt/bluedroid/hci/include/hci_internals.h b/components/bt/bluedroid/hci/include/hci_internals.h new file mode 100755 index 0000000000..41c792cf3c --- /dev/null +++ b/components/bt/bluedroid/hci/include/hci_internals.h @@ -0,0 +1,31 @@ +/****************************************************************************** + * + * Copyright (C) 2014 Google, Inc. + * + * 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. + * + ******************************************************************************/ + +#ifndef _HCI_INTERNALS_H_ +#define _HCI_INTERNALS_H_ + +// 2 bytes for opcode, 1 byte for parameter length (Volume 2, Part E, 5.4.1) +#define HCI_COMMAND_PREAMBLE_SIZE 3 +// 2 bytes for handle, 2 bytes for data length (Volume 2, Part E, 5.4.2) +#define HCI_ACL_PREAMBLE_SIZE 4 +// 2 bytes for handle, 1 byte for data length (Volume 2, Part E, 5.4.3) +#define HCI_SCO_PREAMBLE_SIZE 3 +// 1 byte for event code, 1 byte for parameter length (Volume 2, Part E, 5.4.4) +#define HCI_EVENT_PREAMBLE_SIZE 2 + +#endif /* _HCI_INTERNALS_H_ */ diff --git a/components/bt/bluedroid/hci/include/hci_layer.h b/components/bt/bluedroid/hci/include/hci_layer.h new file mode 100755 index 0000000000..7c37391391 --- /dev/null +++ b/components/bt/bluedroid/hci/include/hci_layer.h @@ -0,0 +1,101 @@ +/****************************************************************************** + * + * Copyright (C) 2014 Google, Inc. + * + * 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. + * + ******************************************************************************/ + +#ifndef _HCI_LAYER_H_ +#define _HCI_LAYER_H_ + +#include "bt_types.h" +#include "allocator.h" +#include "fixed_queue.h" +#include "osi.h" + +///// LEGACY DEFINITIONS ///// + +/* Message event mask across Host/Controller lib and stack */ +#define MSG_EVT_MASK 0xFF00 /* eq. BT_EVT_MASK */ +#define MSG_SUB_EVT_MASK 0x00FF /* eq. BT_SUB_EVT_MASK */ + +/* Message event ID passed from Host/Controller lib to stack */ +#define MSG_HC_TO_STACK_HCI_ERR 0x1300 /* eq. BT_EVT_TO_BTU_HCIT_ERR */ +#define MSG_HC_TO_STACK_HCI_ACL 0x1100 /* eq. BT_EVT_TO_BTU_HCI_ACL */ +#define MSG_HC_TO_STACK_HCI_SCO 0x1200 /* eq. BT_EVT_TO_BTU_HCI_SCO */ +#define MSG_HC_TO_STACK_HCI_EVT 0x1000 /* eq. BT_EVT_TO_BTU_HCI_EVT */ +#define MSG_HC_TO_STACK_L2C_SEG_XMIT 0x1900 /* eq. BT_EVT_TO_BTU_L2C_SEG_XMIT */ + +/* Message event ID passed from stack to vendor lib */ +#define MSG_STACK_TO_HC_HCI_ACL 0x2100 /* eq. BT_EVT_TO_LM_HCI_ACL */ +#define MSG_STACK_TO_HC_HCI_SCO 0x2200 /* eq. BT_EVT_TO_LM_HCI_SCO */ +#define MSG_STACK_TO_HC_HCI_CMD 0x2000 /* eq. BT_EVT_TO_LM_HCI_CMD */ + +/* Local Bluetooth Controller ID for BR/EDR */ +#define LOCAL_BR_EDR_CONTROLLER_ID 0 + +///// END LEGACY DEFINITIONS ///// + +typedef struct hci_hal_t hci_hal_t; +//typedef struct btsnoop_t btsnoop_t; +typedef struct controller_t controller_t; +//typedef struct hci_inject_t hci_inject_t; +typedef struct packet_fragmenter_t packet_fragmenter_t; +//typedef struct vendor_t vendor_t; +//typedef struct low_power_manager_t low_power_manager_t; + +//typedef unsigned char * bdaddr_t; +typedef uint16_t command_opcode_t; + +/* +typedef enum { + LPM_DISABLE, + LPM_ENABLE, + LPM_WAKE_ASSERT, + LPM_WAKE_DEASSERT +} low_power_command_t; +*/ + +typedef void (*command_complete_cb)(BT_HDR *response, void *context); +typedef void (*command_status_cb)(uint8_t status, BT_HDR *command, void *context); + +typedef struct hci_t { + // Send a low power command, if supported and the low power manager is enabled. + //void (*send_low_power_command)(low_power_command_t command); + + // Do the postload sequence (call after the rest of the BT stack initializes). + void (*do_postload)(void); + + // Set the queue to receive ACL data in + void (*set_data_queue)(fixed_queue_t *queue); + + // Send a command through the HCI layer + void (*transmit_command)( + BT_HDR *command, + command_complete_cb complete_callback, + command_status_cb status_cb, + void *context + ); + + // Send some data downward through the HCI layer + void (*transmit_downward)(uint16_t type, void *data); +} hci_t; + +const hci_t *hci_layer_get_interface(); + +int hci_start_up(void); +void hci_shut_down(void); + + +#endif /* _HCI_LAYER_H_ */ diff --git a/components/bt/bluedroid/hci/include/hci_packet_factory.h b/components/bt/bluedroid/hci/include/hci_packet_factory.h new file mode 100755 index 0000000000..3dd4197a27 --- /dev/null +++ b/components/bt/bluedroid/hci/include/hci_packet_factory.h @@ -0,0 +1,48 @@ +/****************************************************************************** + * + * Copyright (C) 2014 Google, Inc. + * + * 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. + * + ******************************************************************************/ + +#ifndef _HCI_PACKET_FACTORY_H_ +#define _HCI_PACKET_FACTORY_H_ + +#include "bt_types.h" +#include "event_mask.h" + +typedef struct { + BT_HDR *(*make_reset)(void); + BT_HDR *(*make_read_buffer_size)(void); + BT_HDR *(*make_host_buffer_size)(uint16_t acl_size, uint8_t sco_size, uint16_t acl_count, uint16_t sco_count); + BT_HDR *(*make_read_local_version_info)(void); + BT_HDR *(*make_read_bd_addr)(void); + BT_HDR *(*make_read_local_supported_commands)(void); + BT_HDR *(*make_read_local_extended_features)(uint8_t page_number); + BT_HDR *(*make_write_simple_pairing_mode)(uint8_t mode); + BT_HDR *(*make_write_secure_connections_host_support)(uint8_t mode); + BT_HDR *(*make_set_event_mask)(const bt_event_mask_t *event_mask); + BT_HDR *(*make_ble_write_host_support)(uint8_t supported_host, uint8_t simultaneous_host); + BT_HDR *(*make_ble_read_white_list_size)(void); + BT_HDR *(*make_ble_read_buffer_size)(void); + BT_HDR *(*make_ble_read_supported_states)(void); + BT_HDR *(*make_ble_read_local_supported_features)(void); + BT_HDR *(*make_ble_read_resolving_list_size)(void); + BT_HDR *(*make_ble_read_suggested_default_data_length)(void); + BT_HDR *(*make_ble_set_event_mask)(const bt_event_mask_t *event_mask); +} hci_packet_factory_t; + +const hci_packet_factory_t *hci_packet_factory_get_interface(); + +#endif /*_HCI_PACKET_FACTORY_H_*/ diff --git a/components/bt/bluedroid/hci/include/hci_packet_parser.h b/components/bt/bluedroid/hci/include/hci_packet_parser.h new file mode 100755 index 0000000000..000397295c --- /dev/null +++ b/components/bt/bluedroid/hci/include/hci_packet_parser.h @@ -0,0 +1,99 @@ +/****************************************************************************** + * + * Copyright (C) 2014 Google, Inc. + * + * 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. + * + ******************************************************************************/ + +#ifndef _HCI_PACKET_PARSER_H_ +#define _HCI_PACKET_PARSER_H_ + +#include + +#include "allocator.h" +#include "bdaddr.h" +#include "bt_types.h" +#include "device_features.h" +//#include "features.h" +#include "version.h" + +typedef struct { + void (*parse_generic_command_complete)(BT_HDR *response); + + void (*parse_read_buffer_size_response)( + BT_HDR *response, + uint16_t *data_size_ptr, + uint16_t *acl_buffer_count_ptr + ); + + void (*parse_read_local_version_info_response)( + BT_HDR *response, + bt_version_t *bt_version_ptr + ); + + void (*parse_read_bd_addr_response)( + BT_HDR *response, + bt_bdaddr_t *address_ptr + ); + + void (*parse_read_local_supported_commands_response)( + BT_HDR *response, + uint8_t *supported_commands_ptr, + size_t supported_commands_length + ); + + void (*parse_read_local_extended_features_response)( + BT_HDR *response, + uint8_t *page_number_ptr, + uint8_t *max_page_number_ptr, + bt_device_features_t *feature_pages, + size_t feature_pages_count + ); + + void (*parse_ble_read_white_list_size_response)( + BT_HDR *response, + uint8_t *white_list_size_ptr + ); + + void (*parse_ble_read_buffer_size_response)( + BT_HDR *response, + uint16_t *data_size_ptr, + uint8_t *acl_buffer_count_ptr + ); + + void (*parse_ble_read_supported_states_response)( + BT_HDR *response, + uint8_t *supported_states, + size_t supported_states_size + ); + + void (*parse_ble_read_local_supported_features_response)( + BT_HDR *response, + bt_device_features_t *supported_features + ); + + void (*parse_ble_read_resolving_list_size_response) ( + BT_HDR *response, + uint8_t *resolving_list_size_ptr + ); + + void (*parse_ble_read_suggested_default_data_length_response)( + BT_HDR *response, + uint16_t *ble_default_packet_length_ptr + ); +} hci_packet_parser_t; + +const hci_packet_parser_t *hci_packet_parser_get_interface(); + +#endif /*_HCI_PACKET_PARSER_H_*/ diff --git a/components/bt/bluedroid/hci/include/packet_fragmenter.h b/components/bt/bluedroid/hci/include/packet_fragmenter.h new file mode 100755 index 0000000000..a6ba15c0c3 --- /dev/null +++ b/components/bt/bluedroid/hci/include/packet_fragmenter.h @@ -0,0 +1,62 @@ +/****************************************************************************** + * + * Copyright (C) 2014 Google, Inc. + * + * 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. + * + ******************************************************************************/ + +#ifndef _PACKET_FRAGMENTER_H_ +#define _PACKET_FRAGMENTER_H_ + +#include "allocator.h" +#include "bt_types.h" +#include "hci_layer.h" + +typedef void (*transmit_finished_cb)(BT_HDR *packet, bool all_fragments_sent); +typedef void (*packet_reassembled_cb)(BT_HDR *packet); +typedef void (*packet_fragmented_cb)(BT_HDR *packet, bool send_transmit_finished); + +typedef struct { + // Called for every packet fragment. + packet_fragmented_cb fragmented; + + // Called for every completely reassembled packet. + packet_reassembled_cb reassembled; + + // Called when the fragmenter finishes sending all requested fragments, + // but the packet has not been entirely sent. + transmit_finished_cb transmit_finished; +} packet_fragmenter_callbacks_t; + +typedef struct packet_fragmenter_t { + // Initialize the fragmenter, specifying the |result_callbacks|. + void (*init)(const packet_fragmenter_callbacks_t *result_callbacks); + + // Release all resources associated with the fragmenter. + void (*cleanup)(void); + + // CHeck if Current fragmenter is ongoing + BT_HDR *(*fragment_current_packet)(void); + + // Fragments |packet| if necessary and hands off everything to the fragmented callback. + void (*fragment_and_dispatch)(BT_HDR *packet); + // If |packet| is a complete packet, forwards to the reassembled callback. Otherwise + // holds onto it until all fragments arrive, at which point the reassembled callback is called + // with the reassembled data. + void (*reassemble_and_dispatch)(BT_HDR *packet); +} packet_fragmenter_t; + +const packet_fragmenter_t *packet_fragmenter_get_interface(); + +#endif /* _PACKET_FRAGMENTER_H_ */ diff --git a/components/bt/bluedroid/hci/packet_fragmenter.c b/components/bt/bluedroid/hci/packet_fragmenter.c new file mode 100755 index 0000000000..e9e0d95480 --- /dev/null +++ b/components/bt/bluedroid/hci/packet_fragmenter.c @@ -0,0 +1,225 @@ +/****************************************************************************** + * + * Copyright (C) 2014 Google, Inc. + * + * 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. + * + ******************************************************************************/ +#include +#include "bt_trace.h" +#include "bt_defs.h" +#include "controller.h" +#include "buffer_allocator.h" +#include "hci_internals.h" +#include "hci_layer.h" +#include "packet_fragmenter.h" + +#include "hash_map.h" +#include "hash_functions.h" + + + +#define APPLY_CONTINUATION_FLAG(handle) (((handle) & 0xCFFF) | 0x1000) +#define APPLY_START_FLAG(handle) (((handle) & 0xCFFF) | 0x2000) +#define SUB_EVENT(event) ((event) & MSG_SUB_EVT_MASK) +#define GET_BOUNDARY_FLAG(handle) (((handle) >> 12) & 0x0003) + +#define HANDLE_MASK 0x0FFF +#define START_PACKET_BOUNDARY 2 +#define CONTINUATION_PACKET_BOUNDARY 1 +#define L2CAP_HEADER_SIZE 4 + +// TODO(zachoverflow): find good value for this +#define NUMBER_OF_BUCKETS 42 + +// Our interface and callbacks +static const packet_fragmenter_t interface; +static const allocator_t *buffer_allocator; +static const controller_t *controller; +static const packet_fragmenter_callbacks_t *callbacks; +static hash_map_t *partial_packets; +static BT_HDR *current_fragment_packet; + +static void init(const packet_fragmenter_callbacks_t *result_callbacks) { + current_fragment_packet = NULL; + callbacks = result_callbacks; + partial_packets = hash_map_new(NUMBER_OF_BUCKETS, hash_function_naive, NULL, NULL, NULL); +} + +static void cleanup() { + if (partial_packets) + hash_map_free(partial_packets); +} + +static BT_HDR *fragment_get_current_packet() { + return current_fragment_packet; +} + +static void fragment_and_dispatch(BT_HDR *packet) { + uint16_t continuation_handle, current_pkt_size; + uint16_t max_data_size, max_packet_size, remaining_length; + uint16_t event = packet->event & MSG_EVT_MASK; + uint8_t *stream = packet->data + packet->offset; + + assert(packet != NULL); + + // We only fragment ACL packets + if (event != MSG_STACK_TO_HC_HCI_ACL) { + callbacks->fragmented(packet, true); + return; + } + + max_data_size = + SUB_EVENT(packet->event) == LOCAL_BR_EDR_CONTROLLER_ID ? + controller->get_acl_data_size_classic() : + controller->get_acl_data_size_ble(); + + max_packet_size = max_data_size + HCI_ACL_PREAMBLE_SIZE; + remaining_length = packet->len; + + STREAM_TO_UINT16(continuation_handle, stream); + continuation_handle = APPLY_CONTINUATION_FLAG(continuation_handle); + if (remaining_length > max_packet_size) { + current_fragment_packet = packet; + UINT16_TO_STREAM(stream, max_packet_size); + packet->len = max_packet_size; + callbacks->fragmented(packet, false); + packet->offset += max_data_size; + remaining_length -= max_data_size; + packet->len = remaining_length; + + // Write the ACL header for the next fragment + stream = packet->data + packet->offset; + UINT16_TO_STREAM(stream, continuation_handle); + UINT16_TO_STREAM(stream, remaining_length - HCI_ACL_PREAMBLE_SIZE); + + // Apparently L2CAP can set layer_specific to a max number of segments to transmit + if (packet->layer_specific) { + packet->layer_specific--; + if (packet->layer_specific == 0) { + packet->event = MSG_HC_TO_STACK_L2C_SEG_XMIT; + callbacks->transmit_finished(packet, false); + return; + } + } + } else { + current_fragment_packet = NULL; + callbacks->fragmented(packet, true); + } +} + +static void reassemble_and_dispatch(BT_HDR *packet) { + if ((packet->event & MSG_EVT_MASK) == MSG_HC_TO_STACK_HCI_ACL) { + uint8_t *stream = packet->data + packet->offset; + uint16_t handle; + uint16_t l2cap_length; + uint16_t acl_length; + uint8_t boundary_flag; + BT_HDR *partial_packet; + + STREAM_TO_UINT16(handle, stream); + STREAM_TO_UINT16(acl_length, stream); + STREAM_TO_UINT16(l2cap_length, stream); + + assert(acl_length == packet->len - HCI_ACL_PREAMBLE_SIZE); + + boundary_flag = GET_BOUNDARY_FLAG(handle); + handle = handle & HANDLE_MASK; + + partial_packet = (BT_HDR *)hash_map_get(partial_packets, (void *)(uintptr_t)handle); + + if (boundary_flag == START_PACKET_BOUNDARY) { + uint16_t full_length; + if (partial_packet) { + LOG_WARN("%s found unfinished packet for handle with start packet. Dropping old.", __func__); + + hash_map_erase(partial_packets, (void *)(uintptr_t)handle); + buffer_allocator->free(partial_packet); + } + + full_length = l2cap_length + L2CAP_HEADER_SIZE + HCI_ACL_PREAMBLE_SIZE; + if (full_length <= packet->len) { + if (full_length < packet->len) + LOG_WARN("%s found l2cap full length %d less than the hci length %d.", __func__, l2cap_length, packet->len); + + callbacks->reassembled(packet); + return; + } + + partial_packet = (BT_HDR *)buffer_allocator->alloc(full_length + sizeof(BT_HDR)); + partial_packet->event = packet->event; + partial_packet->len = full_length; + partial_packet->offset = packet->len; + + memcpy(partial_packet->data, packet->data, packet->len); + + // Update the ACL data size to indicate the full expected length + stream = partial_packet->data; + STREAM_SKIP_UINT16(stream); // skip the handle + UINT16_TO_STREAM(stream, full_length - HCI_ACL_PREAMBLE_SIZE); + + hash_map_set(partial_packets, (void *)(uintptr_t)handle, partial_packet); + // Free the old packet buffer, since we don't need it anymore + buffer_allocator->free(packet); + } else { + uint16_t projected_offset; + if (!partial_packet) { + LOG_WARN("%s got continuation for unknown packet. Dropping it.", __func__); + buffer_allocator->free(packet); + return; + } + + packet->offset = HCI_ACL_PREAMBLE_SIZE; + projected_offset = partial_packet->offset + (packet->len - HCI_ACL_PREAMBLE_SIZE); + if (projected_offset > partial_packet->len) { // len stores the expected length + LOG_WARN("%s got packet which would exceed expected length of %d. Truncating.", __func__, partial_packet->len); + packet->len = partial_packet->len - partial_packet->offset; + projected_offset = partial_packet->len; + } + + memcpy( + partial_packet->data + partial_packet->offset, + packet->data + packet->offset, + packet->len - packet->offset + ); + + // Free the old packet buffer, since we don't need it anymore + buffer_allocator->free(packet); + partial_packet->offset = projected_offset; + + if (partial_packet->offset == partial_packet->len) { + hash_map_erase(partial_packets, (void *)(uintptr_t)handle); + partial_packet->offset = 0; + callbacks->reassembled(partial_packet); + } + } + } else { + callbacks->reassembled(packet); + } +} + +static const packet_fragmenter_t interface = { + init, + cleanup, + + fragment_get_current_packet, + fragment_and_dispatch, + reassemble_and_dispatch +}; + +const packet_fragmenter_t *packet_fragmenter_get_interface() { + controller = controller_get_interface(); + buffer_allocator = buffer_allocator_get_interface(); + return &interface; +} + diff --git a/components/bt/bluedroid/include/bt_common_types.h b/components/bt/bluedroid/include/bt_common_types.h new file mode 100755 index 0000000000..87a4d7123a --- /dev/null +++ b/components/bt/bluedroid/include/bt_common_types.h @@ -0,0 +1,31 @@ + + + + +#ifndef _BT_COMMON_TYPES_H_ +#define _BT_COMMON_TYPES_H_ + +#include "bt_defs.h" +#include "thread.h" + + +extern xQueueHandle xBtaApp1Queue; +extern xTaskHandle xBtaApp1TaskHandle; + +typedef struct { + uint8_t client_if; + uint8_t filt_index; + uint8_t advertiser_state; + uint8_t advertiser_info_present; + uint8_t addr_type; + uint8_t tx_power; + int8_t rssi_value; + uint16_t time_stamp; + bt_bdaddr_t bd_addr; + uint8_t adv_pkt_len; + uint8_t *p_adv_pkt_data; + uint8_t scan_rsp_len; + uint8_t *p_scan_rsp_data; +} btgatt_track_adv_info_t; + +#endif diff --git a/components/bt/bluedroid/include/bt_defs.h b/components/bt/bluedroid/include/bt_defs.h new file mode 100755 index 0000000000..283270ba9e --- /dev/null +++ b/components/bt/bluedroid/include/bt_defs.h @@ -0,0 +1,90 @@ +/** + * bt_defs.h Defines useful API for whole Bluedroid + * + */ +#ifndef _BT_DEFS_H_ +#define _BT_DEFS_H_ + +#include +#include +#include "bt_trace.h" + +#include "osi_arch.h" + +#define UNUSED(x) (void)(x) + +#ifndef SIZE_MAX +#define SIZE_MAX 128 +#endif +/*Timer Related Defination*/ + +#define alarm_timer_t uint32_t +#define alarm_timer_setfn(timer, cb, data) \ +do { \ +} while (0) +#define alarm_timer_arm(timer, to, periodic) \ +do { \ +} while (0) +#define alarm_timer_disarm(timer) \ +do { \ +} while (0) +#define alarm_timer_now() (0) + + +/*Thread and locker related defination*/ +#define RTOS_SUPPORT +#ifdef RTOS_SUPPORT +#define pthread_mutex_t osi_mutex_t +#define pthread_mutex_init(mutex, a) osi_mutex_new(mutex) +#define pthread_mutex_destroy(mutex) osi_mutex_free(mutex) +#define pthread_mutex_lock osi_mutex_lock +#define pthread_mutex_unlock osi_mutex_unlock +#else +#define pthread_mutex_t uint8_t +#define pthread_mutex_init(x1, x2) +#define pthread_mutex_destroy(mutex) +#define pthread_mutex_lock(mutex) +#define pthread_mutex_unlock(mutex) +#endif + + +/*Bluetooth Address*/ +typedef struct { + uint8_t address[6]; +} __attribute__ ((__packed__)) bt_bdaddr_t; + + +#ifndef CPU_LITTLE_ENDIAN +#define CPU_LITTLE_ENDIAN +#endif + +inline uint16_t swap_byte_16(uint16_t x) { + return (((x & 0x00ffU) << 8) | + ((x & 0xff00U) >> 8)); +} + +inline uint32_t swap_byte_32(uint32_t x) { + return (((x & 0x000000ffUL) << 24) | + ((x & 0x0000ff00UL) << 8) | + ((x & 0x00ff0000UL) >> 8) | + ((x & 0xff000000UL) >> 24)); +} + +inline uint16_t ntohs(uint16_t x) { +#ifdef CPU_LITTLE_ENDIAN + return swap_byte_16(x); +#else + return x; +#endif +} + +typedef struct vhci_host_callback { + void (*notify_host_send_available)(void); + int (*notify_host_recv)(uint8_t *data, uint16_t len); +} vhci_host_callback_t; + +bool API_vhci_host_check_send_available(void); +void API_vhci_host_send_packet(uint8_t *data, uint16_t len); +void API_vhci_host_register_callback(const vhci_host_callback_t *callback); + +#endif /* _BT_DEFS_H_ */ diff --git a/components/bt/bluedroid/include/bt_target.h b/components/bt/bluedroid/include/bt_target.h new file mode 100755 index 0000000000..9af8a2b760 --- /dev/null +++ b/components/bt/bluedroid/include/bt_target.h @@ -0,0 +1,1769 @@ +/****************************************************************************** + * + * Copyright (c) 2014 The Android Open Source Project + * Copyright (C) 1999-2012 Broadcom Corporation + * + * 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. + * + ******************************************************************************/ + +#ifndef BT_TARGET_H +#define BT_TARGET_H + +#ifndef BUILDCFG +#define BUILDCFG +#endif + +/* +#if !defined(HAS_BDROID_BUILDCFG) && !defined(HAS_NO_BDROID_BUILDCFG) +#error "An Android.mk file did not include bdroid_CFLAGS and possibly not bdorid_C_INCLUDES" +#endif +*/ + +#ifdef HAS_BDROID_BUILDCFG +#include "bdroid_buildcfg.h" +#endif + +#include "bt_types.h" /* This must be defined AFTER buildcfg.h */ + +/* Include common GKI definitions used by this platform */ +#include "gki_target.h" +#include "dyn_mem.h" /* defines static and/or dynamic memory for components */ + +//------------------Added from bdroid_buildcfg.h--------------------- +#ifndef L2CAP_EXTFEA_SUPPORTED_MASK +#define L2CAP_EXTFEA_SUPPORTED_MASK (L2CAP_EXTFEA_ENH_RETRANS | L2CAP_EXTFEA_STREAM_MODE | L2CAP_EXTFEA_NO_CRC | L2CAP_EXTFEA_FIXED_CHNLS) +#endif + +#ifndef BTUI_OPS_FORMATS +#define BTUI_OPS_FORMATS (BTA_OP_VCARD21_MASK | BTA_OP_ANY_MASK) +#endif + +#ifndef BTA_RFC_MTU_SIZE +#define BTA_RFC_MTU_SIZE (L2CAP_MTU_SIZE-L2CAP_MIN_OFFSET-RFCOMM_DATA_OVERHEAD) +#endif + +#ifndef SBC_NO_PCM_CPY_OPTION +#define SBC_NO_PCM_CPY_OPTION FALSE +#endif + +#ifndef BT_APP_DEMO +#define BT_APP_DEMO TRUE +#endif + +#ifndef BTIF_INCLUDED +#define BTIF_INCLUDED FALSE +#endif + +#ifndef BTA_INCLUDED +#define BTA_INCLUDED TRUE +#endif + +#ifndef BTA_PAN_INCLUDED +#define BTA_PAN_INCLUDED FALSE//TRUE +#endif + +#ifndef BTA_HH_INCLUDED +#define BTA_HH_INCLUDED FALSE//TRUE +#endif + +#ifndef BTA_HH_ROLE +#define BTA_HH_ROLE BTA_MASTER_ROLE_PREF +#endif + +#ifndef BTA_HH_LE_INCLUDED +#define BTA_HH_LE_INCLUDED FALSE//TRUE +#endif + +#ifndef BTA_AR_INCLUDED +#define BTA_AR_INCLUDED FALSE//TRUE +#endif + +#ifndef BTA_AV_INCLUDED +#define BTA_AV_INCLUDED FALSE//TRUE +#endif + +#ifndef BTA_AV_SINK_INCLUDED +#define BTA_AV_SINK_INCLUDED FALSE//FALSE +#endif + +#ifndef BTA_DISABLE_DELAY +#define BTA_DISABLE_DELAY 200 /* in milliseconds */ +#endif + +// If the next wakeup time is less than this threshold, we should acquire +// a wakelock instead of setting a wake alarm so we're not bouncing in +// and out of suspend frequently. +// in millisecond +// TODO(zachoverflow): reinstate in alarm code +#ifndef GKI_TIMER_INTERVAL_FOR_WAKELOCK +#define GKI_TIMER_INTERVAL_FOR_WAKELOCK 3000 +#endif + +#ifndef BTA_SYS_TIMER_PERIOD +#define BTA_SYS_TIMER_PERIOD 100 +#endif + +#ifndef SBC_FOR_EMBEDDED_LINUX +#define SBC_FOR_EMBEDDED_LINUX TRUE +#endif + +#ifndef AVDT_VERSION +#define AVDT_VERSION 0x0102 +#endif + +#ifndef BTA_AG_AT_MAX_LEN +#define BTA_AG_AT_MAX_LEN 512 +#endif + +#ifndef BTA_AVRCP_FF_RW_SUPPORT +#define BTA_AVRCP_FF_RW_SUPPORT FALSE//TRUE +#endif + +#ifndef BTA_AG_SCO_PKT_TYPES +#define BTA_AG_SCO_PKT_TYPES (BTM_SCO_LINK_ONLY_MASK | BTM_SCO_PKT_TYPES_MASK_EV3 | BTM_SCO_PKT_TYPES_MASK_NO_3_EV3 | BTM_SCO_PKT_TYPES_MASK_NO_2_EV5 | BTM_SCO_PKT_TYPES_MASK_NO_3_EV5) +#endif + +#ifndef BTA_AV_RET_TOUT +#define BTA_AV_RET_TOUT 15 +#endif + +#ifndef PORCHE_PAIRING_CONFLICT +#define PORCHE_PAIRING_CONFLICT TRUE +#endif + +#ifndef BTA_AV_CO_CP_SCMS_T +#define BTA_AV_CO_CP_SCMS_T FALSE//FALSE +#endif + +/* This feature is used to eanble interleaved scan*/ +#ifndef BTA_HOST_INTERLEAVE_SEARCH +#define BTA_HOST_INTERLEAVE_SEARCH FALSE//FALSE +#endif + +#ifndef BT_USE_TRACES +#define BT_USE_TRACES TRUE +#endif + +#ifndef BT_TRACE_BTIF +#define BT_TRACE_BTIF TRUE +#endif + +#ifndef BT_TRACE_VERBOSE +#define BT_TRACE_VERBOSE FALSE +#endif + +#ifndef BTA_DM_SDP_DB_SIZE +#define BTA_DM_SDP_DB_SIZE 8000 +#endif + +#ifndef HL_INCLUDED +#define HL_INCLUDED TRUE +#endif + +#ifndef AG_VOICE_SETTINGS +#define AG_VOICE_SETTINGS HCI_DEFAULT_VOICE_SETTINGS +#endif + +#ifndef BTIF_DM_OOB_TEST +#define BTIF_DM_OOB_TEST FALSE//TRUE +#endif + +// How long to wait before activating sniff mode after entering the +// idle state for FTS, OPS connections +#ifndef BTA_FTS_OPS_IDLE_TO_SNIFF_DELAY_MS +#define BTA_FTS_OPS_IDLE_TO_SNIFF_DELAY_MS 7000 +#endif + +//------------------End added from bdroid_buildcfg.h--------------------- + + +/****************************************************************************** +** +** GKI Buffer Pools +** +******************************************************************************/ + +/* Receives HCI events from the lower-layer. */ +#ifndef HCI_CMD_POOL_ID +#define HCI_CMD_POOL_ID GKI_POOL_ID_2 +#endif + +#ifndef HCI_CMD_POOL_BUF_SIZE +#define HCI_CMD_POOL_BUF_SIZE GKI_BUF2_SIZE +#endif + +/* Receives ACL data packets from thelower-layer. */ +#ifndef HCI_ACL_POOL_ID +#define HCI_ACL_POOL_ID GKI_POOL_ID_3 +#endif + +/* Maximum number of buffers available for ACL receive data. */ +#ifndef HCI_ACL_BUF_MAX +#define HCI_ACL_BUF_MAX GKI_BUF3_MAX +#endif + +/* Receives SCO data packets from the lower-layer. */ +#ifndef HCI_SCO_POOL_ID +#define HCI_SCO_POOL_ID GKI_POOL_ID_6 +#endif + +/* Sends SDP data packets. */ +#ifndef SDP_POOL_ID +#define SDP_POOL_ID 3 +#endif + +/* Sends RFCOMM command packets. */ +#ifndef RFCOMM_CMD_POOL_ID +#define RFCOMM_CMD_POOL_ID GKI_POOL_ID_2 +#endif + +/* Sends RFCOMM data packets. */ +#ifndef RFCOMM_DATA_POOL_ID +#define RFCOMM_DATA_POOL_ID GKI_POOL_ID_3 +#endif + +#ifndef RFCOMM_DATA_POOL_BUF_SIZE +#define RFCOMM_DATA_POOL_BUF_SIZE GKI_BUF3_SIZE +#endif + +/* Sends L2CAP packets to the peer and HCI messages to the controller. */ +#ifndef L2CAP_CMD_POOL_ID +#define L2CAP_CMD_POOL_ID GKI_POOL_ID_2 +#endif + +/* Sends L2CAP segmented packets in ERTM mode */ +#ifndef L2CAP_FCR_TX_POOL_ID +#define L2CAP_FCR_TX_POOL_ID HCI_ACL_POOL_ID +#endif + +/* Receives L2CAP segmented packets in ERTM mode */ +#ifndef L2CAP_FCR_RX_POOL_ID +#define L2CAP_FCR_RX_POOL_ID HCI_ACL_POOL_ID +#endif + +/* Number of ACL buffers to assign to LE + if the HCI buffer pool is shared with BR/EDR */ +#ifndef L2C_DEF_NUM_BLE_BUF_SHARED +#define L2C_DEF_NUM_BLE_BUF_SHARED 1 +#endif + +/* Used by BTM when it sends HCI commands to the controller. */ +#ifndef BTM_CMD_POOL_ID +#define BTM_CMD_POOL_ID GKI_POOL_ID_2 +#endif + +#ifndef OBX_LRG_DATA_POOL_SIZE +#define OBX_LRG_DATA_POOL_SIZE GKI_BUF4_SIZE +#endif + +#ifndef OBX_LRG_DATA_POOL_ID +#define OBX_LRG_DATA_POOL_ID GKI_POOL_ID_4 +#endif +/* Used to send data to L2CAP. */ +#ifndef GAP_DATA_POOL_ID +#define GAP_DATA_POOL_ID GKI_POOL_ID_3 +#endif + +#ifndef SPP_DB_SIZE +#define SPP_DB_SIZE GKI_BUF3_SIZE +#endif + +/* BNEP data and protocol messages. */ +#ifndef BNEP_POOL_ID +#define BNEP_POOL_ID GKI_POOL_ID_3 +#endif + +/* RPC pool for temporary trace message buffers. */ +#ifndef RPC_SCRATCH_POOL_ID +#define RPC_SCRATCH_POOL_ID GKI_POOL_ID_2 +#endif + +/* AVDTP pool for protocol messages */ +#ifndef AVDT_CMD_POOL_ID +#define AVDT_CMD_POOL_ID GKI_POOL_ID_2 +#endif + +/* AVDTP pool size for media packets in case of fragmentation */ +#ifndef AVDT_DATA_POOL_SIZE +#define AVDT_DATA_POOL_SIZE GKI_BUF3_SIZE +#endif + +#ifndef PAN_POOL_ID +#define PAN_POOL_ID GKI_POOL_ID_3 +/* Maximum amount of the shared buffer to allocate for PAN */ +#define PAN_POOL_MAX (GKI_BUF3_MAX / 4) +#endif + +/* AVCTP pool for protocol messages */ +#ifndef AVCT_CMD_POOL_ID +#define AVCT_CMD_POOL_ID GKI_POOL_ID_1 +#endif + +/* AVRCP pool for protocol messages */ +#ifndef AVRC_CMD_POOL_ID +#define AVRC_CMD_POOL_ID GKI_POOL_ID_1 +#endif + +/* AVRCP pool size for protocol messages */ +#ifndef AVRC_CMD_POOL_SIZE +#define AVRC_CMD_POOL_SIZE GKI_BUF1_SIZE +#endif + +/* AVRCP Metadata pool for protocol messages */ +#ifndef AVRC_META_CMD_POOL_ID +#define AVRC_META_CMD_POOL_ID GKI_POOL_ID_2 +#endif + +/* AVRCP Metadata pool size for protocol messages */ +#ifndef AVRC_META_CMD_POOL_SIZE +#define AVRC_META_CMD_POOL_SIZE GKI_BUF2_SIZE +#endif + + +/* AVRCP buffer size for browsing channel messages */ +#ifndef AVRC_BROWSE_POOL_SIZE +#define AVRC_BROWSE_POOL_SIZE GKI_MAX_BUF_SIZE +#endif + +#ifndef BTA_HL_LRG_DATA_POOL_ID +#define BTA_HL_LRG_DATA_POOL_ID GKI_POOL_ID_7 +#endif + +/* GATT Server Database pool ID */ +#ifndef GATT_DB_POOL_ID +#define GATT_DB_POOL_ID GKI_POOL_ID_8 +#endif + +/* GATT Data sending buffer pool ID, use default ACL pool for fix channel data */ +#ifndef GATT_BUF_POOL_ID +#define GATT_BUF_POOL_ID HCI_ACL_POOL_ID +#endif + +/****************************************************************************** +** +** Lower Layer Interface +** +******************************************************************************/ + +/* Macro for allocating buffer for HCI commands */ +#ifndef HCI_GET_CMD_BUF +#if (!defined(HCI_USE_VARIABLE_SIZE_CMD_BUF) || (HCI_USE_VARIABLE_SIZE_CMD_BUF == FALSE)) +/* Allocate fixed-size buffer from HCI_CMD_POOL (default case) */ +#define HCI_GET_CMD_BUF(paramlen) ((BT_HDR *)GKI_getpoolbuf (HCI_CMD_POOL_ID)) +#else +/* Allocate smallest possible buffer (for platforms with limited RAM) */ +#define HCI_GET_CMD_BUF(paramlen) ((BT_HDR *)GKI_getbuf ((UINT16)(BT_HDR_SIZE + HCIC_PREAMBLE_SIZE + (paramlen)))) +#endif +#endif /* HCI_GET_CMD_BUF */ + +/****************************************************************************** +** +** HCI Services (H4) +** +******************************************************************************/ + +/* Use 2 second for low-resolution systems, override to 1 for high-resolution systems */ +#ifndef BT_1SEC_TIMEOUT +#define BT_1SEC_TIMEOUT (2) +#endif + +/* Quick Timer */ +/* if L2CAP_FCR_INCLUDED is TRUE then it should have 100 millisecond resolution */ +/* if none of them is included then QUICK_TIMER_TICKS_PER_SEC is set to 0 to exclude quick timer */ +#ifndef QUICK_TIMER_TICKS_PER_SEC +#define QUICK_TIMER_TICKS_PER_SEC 10 /* 100ms timer */ +#endif + +/****************************************************************************** +** +** BTM +** +******************************************************************************/ + +/* Cancel Inquiry on incoming SSP */ +#ifndef BTM_NO_SSP_ON_INQUIRY +#define BTM_NO_SSP_ON_INQUIRY FALSE +#endif + +/* Includes SCO if TRUE */ +#ifndef BTM_SCO_INCLUDED +#define BTM_SCO_INCLUDED TRUE /* TRUE includes SCO code */ +#endif + +/* Includes SCO if TRUE */ +#ifndef BTM_SCO_HCI_INCLUDED +#define BTM_SCO_HCI_INCLUDED FALSE /* TRUE includes SCO over HCI code */ +#endif + +/* Includes WBS if TRUE */ +#ifndef BTM_WBS_INCLUDED +#define BTM_WBS_INCLUDED FALSE /* TRUE includes WBS code */ +#endif + +/* This is used to work around a controller bug that doesn't like Disconnect +** issued while there is a role switch in progress +*/ +#ifndef BTM_DISC_DURING_RS +#define BTM_DISC_DURING_RS TRUE +#endif + +/************************** +** Initial SCO TX credit +*************************/ +/* max TX SCO data packet size */ +#ifndef BTM_SCO_DATA_SIZE_MAX +#define BTM_SCO_DATA_SIZE_MAX 240 +#endif + +/* The size in bytes of the BTM inquiry database. 40 As Default */ +#ifndef BTM_INQ_DB_SIZE +#define BTM_INQ_DB_SIZE 32 +#endif + +/* The default scan mode */ +#ifndef BTM_DEFAULT_SCAN_TYPE +#define BTM_DEFAULT_SCAN_TYPE BTM_SCAN_TYPE_INTERLACED +#endif + +/* Should connections to unknown devices be allowed when not discoverable? */ +#ifndef BTM_ALLOW_CONN_IF_NONDISCOVER +#define BTM_ALLOW_CONN_IF_NONDISCOVER TRUE +#endif + +/* Sets the Page_Scan_Window: the length of time that the device is performing a page scan. */ +#ifndef BTM_DEFAULT_CONN_WINDOW +#define BTM_DEFAULT_CONN_WINDOW 0x0012 +#endif + +/* Sets the Page_Scan_Activity: the interval between the start of two consecutive page scans. */ +#ifndef BTM_DEFAULT_CONN_INTERVAL +#define BTM_DEFAULT_CONN_INTERVAL 0x0800 +#endif + +/* When automatic inquiry scan is enabled, this sets the inquiry scan window. */ +#ifndef BTM_DEFAULT_DISC_WINDOW +#define BTM_DEFAULT_DISC_WINDOW 0x0012 +#endif + +/* When automatic inquiry scan is enabled, this sets the inquiry scan interval. */ +#ifndef BTM_DEFAULT_DISC_INTERVAL +#define BTM_DEFAULT_DISC_INTERVAL 0x0800 +#endif + +/* Default class of device +* {SERVICE_CLASS, MAJOR_CLASS, MINOR_CLASS} +* +* SERVICE_CLASS:0x5A (Bit17 -Networking,Bit19 - Capturing,Bit20 -Object Transfer,Bit22 -Telephony) +* MAJOR_CLASS:0x02 - PHONE +* MINOR_CLASS:0x0C - SMART_PHONE +* +*/ +#ifndef BTA_DM_COD +#define BTA_DM_COD {0x5A, 0x02, 0x0C} +#endif + +/* The number of SCO links. */ +#ifndef BTM_MAX_SCO_LINKS +#define BTM_MAX_SCO_LINKS 3 +#endif + +/* The preferred type of SCO links (2-eSCO, 0-SCO). */ +#ifndef BTM_DEFAULT_SCO_MODE +#define BTM_DEFAULT_SCO_MODE 2 +#endif + +/* The number of security records for peer devices. 100 AS Default*/ +#ifndef BTM_SEC_MAX_DEVICE_RECORDS +#define BTM_SEC_MAX_DEVICE_RECORDS 8 // 100 +#endif + +/* The number of security records for services. 32 AS Default*/ +#ifndef BTM_SEC_MAX_SERVICE_RECORDS +#define BTM_SEC_MAX_SERVICE_RECORDS 8 // 32 +#endif + +/* If True, force a retrieval of remote device name for each bond in case it's changed */ +#ifndef BTM_SEC_FORCE_RNR_FOR_DBOND +#define BTM_SEC_FORCE_RNR_FOR_DBOND FALSE +#endif + +/* Maximum device name length used in btm database. Up to 248*/ +#ifndef BTM_MAX_REM_BD_NAME_LEN +#define BTM_MAX_REM_BD_NAME_LEN 64 +#endif + +/* Maximum local device name length stored btm database. + '0' disables storage of the local name in BTM */ +#ifndef BTM_MAX_LOC_BD_NAME_LEN +#define BTM_MAX_LOC_BD_NAME_LEN 64 +#endif + +/* Fixed Default String. When this is defined as null string, the device's + * product model name is used as the default local name. + */ +#ifndef BTM_DEF_LOCAL_NAME +#define BTM_DEF_LOCAL_NAME "" +#endif + +/* Maximum service name stored with security authorization (0 if not needed) */ +#ifndef BTM_SEC_SERVICE_NAME_LEN +#define BTM_SEC_SERVICE_NAME_LEN BT_MAX_SERVICE_NAME_LEN +#endif + +/* Maximum length of the service name. */ +#ifndef BT_MAX_SERVICE_NAME_LEN +#define BT_MAX_SERVICE_NAME_LEN 21 +#endif + +/* ACL buffer size in HCI Host Buffer Size command. */ +#ifndef BTM_ACL_BUF_SIZE +#define BTM_ACL_BUF_SIZE 0 +#endif + +/* The maximum number of clients that can register with the power manager. */ +#ifndef BTM_MAX_PM_RECORDS +#define BTM_MAX_PM_RECORDS 2 +#endif + +/* This is set to show debug trace messages for the power manager. */ +#ifndef BTM_PM_DEBUG +#define BTM_PM_DEBUG FALSE +#endif + +/* This is set to TRUE if link is to be unparked due to BTM_CreateSCO API. */ +#ifndef BTM_SCO_WAKE_PARKED_LINK +#define BTM_SCO_WAKE_PARKED_LINK TRUE +#endif + +/* If the user does not respond to security process requests within this many seconds, + * a negative response would be sent automatically. + * 30 is LMP response timeout value */ +#ifndef BTM_SEC_TIMEOUT_VALUE +#define BTM_SEC_TIMEOUT_VALUE 35 +#endif + +/* Maximum number of callbacks that can be registered using BTM_RegisterForVSEvents */ +#ifndef BTM_MAX_VSE_CALLBACKS +#define BTM_MAX_VSE_CALLBACKS 3 +#endif + +/****************************************** +** Lisbon Features +*******************************************/ +/* This is set to TRUE if the FEC is required for EIR packet. */ +#ifndef BTM_EIR_DEFAULT_FEC_REQUIRED +#define BTM_EIR_DEFAULT_FEC_REQUIRED TRUE +#endif + +/* The IO capability of the local device (for Simple Pairing) */ +#ifndef BTM_LOCAL_IO_CAPS +#define BTM_LOCAL_IO_CAPS BTM_IO_CAP_IO +#endif + +#ifndef BTM_LOCAL_IO_CAPS_BLE +#define BTM_LOCAL_IO_CAPS_BLE BTM_IO_CAP_KBDISP +#endif + +/* The default MITM Protection Requirement (for Simple Pairing) + * Possible values are BTM_AUTH_SP_YES or BTM_AUTH_SP_NO */ +#ifndef BTM_DEFAULT_AUTH_REQ +#define BTM_DEFAULT_AUTH_REQ BTM_AUTH_SP_NO +#endif + +/* The default MITM Protection Requirement for dedicated bonding using Simple Pairing + * Possible values are BTM_AUTH_AP_YES or BTM_AUTH_AP_NO */ +#ifndef BTM_DEFAULT_DD_AUTH_REQ +#define BTM_DEFAULT_DD_AUTH_REQ BTM_AUTH_AP_YES +#endif + +/* Include Out-of-Band implementation for Simple Pairing */ +#ifndef BTM_OOB_INCLUDED +#define BTM_OOB_INCLUDED TRUE +#endif + +/* TRUE to include Sniff Subrating */ +#ifndef BTM_SSR_INCLUDED +#define BTM_SSR_INCLUDED TRUE +#endif + +/************************* +** End of Lisbon Features +**************************/ + +/* 4.1/4.2 secure connections feature */ +#ifndef SC_MODE_INCLUDED +#define SC_MODE_INCLUDED TRUE +#endif + +/* Used for conformance testing ONLY */ +#ifndef BTM_BLE_CONFORMANCE_TESTING +#define BTM_BLE_CONFORMANCE_TESTING FALSE +#endif + +/****************************************************************************** +** +** L2CAP +** +******************************************************************************/ + +#ifndef L2CAP_CLIENT_INCLUDED +#define L2CAP_CLIENT_INCLUDED FALSE +#endif + + +/* The maximum number of simultaneous links that L2CAP can support. Up to 7*/ +#ifndef MAX_ACL_CONNECTIONS +#define MAX_L2CAP_LINKS 3 +#else +#define MAX_L2CAP_LINKS MAX_ACL_CONNECTIONS +#endif + +/* The maximum number of simultaneous channels that L2CAP can support. Up to 16*/ +#ifndef MAX_L2CAP_CHANNELS +#define MAX_L2CAP_CHANNELS 8 +#endif + +/* The maximum number of simultaneous applications that can register with L2CAP. */ +#ifndef MAX_L2CAP_CLIENTS +#define MAX_L2CAP_CLIENTS 8 +#endif + +/* The number of seconds of link inactivity before a link is disconnected. */ +#ifndef L2CAP_LINK_INACTIVITY_TOUT +#define L2CAP_LINK_INACTIVITY_TOUT 4 +#endif + +/* The number of seconds of link inactivity after bonding before a link is disconnected. */ +#ifndef L2CAP_BONDING_TIMEOUT +#define L2CAP_BONDING_TIMEOUT 3 +#endif + +/* The time from the HCI connection complete to disconnect if no channel is established. */ +#ifndef L2CAP_LINK_STARTUP_TOUT +#define L2CAP_LINK_STARTUP_TOUT 60 +#endif + +/* The L2CAP MTU; must be in accord with the HCI ACL pool size. */ +#ifndef L2CAP_MTU_SIZE +#define L2CAP_MTU_SIZE 1691 +#endif + +/* The L2CAP MPS over Bluetooth; must be in accord with the FCR tx pool size and ACL down buffer size. */ +#ifndef L2CAP_MPS_OVER_BR_EDR +#define L2CAP_MPS_OVER_BR_EDR 1010 +#endif + +/* If host flow control enabled, this is the number of buffers the controller can have unacknowledged. */ +#ifndef L2CAP_HOST_FC_ACL_BUFS +#define L2CAP_HOST_FC_ACL_BUFS 20 +#endif + +/* This is set to enable L2CAP to take the ACL link out of park mode when ACL data is to be sent. */ +#ifndef L2CAP_WAKE_PARKED_LINK +#define L2CAP_WAKE_PARKED_LINK TRUE +#endif + +/* Whether link wants to be the master or the slave. */ +#ifndef L2CAP_DESIRED_LINK_ROLE +#define L2CAP_DESIRED_LINK_ROLE HCI_ROLE_SLAVE +#endif + +/* Include Non-Flushable Packet Boundary Flag feature of Lisbon */ +#ifndef L2CAP_NON_FLUSHABLE_PB_INCLUDED +#define L2CAP_NON_FLUSHABLE_PB_INCLUDED TRUE +#endif + +/* Minimum number of ACL credit for high priority link */ +#ifndef L2CAP_HIGH_PRI_MIN_XMIT_QUOTA +#define L2CAP_HIGH_PRI_MIN_XMIT_QUOTA 5 +#endif + +/* used for monitoring HCI ACL credit management */ +#ifndef L2CAP_HCI_FLOW_CONTROL_DEBUG +#define L2CAP_HCI_FLOW_CONTROL_DEBUG TRUE +#endif + +/* Used for calculating transmit buffers off of */ +#ifndef L2CAP_NUM_XMIT_BUFFS +#define L2CAP_NUM_XMIT_BUFFS HCI_ACL_BUF_MAX +#endif + +/* Unicast Connectionless Data */ +#ifndef L2CAP_UCD_INCLUDED +#define L2CAP_UCD_INCLUDED FALSE +#endif + +/* Unicast Connectionless Data MTU */ +#ifndef L2CAP_UCD_MTU +#define L2CAP_UCD_MTU L2CAP_MTU_SIZE +#endif + +/* Unicast Connectionless Data Idle Timeout */ +#ifndef L2CAP_UCD_IDLE_TIMEOUT +#define L2CAP_UCD_IDLE_TIMEOUT 2 +#endif + +/* Unicast Connectionless Data Idle Timeout */ +#ifndef L2CAP_UCD_CH_PRIORITY +#define L2CAP_UCD_CH_PRIORITY L2CAP_CHNL_PRIORITY_MEDIUM +#endif + +/* Used for features using fixed channels; set to zero if no fixed channels supported (BLE, etc.) */ +/* Excluding L2CAP signaling channel and UCD */ +#ifndef L2CAP_NUM_FIXED_CHNLS +#define L2CAP_NUM_FIXED_CHNLS 32 +#endif + +/* First fixed channel supported */ +#ifndef L2CAP_FIRST_FIXED_CHNL +#define L2CAP_FIRST_FIXED_CHNL 4 +#endif + +#ifndef L2CAP_LAST_FIXED_CHNL +#define L2CAP_LAST_FIXED_CHNL (L2CAP_FIRST_FIXED_CHNL + L2CAP_NUM_FIXED_CHNLS - 1) +#endif + +/* Round Robin service channels in link */ +#ifndef L2CAP_ROUND_ROBIN_CHANNEL_SERVICE +#define L2CAP_ROUND_ROBIN_CHANNEL_SERVICE TRUE +#endif + +/* Used for calculating transmit buffers off of */ +#ifndef L2CAP_NUM_XMIT_BUFFS +#define L2CAP_NUM_XMIT_BUFFS HCI_ACL_BUF_MAX +#endif + +/* used for monitoring eL2CAP data flow */ +#ifndef L2CAP_ERTM_STATS +#define L2CAP_ERTM_STATS FALSE +#endif + +/* Used for conformance testing ONLY: When TRUE lets scriptwrapper overwrite info response */ +#ifndef L2CAP_CONFORMANCE_TESTING +#define L2CAP_CONFORMANCE_TESTING FALSE +#endif + +/* + * Max bytes per connection to buffer locally before dropping the + * connection if local client does not receive it - default is 1MB + */ +#ifndef L2CAP_MAX_RX_BUFFER +#define L2CAP_MAX_RX_BUFFER 0x100000 +#endif + + +#ifndef TIMER_PARAM_TYPE +#define TIMER_PARAM_TYPE UINT32 +#endif + +/****************************************************************************** +** +** BLE +** +******************************************************************************/ + +#ifndef BLE_INCLUDED +#define BLE_INCLUDED TRUE +#endif + +#ifndef BLE_ANDROID_CONTROLLER_SCAN_FILTER +#define BLE_ANDROID_CONTROLLER_SCAN_FILTER TRUE +#endif + +#ifndef LOCAL_BLE_CONTROLLER_ID +#define LOCAL_BLE_CONTROLLER_ID (1) +#endif + +/* + * Toggles support for general LE privacy features such as remote address + * resolution, local address rotation etc. + */ +#ifndef BLE_PRIVACY_SPT +#define BLE_PRIVACY_SPT TRUE +#endif + +/* + * Enables or disables support for local privacy (ex. address rotation) + */ +#ifndef BLE_LOCAL_PRIVACY_ENABLED +#define BLE_LOCAL_PRIVACY_ENABLED TRUE +#endif + +/* + * Toggles support for vendor specific extensions such as RPA offloading, + * feature discovery, multi-adv etc. + */ +#ifndef BLE_VND_INCLUDED +#define BLE_VND_INCLUDED FALSE +#endif + +#ifndef BTM_BLE_ADV_TX_POWER +#define BTM_BLE_ADV_TX_POWER {-21, -15, -7, 1, 9} +#endif + + +#ifndef BLE_BATCH_SCAN_INCLUDED +#define BLE_BATCH_SCAN_INCLUDED TRUE +#endif + +/****************************************************************************** +** +** ATT/GATT Protocol/Profile Settings +** +******************************************************************************/ +#ifndef GATT_INCLUDED +#if BLE_INCLUDED == TRUE +#define GATT_INCLUDED TRUE +#else +#define GATT_INCLUDED FALSE +#endif +#endif + +#ifndef BTA_GATT_INCLUDED +#if BLE_INCLUDED == TRUE +#define BTA_GATT_INCLUDED TRUE +#else +#define BTA_GATT_INCLUDED FALSE +#endif +#endif + +#if BTA_GATT_INCLUDED == TRUE && BLE_INCLUDED == FALSE +#error "can't have GATT without BLE" +#endif + +#ifndef BLE_LLT_INCLUDED +#define BLE_LLT_INCLUDED TRUE +#endif + +#ifndef ATT_INCLUDED +#define ATT_INCLUDED TRUE +#endif + +#ifndef ATT_DEBUG +#define ATT_DEBUG FALSE//TRUE +#endif + +#ifndef BLE_PERIPHERAL_MODE_SUPPORT +#define BLE_PERIPHERAL_MODE_SUPPORT TRUE +#endif + +#ifndef BLE_DELAY_REQUEST_ENC +/* This flag is to work around IPHONE problem, We need to wait for iPhone ready + before send encryption request to iPhone */ +#define BLE_DELAY_REQUEST_ENC FALSE +#endif + +#ifndef GAP_TRANSPORT_SUPPORTED +#define GAP_TRANSPORT_SUPPORTED GATT_TRANSPORT_LE_BR_EDR +#endif + +#ifndef GATTP_TRANSPORT_SUPPORTED +#define GATTP_TRANSPORT_SUPPORTED GATT_TRANSPORT_LE_BR_EDR +#endif + +#ifndef GATT_MAX_SR_PROFILES +#define GATT_MAX_SR_PROFILES 8 /* max is 32 */ +#endif + +#ifndef GATT_MAX_APPS +#define GATT_MAX_APPS 8 /* MAX is 32 note: 2 apps used internally GATT and GAP */ +#endif + +#ifndef GATT_MAX_PHY_CHANNEL +#define GATT_MAX_PHY_CHANNEL 7 +#endif + +/* Used for conformance testing ONLY */ +#ifndef GATT_CONFORMANCE_TESTING +#define GATT_CONFORMANCE_TESTING FALSE +#endif + +/* number of background connection device allowence, ideally to be the same as WL size +*/ +#ifndef GATT_MAX_BG_CONN_DEV +#define GATT_MAX_BG_CONN_DEV 8 /*MAX is 32*/ +#endif + +/****************************************************************************** +** +** SMP +** +******************************************************************************/ +#ifndef SMP_INCLUDED +#if BLE_INCLUDED == TRUE +#define SMP_INCLUDED TRUE +#else +#define SMP_INCLUDED FALSE +#endif +#endif + +#if SMP_INCLUDED == TRUE && BLE_INCLUDED == FALSE +#error "can't have SMP without BLE" +#endif + +#ifndef SMP_DEBUG +#define SMP_DEBUG FALSE +#endif + +#ifndef SMP_DEFAULT_AUTH_REQ +#define SMP_DEFAULT_AUTH_REQ SMP_AUTH_NB_ENC_ONLY +#endif + +#ifndef SMP_MAX_ENC_KEY_SIZE +#define SMP_MAX_ENC_KEY_SIZE 16 +#endif + +#ifndef SMP_MIN_ENC_KEY_SIZE +#define SMP_MIN_ENC_KEY_SIZE 7 +#endif + +/* minimum link timeout after SMP pairing is done, leave room for key exchange + and racing condition for the following service connection. + Prefer greater than 0 second, and no less than default inactivity link idle + timer(L2CAP_LINK_INACTIVITY_TOUT) in l2cap) */ +#ifndef SMP_LINK_TOUT_MIN +#if (L2CAP_LINK_INACTIVITY_TOUT > 0) +#define SMP_LINK_TOUT_MIN L2CAP_LINK_INACTIVITY_TOUT +#else +#define SMP_LINK_TOUT_MIN 2 +#endif +#endif +/****************************************************************************** +** +** SDP +** +******************************************************************************/ + +#ifndef SDP_INCLUDED +#define SDP_INCLUDED TRUE +#endif + +/* This is set to enable SDP server functionality. */ +#ifndef SDP_SERVER_ENABLED +#if SDP_INCLUDED == TRUE +#define SDP_SERVER_ENABLED TRUE +#else +#define SDP_SERVER_ENABLED FALSE +#endif +#endif + +/* This is set to enable SDP client functionality. */ +#ifndef SDP_CLIENT_ENABLED +#if SDP_INCLUDED == TRUE +#define SDP_CLIENT_ENABLED TRUE +#else +#define SDP_CLIENT_ENABLED FALSE +#endif +#endif + +/* The maximum number of SDP records the server can support. */ +#ifndef SDP_MAX_RECORDS +#define SDP_MAX_RECORDS 15 /*max is 30*/ +#endif + +/* The maximum number of attributes in each record. */ +#ifndef SDP_MAX_REC_ATTR +#define SDP_MAX_REC_ATTR 25 +#endif + +#ifndef SDP_MAX_PAD_LEN +#define SDP_MAX_PAD_LEN 600 +#endif + +/* The maximum length, in bytes, of an attribute. */ +#ifndef SDP_MAX_ATTR_LEN +#define SDP_MAX_ATTR_LEN 400 +#endif + +/* The maximum number of attribute filters supported by SDP databases. */ +#ifndef SDP_MAX_ATTR_FILTERS +#define SDP_MAX_ATTR_FILTERS 15 +#endif + +/* The maximum number of UUID filters supported by SDP databases. */ +#ifndef SDP_MAX_UUID_FILTERS +#define SDP_MAX_UUID_FILTERS 3 +#endif + +/* The maximum number of record handles retrieved in a search. */ +#ifndef SDP_MAX_DISC_SERVER_RECS +#define SDP_MAX_DISC_SERVER_RECS 21 +#endif + +/* The size of a scratchpad buffer, in bytes, for storing the response to an attribute request. */ +#ifndef SDP_MAX_LIST_BYTE_COUNT +#define SDP_MAX_LIST_BYTE_COUNT 4096 +#endif + +/* The maximum number of parameters in an SDP protocol element. */ +#ifndef SDP_MAX_PROTOCOL_PARAMS +#define SDP_MAX_PROTOCOL_PARAMS 2 +#endif + +/* The maximum number of simultaneous client and server connections. */ +#ifndef SDP_MAX_CONNECTIONS +#define SDP_MAX_CONNECTIONS 2 // 4 +#endif + +/* The MTU size for the L2CAP configuration. */ +#ifndef SDP_MTU_SIZE +#define SDP_MTU_SIZE 672 +#endif + +/* The flush timeout for the L2CAP configuration. */ +#ifndef SDP_FLUSH_TO +#define SDP_FLUSH_TO 0xFFFF +#endif + +/* The name for security authorization. */ +#ifndef SDP_SERVICE_NAME +#define SDP_SERVICE_NAME "Service Discovery" +#endif + +/* The security level for BTM. */ +#ifndef SDP_SECURITY_LEVEL +#define SDP_SECURITY_LEVEL BTM_SEC_NONE +#endif + +/****************************************************************************** +** +** RFCOMM +** +******************************************************************************/ +#ifndef RFCOMM_INCLUDED +#define RFCOMM_INCLUDED FALSE +#endif + +/* The maximum number of ports supported. */ +#ifndef MAX_RFC_PORTS +#define MAX_RFC_PORTS 16 /*max is 30*/ +#endif + +/* The maximum simultaneous links to different devices. */ +#ifndef MAX_ACL_CONNECTIONS +#define MAX_BD_CONNECTIONS 3 /*max is 7*/ +#else +#define MAX_BD_CONNECTIONS MAX_ACL_CONNECTIONS +#endif + +/* The port receive queue low watermark level, in bytes. */ +#ifndef PORT_RX_LOW_WM +#define PORT_RX_LOW_WM (BTA_RFC_MTU_SIZE * PORT_RX_BUF_LOW_WM) +#endif + +/* The port receive queue high watermark level, in bytes. */ +#ifndef PORT_RX_HIGH_WM +#define PORT_RX_HIGH_WM (BTA_RFC_MTU_SIZE * PORT_RX_BUF_HIGH_WM) +#endif + +/* The port receive queue critical watermark level, in bytes. */ +#ifndef PORT_RX_CRITICAL_WM +#define PORT_RX_CRITICAL_WM (BTA_RFC_MTU_SIZE * PORT_RX_BUF_CRITICAL_WM) +#endif + +/* The port receive queue low watermark level, in number of buffers. */ +#ifndef PORT_RX_BUF_LOW_WM +#define PORT_RX_BUF_LOW_WM 4 +#endif + +/* The port receive queue high watermark level, in number of buffers. */ +#ifndef PORT_RX_BUF_HIGH_WM +#define PORT_RX_BUF_HIGH_WM 10 +#endif + +/* The port receive queue critical watermark level, in number of buffers. */ +#ifndef PORT_RX_BUF_CRITICAL_WM +#define PORT_RX_BUF_CRITICAL_WM 15 +#endif + +/* The port transmit queue high watermark level, in bytes. */ +#ifndef PORT_TX_HIGH_WM +#define PORT_TX_HIGH_WM (BTA_RFC_MTU_SIZE * PORT_TX_BUF_HIGH_WM) +#endif + +/* The port transmit queue critical watermark level, in bytes. */ +#ifndef PORT_TX_CRITICAL_WM +#define PORT_TX_CRITICAL_WM (BTA_RFC_MTU_SIZE * PORT_TX_BUF_CRITICAL_WM) +#endif + +/* The port transmit queue high watermark level, in number of buffers. */ +#ifndef PORT_TX_BUF_HIGH_WM +#define PORT_TX_BUF_HIGH_WM 10 +#endif + +/* The port transmit queue high watermark level, in number of buffers. */ +#ifndef PORT_TX_BUF_CRITICAL_WM +#define PORT_TX_BUF_CRITICAL_WM 15 +#endif + +/* The RFCOMM multiplexer preferred flow control mechanism. */ +#ifndef PORT_FC_DEFAULT +#define PORT_FC_DEFAULT PORT_FC_CREDIT +#endif + +/* The maximum number of credits receiver sends to peer when using credit-based flow control. */ +#ifndef PORT_CREDIT_RX_MAX +#define PORT_CREDIT_RX_MAX 16 +#endif + +/* The credit low watermark level. */ +#ifndef PORT_CREDIT_RX_LOW +#define PORT_CREDIT_RX_LOW 8 +#endif + +/* if application like BTA, Java or script test engine is running on other than BTU thread, */ +/* PORT_SCHEDULE_LOCK shall be defined as GKI_sched_lock() or GKI_disable() */ +#ifndef PORT_SCHEDULE_LOCK +#define PORT_SCHEDULE_LOCK GKI_disable() +#endif + +/* if application like BTA, Java or script test engine is running on other than BTU thread, */ +/* PORT_SCHEDULE_LOCK shall be defined as GKI_sched_unlock() or GKI_enable() */ +#ifndef PORT_SCHEDULE_UNLOCK +#define PORT_SCHEDULE_UNLOCK GKI_enable() +#endif + +/****************************************************************************** +** +** OBEX +** +******************************************************************************/ +#define OBX_14_INCLUDED FALSE + +/* The maximum number of registered servers. */ +#ifndef OBX_NUM_SERVERS +#define OBX_NUM_SERVERS 12 +#endif + +/* The maximum number of active clients. */ +#ifndef OBX_NUM_CLIENTS +#define OBX_NUM_CLIENTS 8 +#endif + +/* This option is application when OBX_14_INCLUDED=TRUE + Pool ID where to reassemble the SDU. + This Pool will allow buffers to be used that are larger than + the L2CAP_MAX_MTU. */ +#ifndef OBX_USER_RX_POOL_ID +#define OBX_USER_RX_POOL_ID OBX_LRG_DATA_POOL_ID +#endif + +/* This option is application when OBX_14_INCLUDED=TRUE + Pool ID where to hold the SDU. + This Pool will allow buffers to be used that are larger than + the L2CAP_MAX_MTU. */ +#ifndef OBX_USER_TX_POOL_ID +#define OBX_USER_TX_POOL_ID OBX_LRG_DATA_POOL_ID +#endif + +/* This option is application when OBX_14_INCLUDED=TRUE +GKI Buffer Pool ID used to hold MPS segments during SDU reassembly +*/ +#ifndef OBX_FCR_RX_POOL_ID +#define OBX_FCR_RX_POOL_ID HCI_ACL_POOL_ID +#endif + +/* This option is application when OBX_14_INCLUDED=TRUE +GKI Buffer Pool ID used to hold MPS segments used in (re)transmissions. +L2CAP_DEFAULT_ERM_POOL_ID is specified to use the HCI ACL data pool. +Note: This pool needs to have enough buffers to hold two times the window size negotiated + in the L2CA_SetFCROptions (2 * tx_win_size) to allow for retransmissions. + The size of each buffer must be able to hold the maximum MPS segment size passed in + L2CA_SetFCROptions plus BT_HDR (8) + HCI preamble (4) + L2CAP_MIN_OFFSET (11 - as of BT 2.1 + EDR Spec). +*/ +#ifndef OBX_FCR_TX_POOL_ID +#define OBX_FCR_TX_POOL_ID HCI_ACL_POOL_ID +#endif + +/* This option is application when OBX_14_INCLUDED=TRUE +Size of the transmission window when using enhanced retransmission mode. Not used +in basic and streaming modes. Range: 1 - 63 +*/ +#ifndef OBX_FCR_OPT_TX_WINDOW_SIZE_BR_EDR +#define OBX_FCR_OPT_TX_WINDOW_SIZE_BR_EDR 20 +#endif + +/* This option is application when OBX_14_INCLUDED=TRUE +Number of transmission attempts for a single I-Frame before taking +Down the connection. Used In ERTM mode only. Value is Ignored in basic and +Streaming modes. +Range: 0, 1-0xFF +0 - infinite retransmissions +1 - single transmission +*/ +#ifndef OBX_FCR_OPT_MAX_TX_B4_DISCNT +#define OBX_FCR_OPT_MAX_TX_B4_DISCNT 20 +#endif + +/* This option is application when OBX_14_INCLUDED=TRUE +Retransmission Timeout +Range: Minimum 2000 (2 secs) on BR/EDR when supporting PBF. + */ +#ifndef OBX_FCR_OPT_RETX_TOUT +#define OBX_FCR_OPT_RETX_TOUT 2000 +#endif + +/* This option is application when OBX_14_INCLUDED=TRUE +Monitor Timeout +Range: Minimum 12000 (12 secs) on BR/EDR when supporting PBF. +*/ +#ifndef OBX_FCR_OPT_MONITOR_TOUT +#define OBX_FCR_OPT_MONITOR_TOUT 12000 +#endif + +/* This option is application when OBX_14_INCLUDED=TRUE +Maximum PDU payload size. +Suggestion: The maximum amount of data that will fit into a 3-DH5 packet. +Range: 2 octets +*/ +#ifndef OBX_FCR_OPT_MAX_PDU_SIZE +#define OBX_FCR_OPT_MAX_PDU_SIZE L2CAP_MPS_OVER_BR_EDR +#endif + + +/****************************************************************************** +** +** BNEP +** +******************************************************************************/ + +#ifndef BNEP_INCLUDED +#define BNEP_INCLUDED FALSE//TRUE +#endif + +/* BNEP status API call is used mainly to get the L2CAP handle */ +#ifndef BNEP_SUPPORTS_STATUS_API +#define BNEP_SUPPORTS_STATUS_API FALSE//TRUE +#endif + +/* +** When BNEP connection changes roles after the connection is established +** we will do an authentication check again on the new role +*/ +#ifndef BNEP_DO_AUTH_FOR_ROLE_SWITCH +#define BNEP_DO_AUTH_FOR_ROLE_SWITCH FALSE//TRUE +#endif + + +/* Maximum number of protocol filters supported. */ +#ifndef BNEP_MAX_PROT_FILTERS +#define BNEP_MAX_PROT_FILTERS 5 +#endif + +/* Maximum number of multicast filters supported. */ +#ifndef BNEP_MAX_MULTI_FILTERS +#define BNEP_MAX_MULTI_FILTERS 5 +#endif + +/* Minimum MTU size. */ +#ifndef BNEP_MIN_MTU_SIZE +#define BNEP_MIN_MTU_SIZE L2CAP_MTU_SIZE +#endif + +/* Preferred MTU size. */ +#ifndef BNEP_MTU_SIZE +#define BNEP_MTU_SIZE BNEP_MIN_MTU_SIZE +#endif + +/* Maximum number of buffers allowed in transmit data queue. */ +#ifndef BNEP_MAX_XMITQ_DEPTH +#define BNEP_MAX_XMITQ_DEPTH 20 +#endif + +/* Maximum number BNEP of connections supported. */ +#ifndef BNEP_MAX_CONNECTIONS +#define BNEP_MAX_CONNECTIONS 7 +#endif + + +/****************************************************************************** +** +** AVDTP +** +******************************************************************************/ + +#ifndef AVDT_INCLUDED +#define AVDT_INCLUDED FALSE//TRUE +#endif + +/* Include reporting capability in AVDTP */ +#ifndef AVDT_REPORTING +#define AVDT_REPORTING FALSE//TRUE +#endif + +/* Include multiplexing capability in AVDTP */ +#ifndef AVDT_MULTIPLEXING +#define AVDT_MULTIPLEXING FALSE//TRUE +#endif + +/* Number of simultaneous links to different peer devices. */ +#ifndef AVDT_NUM_LINKS +#define AVDT_NUM_LINKS 2 +#endif + +/* Number of simultaneous stream endpoints. */ +#ifndef AVDT_NUM_SEPS +#define AVDT_NUM_SEPS 3 +#endif + +/* Number of transport channels setup per media stream(audio or video) */ +#ifndef AVDT_NUM_CHANNELS + +#if AVDT_REPORTING == TRUE +/* signaling, media and reporting channels */ +#define AVDT_NUM_CHANNELS 3 +#else +/* signaling and media channels */ +#define AVDT_NUM_CHANNELS 2 +#endif // AVDT_REPORTING + +#endif // AVDT_NUM_CHANNELS + +/* Number of transport channels setup by AVDT for all media streams + * AVDT_NUM_CHANNELS * Number of simultaneous streams. + */ +#ifndef AVDT_NUM_TC_TBL +#define AVDT_NUM_TC_TBL 6 +#endif + +/* Maximum size in bytes of the codec capabilities information element. */ +#ifndef AVDT_CODEC_SIZE +#define AVDT_CODEC_SIZE 10 +#endif + +/* Maximum size in bytes of the content protection information element. */ +#ifndef AVDT_PROTECT_SIZE +#define AVDT_PROTECT_SIZE 90 +#endif + +/* Maximum number of GKI buffers in the fragment queue (for video frames). + * Must be less than the number of buffers in the buffer pool of size AVDT_DATA_POOL_SIZE */ +#ifndef AVDT_MAX_FRAG_COUNT +#define AVDT_MAX_FRAG_COUNT 15 +#endif + +/****************************************************************************** +** +** PAN +** +******************************************************************************/ + +#ifndef PAN_INCLUDED +#define PAN_INCLUDED FALSE//TRUE +#endif + +/* This will enable the PANU role */ +#ifndef PAN_SUPPORTS_ROLE_PANU +#define PAN_SUPPORTS_ROLE_PANU FALSE//TRUE +#endif + +/* This will enable the GN role */ +#ifndef PAN_SUPPORTS_ROLE_GN +#define PAN_SUPPORTS_ROLE_GN FALSE//TRUE +#endif + +/* This will enable the NAP role */ +#ifndef PAN_SUPPORTS_ROLE_NAP +#define PAN_SUPPORTS_ROLE_NAP FALSE//TRUE +#endif + +/* This is just for debugging purposes */ +#ifndef PAN_SUPPORTS_DEBUG_DUMP +#define PAN_SUPPORTS_DEBUG_DUMP FALSE//TRUE +#endif + +/* Maximum number of PAN connections allowed */ +#ifndef MAX_PAN_CONNS +#define MAX_PAN_CONNS 7 +#endif + +/* Default service name for NAP role */ +#ifndef PAN_NAP_DEFAULT_SERVICE_NAME +#define PAN_NAP_DEFAULT_SERVICE_NAME "Network Access Point Service" +#endif + +/* Default service name for GN role */ +#ifndef PAN_GN_DEFAULT_SERVICE_NAME +#define PAN_GN_DEFAULT_SERVICE_NAME "Group Network Service" +#endif + +/* Default service name for PANU role */ +#ifndef PAN_PANU_DEFAULT_SERVICE_NAME +#define PAN_PANU_DEFAULT_SERVICE_NAME "PAN User Service" +#endif + +/* Default description for NAP role service */ +#ifndef PAN_NAP_DEFAULT_DESCRIPTION +#define PAN_NAP_DEFAULT_DESCRIPTION "NAP" +#endif + +/* Default description for GN role service */ +#ifndef PAN_GN_DEFAULT_DESCRIPTION +#define PAN_GN_DEFAULT_DESCRIPTION "GN" +#endif + +/* Default description for PANU role service */ +#ifndef PAN_PANU_DEFAULT_DESCRIPTION +#define PAN_PANU_DEFAULT_DESCRIPTION "PANU" +#endif + +/* Default Security level for PANU role. */ +#ifndef PAN_PANU_SECURITY_LEVEL +#define PAN_PANU_SECURITY_LEVEL 0 +#endif + +/* Default Security level for GN role. */ +#ifndef PAN_GN_SECURITY_LEVEL +#define PAN_GN_SECURITY_LEVEL 0 +#endif + +/* Default Security level for NAP role. */ +#ifndef PAN_NAP_SECURITY_LEVEL +#define PAN_NAP_SECURITY_LEVEL 0 +#endif + +/****************************************************************************** +** +** GAP +** +******************************************************************************/ + +#ifndef GAP_INCLUDED +#define GAP_INCLUDED TRUE +#endif + +/* This is set to enable use of GAP L2CAP connections. */ +#ifndef GAP_CONN_INCLUDED +#if GAP_INCLUDED == TRUE +#define GAP_CONN_INCLUDED TRUE +#else +#define GAP_CONN_INCLUDED FALSE +#endif +#endif + +/* This is set to enable posting event for data write */ +#ifndef GAP_CONN_POST_EVT_INCLUDED +#define GAP_CONN_POST_EVT_INCLUDED FALSE +#endif + +/* The maximum number of simultaneous GAP L2CAP connections. */ +#ifndef GAP_MAX_CONNECTIONS +#define GAP_MAX_CONNECTIONS 10 // 30 +#endif + +/* keep the raw data received from SDP server in database. */ +#ifndef SDP_RAW_DATA_INCLUDED +#define SDP_RAW_DATA_INCLUDED TRUE +#endif + +/* Inquiry duration in 1.28 second units. */ +#ifndef SDP_DEBUG +#define SDP_DEBUG TRUE +#endif + +/****************************************************************************** +** +** HID +** +******************************************************************************/ + +#ifndef HID_DEV_SUBCLASS +#define HID_DEV_SUBCLASS COD_MINOR_POINTING +#endif + +#ifndef HID_CONTROL_POOL_ID +#define HID_CONTROL_POOL_ID 2 +#endif + +#ifndef HID_INTERRUPT_POOL_ID +#define HID_INTERRUPT_POOL_ID 2 +#endif + +/************************************************************************* +** Definitions for Both HID-Host & Device +*/ +#ifndef HID_MAX_SVC_NAME_LEN +#define HID_MAX_SVC_NAME_LEN 32 +#endif + +#ifndef HID_MAX_SVC_DESCR_LEN +#define HID_MAX_SVC_DESCR_LEN 32 +#endif + +#ifndef HID_MAX_PROV_NAME_LEN +#define HID_MAX_PROV_NAME_LEN 32 +#endif + +/************************************************************************* +** Definitions for HID-Host +*/ +#ifndef HID_HOST_INCLUDED +#define HID_HOST_INCLUDED FALSE//TRUE +#endif + +#ifndef HID_HOST_MAX_DEVICES +#define HID_HOST_MAX_DEVICES 7 +#endif + +#ifndef HID_HOST_MTU +#define HID_HOST_MTU 640 +#endif + +#ifndef HID_HOST_FLUSH_TO +#define HID_HOST_FLUSH_TO 0xffff +#endif + +#ifndef HID_HOST_MAX_CONN_RETRY +#define HID_HOST_MAX_CONN_RETRY (3) +#endif + +#ifndef HID_HOST_REPAGE_WIN +#define HID_HOST_REPAGE_WIN (2) +#endif + +/************************************************************************* + * A2DP Definitions + */ +#ifndef A2D_INCLUDED +#define A2D_INCLUDED FALSE//TRUE +#endif + +/****************************************************************************** +** +** AVCTP +** +******************************************************************************/ + +/* Number of simultaneous ACL links to different peer devices. */ +#ifndef AVCT_NUM_LINKS +#define AVCT_NUM_LINKS 2 +#endif + +/* Number of simultaneous AVCTP connections. */ +#ifndef AVCT_NUM_CONN +#define AVCT_NUM_CONN 3 +#endif + +/****************************************************************************** +** +** AVRCP +** +******************************************************************************/ +#ifndef AVRC_INCLUDED +#define AVRC_INCLUDED FALSE +#endif + +#ifndef AVRC_METADATA_INCLUDED +#if AVRC_INCLUDED == TRUE +#define AVRC_METADATA_INCLUDED TRUE +#else +#define AVRC_METADATA_INCLUDED FALSE +#endif +#endif + +#ifndef AVRC_ADV_CTRL_INCLUDED +#if AVRC_INCLUDED == TRUE +#define AVRC_ADV_CTRL_INCLUDED TRUE +#else +#define AVRC_ADV_CTRL_INCLUDED FALSE +#endif +#endif + +#ifndef AVRC_CTLR_INCLUDED +#if AVRC_INCLUDED == TRUE +#define AVRC_CTLR_INCLUDED TRUE +#else +#define AVRC_CTLR_INCLUDED FALSE +#endif +#endif + +/****************************************************************************** +** +** MCAP +** +******************************************************************************/ +#ifndef MCA_INCLUDED +#define MCA_INCLUDED FALSE +#endif + +/* The MTU size for the L2CAP configuration on control channel. 48 is the minimal */ +#ifndef MCA_CTRL_MTU +#define MCA_CTRL_MTU 60 +#endif + +/* The maximum number of registered MCAP instances. */ +#ifndef MCA_NUM_REGS +#define MCA_NUM_REGS 12 +#endif + +/* The maximum number of control channels (to difference devices) per registered MCAP instances. */ +#ifndef MCA_NUM_LINKS +#define MCA_NUM_LINKS 3 +#endif + +/* The maximum number of MDEP (including HDP echo) per registered MCAP instances. */ +#ifndef MCA_NUM_DEPS +#define MCA_NUM_DEPS 13 +#endif + +/* The maximum number of MDL link per control channel. */ +#ifndef MCA_NUM_MDLS +#define MCA_NUM_MDLS 4 +#endif + +/* Pool ID where to reassemble the SDU. */ +#ifndef MCA_USER_RX_POOL_ID +#define MCA_USER_RX_POOL_ID HCI_ACL_POOL_ID +#endif + +/* Pool ID where to hold the SDU. */ +#ifndef MCA_USER_TX_POOL_ID +#define MCA_USER_TX_POOL_ID HCI_ACL_POOL_ID +#endif + +/* +GKI Buffer Pool ID used to hold MPS segments during SDU reassembly +*/ +#ifndef MCA_FCR_RX_POOL_ID +#define MCA_FCR_RX_POOL_ID HCI_ACL_POOL_ID +#endif + +/* +GKI Buffer Pool ID used to hold MPS segments used in (re)transmissions. +L2CAP_DEFAULT_ERM_POOL_ID is specified to use the HCI ACL data pool. +Note: This pool needs to have enough buffers to hold two times the window size negotiated + in the tL2CAP_FCR_OPTIONS (2 * tx_win_size) to allow for retransmissions. + The size of each buffer must be able to hold the maximum MPS segment size passed in + tL2CAP_FCR_OPTIONS plus BT_HDR (8) + HCI preamble (4) + L2CAP_MIN_OFFSET (11 - as of BT 2.1 + EDR Spec). +*/ +#ifndef MCA_FCR_TX_POOL_ID +#define MCA_FCR_TX_POOL_ID HCI_ACL_POOL_ID +#endif + +/* MCAP control channel FCR Option: +Size of the transmission window when using enhanced retransmission mode. +1 is defined by HDP specification for control channel. +*/ +#ifndef MCA_FCR_OPT_TX_WINDOW_SIZE +#define MCA_FCR_OPT_TX_WINDOW_SIZE 1 +#endif + +/* MCAP control channel FCR Option: +Number of transmission attempts for a single I-Frame before taking +Down the connection. Used In ERTM mode only. Value is Ignored in basic and +Streaming modes. +Range: 0, 1-0xFF +0 - infinite retransmissions +1 - single transmission +*/ +#ifndef MCA_FCR_OPT_MAX_TX_B4_DISCNT +#define MCA_FCR_OPT_MAX_TX_B4_DISCNT 20 +#endif + +/* MCAP control channel FCR Option: Retransmission Timeout +The AVRCP specification set a value in the range of 300 - 2000 ms +Timeout (in msecs) to detect Lost I-Frames. Only used in Enhanced retransmission mode. +Range: Minimum 2000 (2 secs) when supporting PBF. + */ +#ifndef MCA_FCR_OPT_RETX_TOUT +#define MCA_FCR_OPT_RETX_TOUT 2000 +#endif + +/* MCAP control channel FCR Option: Monitor Timeout +The AVRCP specification set a value in the range of 300 - 2000 ms +Timeout (in msecs) to detect Lost S-Frames. Only used in Enhanced retransmission mode. +Range: Minimum 12000 (12 secs) when supporting PBF. +*/ +#ifndef MCA_FCR_OPT_MONITOR_TOUT +#define MCA_FCR_OPT_MONITOR_TOUT 12000 +#endif + +/* MCAP control channel FCR Option: Maximum PDU payload size. +The maximum number of payload octets that the local device can receive in a single PDU. +*/ +#ifndef MCA_FCR_OPT_MPS_SIZE +#define MCA_FCR_OPT_MPS_SIZE 1000 +#endif + +/* Shared transport */ +#ifndef NFC_SHARED_TRANSPORT_ENABLED +#define NFC_SHARED_TRANSPORT_ENABLED FALSE +#endif + +/****************************************************************************** +** +** Sleep Mode (Low Power Mode) +** +******************************************************************************/ + +#ifndef HCILP_INCLUDED +#define HCILP_INCLUDED FALSE//TRUE +#endif + +/****************************************************************************** +** +** APPL - Application Task +** +******************************************************************************/ + +#define L2CAP_FEATURE_REQ_ID 73 +#define L2CAP_FEATURE_RSP_ID 173 + +/****************************************************************************** +** +** BTA +** +******************************************************************************/ +/* BTA EIR canned UUID list (default is dynamic) */ +#ifndef BTA_EIR_CANNED_UUID_LIST +#define BTA_EIR_CANNED_UUID_LIST FALSE +#endif + +/* Number of supported customer UUID in EIR */ +#ifndef BTA_EIR_SERVER_NUM_CUSTOM_UUID +#define BTA_EIR_SERVER_NUM_CUSTOM_UUID 8 +#endif + +/* CHLD override for bluedroid */ +#ifndef BTA_AG_CHLD_VAL_ECC +#define BTA_AG_CHLD_VAL_ECC "(0,1,1x,2,2x,3)" +#endif + +#ifndef BTA_AG_CHLD_VAL +#define BTA_AG_CHLD_VAL "(0,1,2,3)" +#endif + +/* Set the CIND to match HFP 1.5 */ +#ifndef BTA_AG_CIND_INFO +#define BTA_AG_CIND_INFO "(\"call\",(0,1)),(\"callsetup\",(0-3)),(\"service\",(0-1)),(\"signal\",(0-5)),(\"roam\",(0,1)),(\"battchg\",(0-5)),(\"callheld\",(0-2))" +#endif + +#ifndef BTA_DM_AVOID_A2DP_ROLESWITCH_ON_INQUIRY +#define BTA_DM_AVOID_A2DP_ROLESWITCH_ON_INQUIRY FALSE//TRUE +#endif + +/****************************************************************************** +** +** Tracing: Include trace header file here. +** +******************************************************************************/ + +/* Enable/disable BTSnoop memory logging */ +#ifndef BTSNOOP_MEM +#define BTSNOOP_MEM FALSE//TRUE +#endif + +#include "bt_trace.h" + +#endif /* BT_TARGET_H */ diff --git a/components/bt/bluedroid/include/bt_trace.h b/components/bt/bluedroid/include/bt_trace.h new file mode 100755 index 0000000000..17cfe51916 --- /dev/null +++ b/components/bt/bluedroid/include/bt_trace.h @@ -0,0 +1,462 @@ +/****************************************************************************** + * + * Copyright (C) 1999-2012 Broadcom Corporation + * + * 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. + * + ******************************************************************************/ + +#ifndef _BT_TRACE_H_ +#define _BT_TRACE_H_ + +#include "bt_types.h" + +#include "rom/ets_sys.h" +//extern void ets_printf(const char *fmt, ...); + +#define assert(x) do { if (!(x)) ets_printf("bt host error %s %u\n", __FILE__, __LINE__); } while (0) + +inline void trc_dump_buffer(uint8_t *prefix, uint8_t *data, uint16_t len) +{ + uint16_t i; + + if (!data || !len) + return; + + if (prefix) + ets_printf("%s:\t", prefix); + + for (i = 0; i < len; i++) { + ets_printf(" %02x", *(data + i)); + if (!((i + 1) & 0xf)) + ets_printf("\n"); + } + ets_printf("\n"); +} + +#ifdef BTTRC_DUMP_BUFFER +#define BTTRC_DUMP_BUFFER(_prefix, _data, _len) trc_dump_buffer(_data, _len) +#else +#define BTTRC_DUMP_BUFFER(_prefix, _data, _len) +#endif + +//static const char BTE_LOGMSG_MODULE[] = "bte_logmsg_module"; + +/* BTrgs);E tracing IDs for debug purposes */ +/* LayerIDs for stack */ +#define BTTRC_ID_STK_GKI 1 +#define BTTRC_ID_STK_BTU 2 +#define BTTRC_ID_STK_HCI 3 +#define BTTRC_ID_STK_L2CAP 4 +#define BTTRC_ID_STK_RFCM_MX 5 +#define BTTRC_ID_STK_RFCM_PRT 6 +#define BTTRC_ID_STK_OBEX_C 7 +#define BTTRC_ID_STK_OBEX_S 8 +#define BTTRC_ID_STK_AVCT 9 +#define BTTRC_ID_STK_AVDT 10 +#define BTTRC_ID_STK_AVRC 11 +#define BTTRC_ID_STK_BIC 12 +#define BTTRC_ID_STK_BIS 13 +#define BTTRC_ID_STK_BNEP 14 +#define BTTRC_ID_STK_BPP 15 +#define BTTRC_ID_STK_BTM_ACL 16 +#define BTTRC_ID_STK_BTM_PM 17 +#define BTTRC_ID_STK_BTM_DEV_CTRL 18 +#define BTTRC_ID_STK_BTM_SVC_DSC 19 +#define BTTRC_ID_STK_BTM_INQ 20 +#define BTTRC_ID_STK_BTM_SCO 21 +#define BTTRC_ID_STK_BTM_SEC 22 +#define BTTRC_ID_STK_HID 24 +#define BTTRC_ID_STK_HSP2 25 +#define BTTRC_ID_STK_CTP 26 +#define BTTRC_ID_STK_FTC 27 +#define BTTRC_ID_STK_FTS 28 +#define BTTRC_ID_STK_GAP 29 +#define BTTRC_ID_STK_HCRP 31 +#define BTTRC_ID_STK_ICP 32 +#define BTTRC_ID_STK_OPC 33 +#define BTTRC_ID_STK_OPS 34 +#define BTTRC_ID_STK_PAN 35 +#define BTTRC_ID_STK_SAP 36 +#define BTTRC_ID_STK_SDP 37 +#define BTTRC_ID_STK_SLIP 38 +#define BTTRC_ID_STK_SPP 39 +#define BTTRC_ID_STK_TCS 40 +#define BTTRC_ID_STK_VDP 41 +#define BTTRC_ID_STK_MCAP 42 +#define BTTRC_ID_STK_GATT 43 +#define BTTRC_ID_STK_SMP 44 +#define BTTRC_ID_STK_NFC 45 +#define BTTRC_ID_STK_NCI 46 +#define BTTRC_ID_STK_IDEP 47 +#define BTTRC_ID_STK_NDEP 48 +#define BTTRC_ID_STK_LLCP 49 +#define BTTRC_ID_STK_RW 50 +#define BTTRC_ID_STK_CE 51 +#define BTTRC_ID_STK_SNEP 52 +#define BTTRC_ID_STK_NDEF 53 + +/* LayerIDs for BTA */ +#define BTTRC_ID_BTA_ACC 55 /* Advanced Camera Client */ +#define BTTRC_ID_BTA_AG 56 /* audio gateway */ +#define BTTRC_ID_BTA_AV 57 /* Advanced audio */ +#define BTTRC_ID_BTA_BIC 58 /* Basic Imaging Client */ +#define BTTRC_ID_BTA_BIS 59 /* Basic Imaging Server */ +#define BTTRC_ID_BTA_BP 60 /* Basic Printing Client */ +#define BTTRC_ID_BTA_CG 61 +#define BTTRC_ID_BTA_CT 62 /* cordless telephony terminal */ +#define BTTRC_ID_BTA_DG 63 /* data gateway */ +#define BTTRC_ID_BTA_DM 64 /* device manager */ +#define BTTRC_ID_BTA_DM_SRCH 65 /* device manager search */ +#define BTTRC_ID_BTA_DM_SEC 66 /* device manager security */ +#define BTTRC_ID_BTA_FM 67 +#define BTTRC_ID_BTA_FTC 68 /* file transfer client */ +#define BTTRC_ID_BTA_FTS 69 /* file transfer server */ +#define BTTRC_ID_BTA_HIDH 70 +#define BTTRC_ID_BTA_HIDD 71 +#define BTTRC_ID_BTA_JV 72 +#define BTTRC_ID_BTA_OPC 73 /* object push client */ +#define BTTRC_ID_BTA_OPS 74 /* object push server */ +#define BTTRC_ID_BTA_PAN 75 /* Personal Area Networking */ +#define BTTRC_ID_BTA_PR 76 /* Printer client */ +#define BTTRC_ID_BTA_SC 77 /* SIM Card Access server */ +#define BTTRC_ID_BTA_SS 78 /* synchronization server */ +#define BTTRC_ID_BTA_SYS 79 /* system manager */ +#define BTTRC_ID_AVDT_SCB 80 /* avdt scb */ +#define BTTRC_ID_AVDT_CCB 81 /* avdt ccb */ + +// btla-specific ++ +/* LayerIDs added for BTL-A. Probably should modify bte_logmsg.c in future. */ +#define BTTRC_ID_STK_RFCOMM 82 +#define BTTRC_ID_STK_RFCOMM_DATA 83 +#define BTTRC_ID_STK_OBEX 84 +#define BTTRC_ID_STK_A2D 85 +#define BTTRC_ID_STK_BIP 86 + +/* LayerIDs for BT APP */ +#define BTTRC_ID_BTAPP 87 +#define BTTRC_ID_BT_PROTOCOL 88 /* this is a temporary solution to allow dynamic + enable/disable of BT_PROTOCOL_TRACE */ +#define BTTRC_ID_MAX_ID BTTRC_ID_BT_PROTOCOL +// btla-specific -- +#define BTTRC_ID_ALL_LAYERS 0xFF /* all trace layers */ +/* Parameter datatypes used in Trace APIs */ +#define BTTRC_PARAM_UINT8 1 +#define BTTRC_PARAM_UINT16 2 +#define BTTRC_PARAM_UINT32 3 + +/* Enables or disables verbose trace information. */ +#ifndef BT_TRACE_VERBOSE +#define BT_TRACE_VERBOSE FALSE +#endif + +/* Enables or disables all trace messages. */ +#ifndef BT_USE_TRACES +#define BT_USE_TRACES TRUE +#endif + +/****************************************************************************** +** +** Trace Levels +** +** The following values may be used for different levels: +** BT_TRACE_LEVEL_NONE 0 * No trace messages to be generated +** BT_TRACE_LEVEL_ERROR 1 * Error condition trace messages +** BT_TRACE_LEVEL_WARNING 2 * Warning condition trace messages +** BT_TRACE_LEVEL_API 3 * API traces +** BT_TRACE_LEVEL_EVENT 4 * Debug messages for events +** BT_TRACE_LEVEL_DEBUG 5 * Debug messages (general) +******************************************************************************/ + +// btla-specific ++ +/* Core Stack default trace levels */ +#ifndef HCI_INITIAL_TRACE_LEVEL +#define HCI_INITIAL_TRACE_LEVEL BT_TRACE_LEVEL_WARNING +#endif + +#ifndef BTM_INITIAL_TRACE_LEVEL +#define BTM_INITIAL_TRACE_LEVEL BT_TRACE_LEVEL_WARNING +#endif + +#ifndef L2CAP_INITIAL_TRACE_LEVEL +#define L2CAP_INITIAL_TRACE_LEVEL BT_TRACE_LEVEL_WARNING +#endif + +#ifndef RFCOMM_INITIAL_TRACE_LEVEL +#define RFCOMM_INITIAL_TRACE_LEVEL BT_TRACE_LEVEL_WARNING +#endif + +#ifndef SDP_INITIAL_TRACE_LEVEL +#define SDP_INITIAL_TRACE_LEVEL BT_TRACE_LEVEL_WARNING +#endif + +#ifndef GAP_INITIAL_TRACE_LEVEL +#define GAP_INITIAL_TRACE_LEVEL BT_TRACE_LEVEL_WARNING +#endif + +#ifndef BNEP_INITIAL_TRACE_LEVEL +#define BNEP_INITIAL_TRACE_LEVEL BT_TRACE_LEVEL_WARNING +#endif + +#ifndef PAN_INITIAL_TRACE_LEVEL +#define PAN_INITIAL_TRACE_LEVEL BT_TRACE_LEVEL_WARNING +#endif + +#ifndef A2D_INITIAL_TRACE_LEVEL +#define A2D_INITIAL_TRACE_LEVEL BT_TRACE_LEVEL_WARNING +#endif + +#ifndef AVDT_INITIAL_TRACE_LEVEL +#define AVDT_INITIAL_TRACE_LEVEL BT_TRACE_LEVEL_WARNING +#endif + +#ifndef AVCT_INITIAL_TRACE_LEVEL +#define AVCT_INITIAL_TRACE_LEVEL BT_TRACE_LEVEL_WARNING +#endif + +#ifndef AVRC_INITIAL_TRACE_LEVEL +#define AVRC_INITIAL_TRACE_LEVEL BT_TRACE_LEVEL_WARNING +#endif + +#ifndef MCA_INITIAL_TRACE_LEVEL +#define MCA_INITIAL_TRACE_LEVEL BT_TRACE_LEVEL_WARNING +#endif + +#ifndef HID_INITIAL_TRACE_LEVEL +#define HID_INITIAL_TRACE_LEVEL BT_TRACE_LEVEL_WARNING +#endif + +#ifndef APPL_INITIAL_TRACE_LEVEL +#define APPL_INITIAL_TRACE_LEVEL BT_TRACE_LEVEL_WARNING +#endif + +#ifndef BT_TRACE_APPL +#define BT_TRACE_APPL BT_USE_TRACES +#endif + +#ifndef GATT_INITIAL_TRACE_LEVEL +#define GATT_INITIAL_TRACE_LEVEL BT_TRACE_LEVEL_WARNING +#endif + +#ifndef SMP_INITIAL_TRACE_LEVEL +#define SMP_INITIAL_TRACE_LEVEL BT_TRACE_LEVEL_WARNING +#endif +// btla-specific -- + +/* Define common tracing for all */ +#define LOG_LEVEL_ERROR 1 +#define LOG_LEVEL_WARN 2 +#define LOG_LEVEL_INFO 3 +#define LOG_LEVEL_DEBUG 4 +#define LOG_LEVEL_VERBOSE 5 +#ifndef LOG_LEVEL +#define LOG_LEVEL LOG_LEVEL_DEBUG +#endif +#define LOG_ERROR(fmt, args...) do {if (LOG_LEVEL >= LOG_LEVEL_ERROR) ets_printf(fmt,## args);} while(0) +#define LOG_WARN(fmt, args...) do {if (LOG_LEVEL >= LOG_LEVEL_WARN) ets_printf(fmt,## args);} while(0) +#define LOG_INFO(fmt, args...) do {if (LOG_LEVEL >= LOG_LEVEL_INFO) ets_printf(fmt,## args);} while(0) +#define LOG_DEBUG(fmt, args...) do {if (LOG_LEVEL >= LOG_LEVEL_DEBUG) ets_printf(fmt,## args);} while(0) +#define LOG_VERBOSE(fmt, args...) do {if (LOG_LEVEL >= LOG_LEVEL_VERBOSE) ets_printf(fmt,## args);} while(0) + +/* Define tracing for the HCI unit +*/ +#define HCI_TRACE_ERROR(fmt, args...) {if (btu_cb.trace_level >= BT_TRACE_LEVEL_ERROR) ets_printf(fmt,## args);} +#define HCI_TRACE_WARNING(fmt, args...) {if (btu_cb.trace_level >= BT_TRACE_LEVEL_WARNING) ets_printf(fmt,## args);} +#define HCI_TRACE_EVENT(fmt, args...) {if (btu_cb.trace_level >= BT_TRACE_LEVEL_EVENT) ets_printf(fmt,## args);} +#define HCI_TRACE_DEBUG(fmt, args...) {if (btu_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) ets_printf(fmt,## args);} + +/* Define tracing for BTM +*/ +#define BTM_TRACE_ERROR(fmt, args...) {if (btm_cb.trace_level >= BT_TRACE_LEVEL_ERROR) ets_printf(fmt, ## args);} +#define BTM_TRACE_WARNING(fmt, args...) {if (btm_cb.trace_level >= BT_TRACE_LEVEL_WARNING) ets_printf(fmt, ## args);} +#define BTM_TRACE_API(fmt, args...) {if (btm_cb.trace_level >= BT_TRACE_LEVEL_API) ets_printf(fmt, ## args);} +#define BTM_TRACE_EVENT(fmt, args...) {if (btm_cb.trace_level >= BT_TRACE_LEVEL_EVENT) ets_printf(fmt, ## args);} +#define BTM_TRACE_DEBUG(fmt, args...) {if (btm_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) ets_printf(fmt, ## args);} + +/* Define tracing for the L2CAP unit +*/ +#define L2CAP_TRACE_ERROR(fmt, args...) {if (l2cb.l2cap_trace_level >= BT_TRACE_LEVEL_ERROR) ets_printf(fmt, ## args);} +#define L2CAP_TRACE_WARNING(fmt, args...) {if (l2cb.l2cap_trace_level >= BT_TRACE_LEVEL_WARNING) ets_printf(fmt, ## args);} +#define L2CAP_TRACE_API(fmt, args...) {if (l2cb.l2cap_trace_level >= BT_TRACE_LEVEL_API) ets_printf(fmt, ## args);} +#define L2CAP_TRACE_EVENT(fmt, args...) {if (l2cb.l2cap_trace_level >= BT_TRACE_LEVEL_EVENT) ets_printf(fmt, ## args);} +#define L2CAP_TRACE_DEBUG(fmt, args...) {if (l2cb.l2cap_trace_level >= BT_TRACE_LEVEL_DEBUG) ets_printf(fmt, ## args);} + +/* Define tracing for the SDP unit +*/ +#define SDP_TRACE_ERROR(fmt, args...) {if (sdp_cb.trace_level >= BT_TRACE_LEVEL_ERROR) ets_printf(fmt, ## args);} +#define SDP_TRACE_WARNING(fmt, args...) {if (sdp_cb.trace_level >= BT_TRACE_LEVEL_WARNING) ets_printf(fmt, ## args);} +#define SDP_TRACE_API(fmt, args...) {if (sdp_cb.trace_level >= BT_TRACE_LEVEL_API) ets_printf(fmt, ## args);} +#define SDP_TRACE_EVENT(fmt, args...) {if (sdp_cb.trace_level >= BT_TRACE_LEVEL_EVENT) ets_printf(fmt, ## args);} +#define SDP_TRACE_DEBUG(fmt, args...) {if (sdp_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) ets_printf(fmt, ## args);} + +/* Define tracing for the RFCOMM unit +*/ +#define RFCOMM_TRACE_ERROR(fmt, args...) {if (rfc_cb.trace_level >= BT_TRACE_LEVEL_ERROR) ets_printf(fmt, ## args);} +#define RFCOMM_TRACE_WARNING(fmt, args...) {if (rfc_cb.trace_level >= BT_TRACE_LEVEL_WARNING) ets_printf(fmt, ## args);} +#define RFCOMM_TRACE_API(fmt, args...) {if (rfc_cb.trace_level >= BT_TRACE_LEVEL_API) ets_printf(fmt, ## args);} +#define RFCOMM_TRACE_EVENT(fmt, args...) {if (rfc_cb.trace_level >= BT_TRACE_LEVEL_EVENT) ets_printf(fmt, ## args);} +#define RFCOMM_TRACE_DEBUG(fmt, args...) {if (rfc_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) ets_printf(fmt, ## args);} + +/* Generic Access Profile traces */ +#define GAP_TRACE_ERROR(fmt, args...) {if (gap_cb.trace_level >= BT_TRACE_LEVEL_ERROR) ets_printf(fmt, ## args);} +#define GAP_TRACE_EVENT(fmt, args...) {if (gap_cb.trace_level >= BT_TRACE_LEVEL_EVENT) ets_printf(fmt, ## args);} +#define GAP_TRACE_API(fmt, args...) {if (gap_cb.trace_level >= BT_TRACE_LEVEL_API) ets_printf(fmt, ## args);} +#define GAP_TRACE_WARNING(fmt, args...) {if (gap_cb.trace_level >= BT_TRACE_LEVEL_WARNING) ets_printf(fmt, ## args);} + +/* define traces for HID Host */ +#define HIDH_TRACE_ERROR(fmt, args...) {if (hh_cb.trace_level >= BT_TRACE_LEVEL_ERROR) ets_printf(fmt, ## args);} +#define HIDH_TRACE_WARNING(fmt, args...) {if (hh_cb.trace_level >= BT_TRACE_LEVEL_WARNING) ets_printf(fmt, ## args);} +#define HIDH_TRACE_API(fmt, args...) {if (hh_cb.trace_level >= BT_TRACE_LEVEL_API) ets_printf(fmt, ## args);} +#define HIDH_TRACE_EVENT(fmt, args...) {if (hh_cb.trace_level >= BT_TRACE_LEVEL_EVENT) ets_printf(fmt, ## args);} +#define HIDH_TRACE_DEBUG(fmt, args...) {if (hh_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) ets_printf(fmt, ## args);} + +/* define traces for BNEP */ + +#define BNEP_TRACE_ERROR(fmt, args...) {if (bnep_cb.trace_level >= BT_TRACE_LEVEL_ERROR) ets_printf(fmt, ## args);} +#define BNEP_TRACE_WARNING(fmt, args...) {if (bnep_cb.trace_level >= BT_TRACE_LEVEL_WARNING) ets_printf(fmt, ## args);} +#define BNEP_TRACE_API(fmt, args...) {if (bnep_cb.trace_level >= BT_TRACE_LEVEL_API) ets_printf(fmt, ## args);} +#define BNEP_TRACE_EVENT(fmt, args...) {if (bnep_cb.trace_level >= BT_TRACE_LEVEL_EVENT) ets_printf(fmt, ## args);} +#define BNEP_TRACE_DEBUG(fmt, args...) {if (bnep_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) ets_printf(fmt, ## args);} + +/* define traces for PAN */ + +#define PAN_TRACE_ERROR(fmt, args...) {if (pan_cb.trace_level >= BT_TRACE_LEVEL_ERROR) ets_printf(fmt, ## args);} +#define PAN_TRACE_WARNING(fmt, args...) {if (pan_cb.trace_level >= BT_TRACE_LEVEL_WARNING) ets_printf(fmt, ## args);} +#define PAN_TRACE_API(fmt, args...) {if (pan_cb.trace_level >= BT_TRACE_LEVEL_API) ets_printf(fmt, ## args);} +#define PAN_TRACE_EVENT(fmt, args...) {if (pan_cb.trace_level >= BT_TRACE_LEVEL_EVENT) ets_printf(fmt, ## args);} +#define PAN_TRACE_DEBUG(fmt, args...) {if (pan_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) ets_printf(fmt, ## args);} + +/* Define tracing for the A2DP profile +*/ +#define A2D_TRACE_ERROR(fmt, args...) {if (a2d_cb.trace_level >= BT_TRACE_LEVEL_ERROR) ets_printf(fmt, ## args);} +#define A2D_TRACE_WARNING(fmt, args...) {if (a2d_cb.trace_level >= BT_TRACE_LEVEL_WARNING) ets_printf(fmt, ## args);} +#define A2D_TRACE_EVENT(fmt, args...) {if (a2d_cb.trace_level >= BT_TRACE_LEVEL_EVENT) ets_printf(fmt, ## args);} +#define A2D_TRACE_DEBUG(fmt, args...) {if (a2d_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) ets_printf(fmt, ## args);} +#define A2D_TRACE_API(fmt, args...) {if (a2d_cb.trace_level >= BT_TRACE_LEVEL_API) ets_printf(fmt, ## args);} + +/* AVDTP +*/ +#define AVDT_TRACE_ERROR(fmt, args...) {if (avdt_cb.trace_level >= BT_TRACE_LEVEL_ERROR) ets_printf(fmt, ## args);} +#define AVDT_TRACE_WARNING(fmt, args...) {if (avdt_cb.trace_level >= BT_TRACE_LEVEL_WARNING) ets_printf(fmt, ## args);} +#define AVDT_TRACE_EVENT(fmt, args...) {if (avdt_cb.trace_level >= BT_TRACE_LEVEL_EVENT) ets_printf(fmt, ## args);} +#define AVDT_TRACE_DEBUG(fmt, args...) {if (avdt_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) ets_printf(fmt, ## args);} +#define AVDT_TRACE_API(fmt, args...) {if (avdt_cb.trace_level >= BT_TRACE_LEVEL_API) ets_printf(fmt, ## args);} + +/* Define tracing for the AVCTP protocol +*/ +#define AVCT_TRACE_ERROR(fmt, args...) {if (avct_cb.trace_level >= BT_TRACE_LEVEL_ERROR) ets_printf(fmt, ## args);} +#define AVCT_TRACE_WARNING(fmt, args...) {if (avct_cb.trace_level >= BT_TRACE_LEVEL_WARNING) ets_printf(fmt, ## args);} +#define AVCT_TRACE_EVENT(fmt, args...) {if (avct_cb.trace_level >= BT_TRACE_LEVEL_EVENT) ets_printf(fmt, ## args);} +#define AVCT_TRACE_DEBUG(fmt, args...) {if (avct_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) ets_printf(fmt, ## args);} +#define AVCT_TRACE_API(fmt, args...) {if (avct_cb.trace_level >= BT_TRACE_LEVEL_API) ets_printf(fmt, ## args);} + +/* Define tracing for the AVRCP profile +*/ +#define AVRC_TRACE_ERROR(fmt, args...) {if (avrc_cb.trace_level >= BT_TRACE_LEVEL_ERROR) ets_printf(fmt, ## args);} +#define AVRC_TRACE_WARNING(fmt, args...) {if (avrc_cb.trace_level >= BT_TRACE_LEVEL_WARNING) ets_printf(fmt, ## args);} +#define AVRC_TRACE_EVENT(fmt, args...) {if (avrc_cb.trace_level >= BT_TRACE_LEVEL_EVENT) ets_printf(fmt, ## args);} +#define AVRC_TRACE_DEBUG(fmt, args...) {if (avrc_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) ets_printf(fmt, ## args);} +#define AVRC_TRACE_API(fmt, args...) {if (avrc_cb.trace_level >= BT_TRACE_LEVEL_API) ets_printf(fmt, ## args);} + +/* MCAP +*/ +#define MCA_TRACE_ERROR(fmt, args...) {if (mca_cb.trace_level >= BT_TRACE_LEVEL_ERROR) ets_printf(fmt, ## args);} +#define MCA_TRACE_WARNING(fmt, args...) {if (mca_cb.trace_level >= BT_TRACE_LEVEL_WARNING) ets_printf(fmt, ## args);} +#define MCA_TRACE_EVENT(fmt, args...) {if (mca_cb.trace_level >= BT_TRACE_LEVEL_EVENT) ets_printf(fmt, ## args);} +#define MCA_TRACE_DEBUG(fmt, args...) {if (mca_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) ets_printf(fmt, ## args);} +#define MCA_TRACE_API(fmt, args...) {if (mca_cb.trace_level >= BT_TRACE_LEVEL_API) ets_printf(fmt, ## args);} + +/* Define tracing for the ATT/GATT unit +*/ +#define GATT_TRACE_ERROR(fmt, args...) {if (gatt_cb.trace_level >= BT_TRACE_LEVEL_ERROR) ets_printf(fmt, ## args);} +#define GATT_TRACE_WARNING(fmt, args...) {if (gatt_cb.trace_level >= BT_TRACE_LEVEL_WARNING) ets_printf(fmt, ## args);} +#define GATT_TRACE_API(fmt, args...) {if (gatt_cb.trace_level >= BT_TRACE_LEVEL_API) ets_printf(fmt, ## args);} +#define GATT_TRACE_EVENT(fmt, args...) {if (gatt_cb.trace_level >= BT_TRACE_LEVEL_EVENT) ets_printf(fmt, ## args);} +#define GATT_TRACE_DEBUG(fmt, args...) {if (gatt_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) ets_printf(fmt, ## args);} + +/* Define tracing for the SMP unit +*/ +#define SMP_TRACE_ERROR(fmt, args...) {if (smp_cb.trace_level >= BT_TRACE_LEVEL_ERROR) ets_printf(fmt, ## args);} +#define SMP_TRACE_WARNING(fmt, args...) {if (smp_cb.trace_level >= BT_TRACE_LEVEL_WARNING) ets_printf(fmt, ## args);} +#define SMP_TRACE_API(fmt, args...) {if (smp_cb.trace_level >= BT_TRACE_LEVEL_API) ets_printf(fmt, ## args);} +#define SMP_TRACE_EVENT(fmt, args...) {if (smp_cb.trace_level >= BT_TRACE_LEVEL_EVENT) ets_printf(fmt, ## args);} +#define SMP_TRACE_DEBUG(fmt, args...) {if (smp_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) ets_printf(fmt, ## args);} + +extern UINT8 btif_trace_level; + +// define traces for application +#define BTIF_TRACE_ERROR(fmt, args...) {if (btif_trace_level >= BT_TRACE_LEVEL_ERROR) ets_printf(fmt, ## args);} +#define BTIF_TRACE_WARNING(fmt, args...) {if (btif_trace_level >= BT_TRACE_LEVEL_WARNING) ets_printf(fmt, ## args);} +#define BTIF_TRACE_API(fmt, args...) {if (btif_trace_level >= BT_TRACE_LEVEL_API) ets_printf(fmt, ## args);} +#define BTIF_TRACE_EVENT(fmt, args...) {if (btif_trace_level >= BT_TRACE_LEVEL_EVENT) ets_printf(fmt, ## args);} +#define BTIF_TRACE_DEBUG(fmt, args...) {if (btif_trace_level >= BT_TRACE_LEVEL_DEBUG) ets_printf(fmt, ## args);} +#define BTIF_TRACE_VERBOSE(fmt, args...) {if (btif_trace_level >= BT_TRACE_LEVEL_VERBOSE)ets_printf(fmt, ## args);} + +/* define traces for application */ + +#define APPL_TRACE_ERROR(fmt, args...) {if (appl_trace_level >= BT_TRACE_LEVEL_ERROR) ets_printf(fmt, ## args);} +#define APPL_TRACE_WARNING(fmt, args...) {if (appl_trace_level >= BT_TRACE_LEVEL_WARNING) ets_printf(fmt, ## args);} +#define APPL_TRACE_API(fmt, args...) {if (appl_trace_level >= BT_TRACE_LEVEL_API) ets_printf(fmt, ## args);} +#define APPL_TRACE_EVENT(fmt, args...) {if (appl_trace_level >= BT_TRACE_LEVEL_EVENT) ets_printf(fmt, ## args);} +#define APPL_TRACE_DEBUG(fmt, args...) {if (appl_trace_level >= BT_TRACE_LEVEL_DEBUG) ets_printf(fmt, ## args);} +#define APPL_TRACE_VERBOSE(fmt, args...) {if (appl_trace_level >= BT_TRACE_LEVEL_VERBOSE) ets_printf(fmt, ## args);} + +/* Simplified Trace Helper Macro +*/ +#define bdld(fmt, args...) \ + do{\ + if((MY_LOG_LEVEL) >= BT_TRACE_LEVEL_DEBUG) \ + ets_printf(fmt, ## args); \ + }while(0) + +#define bdlw(fmt, args...) \ + do{\ + if((MY_LOG_LEVEL) >= BT_TRACE_LEVEL_DEBUG) \ + ets_printf(fmt, ## args); \ + }while(0) + +#define bdle(fmt, args...) \ + do{\ + if((MY_LOG_LEVEL) >= BT_TRACE_LEVEL_DEBUG) \ + ets_printf(fmt, ## args); \ + }while(0) + +#define bdla(assert_if) \ + do{\ + if(((MY_LOG_LEVEL) >= BT_TRACE_LEVEL_ERROR) && !(assert_if)) \ + ets_printf("%s: assert failed\n", #assert_if); \ + }while(0) + +typedef UINT8 tBTTRC_PARAM_TYPE; +typedef UINT8 tBTTRC_LAYER_ID; +typedef UINT8 tBTTRC_TYPE; + +typedef struct { + tBTTRC_LAYER_ID layer_id; + tBTTRC_TYPE type; /* TODO: use tBTTRC_TYPE instead of "classical level 0-5" */ +} tBTTRC_LEVEL; + +typedef UINT8 (tBTTRC_SET_TRACE_LEVEL)( UINT8 ); + +typedef struct { + const tBTTRC_LAYER_ID layer_id_start; + const tBTTRC_LAYER_ID layer_id_end; + tBTTRC_SET_TRACE_LEVEL *p_f; + const char *trc_name; + UINT8 trace_level; +} tBTTRC_FUNC_MAP; + +/* External declaration for appl_trace_level here to avoid to add the declaration in all the files using APPL_TRACExxx macros */ +extern UINT8 appl_trace_level; + +#endif /*_BT_TRACE_H_*/ diff --git a/components/bt/bluedroid/include/bt_vendor_lib.h b/components/bt/bluedroid/include/bt_vendor_lib.h new file mode 100755 index 0000000000..3d563e1bed --- /dev/null +++ b/components/bt/bluedroid/include/bt_vendor_lib.h @@ -0,0 +1,362 @@ +/****************************************************************************** + * + * Copyright (C) 2009-2012 Broadcom Corporation + * + * 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. + * + ******************************************************************************/ + +#ifndef BT_VENDOR_LIB_H +#define BT_VENDOR_LIB_H + +#include +//#include +//#include + +/** Struct types */ + + +/** Typedefs and defines */ + +/** Vendor specific operations OPCODE */ +typedef enum { +/* [operation] + * Power on or off the BT Controller. + * [input param] + * A pointer to int type with content of bt_vendor_power_state_t. + * Typecasting conversion: (int *) param. + * [return] + * 0 - default, don't care. + * [callback] + * None. + */ + BT_VND_OP_POWER_CTRL, + +/* [operation] + * Perform any vendor specific initialization or configuration + * on the BT Controller. This is called before stack initialization. + * [input param] + * None. + * [return] + * 0 - default, don't care. + * [callback] + * Must call fwcfg_cb to notify the stack of the completion of vendor + * specific initialization once it has been done. + */ + BT_VND_OP_FW_CFG, + +/* [operation] + * Perform any vendor specific SCO/PCM configuration on the BT Controller. + * This is called after stack initialization. + * [input param] + * None. + * [return] + * 0 - default, don't care. + * [callback] + * Must call scocfg_cb to notify the stack of the completion of vendor + * specific SCO configuration once it has been done. + */ + BT_VND_OP_SCO_CFG, + +/* [operation] + * Open UART port on where the BT Controller is attached. + * This is called before stack initialization. + * [input param] + * A pointer to int array type for open file descriptors. + * The mapping of HCI channel to fd slot in the int array is given in + * bt_vendor_hci_channels_t. + * And, it requires the vendor lib to fill up the content before returning + * the call. + * Typecasting conversion: (int (*)[]) param. + * [return] + * Numbers of opened file descriptors. + * Valid number: + * 1 - CMD/EVT/ACL-In/ACL-Out via the same fd (e.g. UART) + * 2 - CMD/EVT on one fd, and ACL-In/ACL-Out on the other fd + * 4 - CMD, EVT, ACL-In, ACL-Out are on their individual fd + * [callback] + * None. + */ + BT_VND_OP_USERIAL_OPEN, + +/* [operation] + * Close the previously opened UART port. + * [input param] + * None. + * [return] + * 0 - default, don't care. + * [callback] + * None. + */ + BT_VND_OP_USERIAL_CLOSE, + +/* [operation] + * Get the LPM idle timeout in milliseconds. + * The stack uses this information to launch a timer delay before it + * attempts to de-assert LPM WAKE signal once downstream HCI packet + * has been delivered. + * [input param] + * A pointer to uint32_t type which is passed in by the stack. And, it + * requires the vendor lib to fill up the content before returning + * the call. + * Typecasting conversion: (uint32_t *) param. + * [return] + * 0 - default, don't care. + * [callback] + * None. + */ + BT_VND_OP_GET_LPM_IDLE_TIMEOUT, + +/* [operation] + * Enable or disable LPM mode on BT Controller. + * [input param] + * A pointer to uint8_t type with content of bt_vendor_lpm_mode_t. + * Typecasting conversion: (uint8_t *) param. + * [return] + * 0 - default, don't care. + * [callback] + * Must call lpm_cb to notify the stack of the completion of LPM + * disable/enable process once it has been done. + */ + BT_VND_OP_LPM_SET_MODE, + +/* [operation] + * Assert or Deassert LPM WAKE on BT Controller. + * [input param] + * A pointer to uint8_t type with content of bt_vendor_lpm_wake_state_t. + * Typecasting conversion: (uint8_t *) param. + * [return] + * 0 - default, don't care. + * [callback] + * None. + */ + BT_VND_OP_LPM_WAKE_SET_STATE, + +/* [operation] + * Perform any vendor specific commands related to audio state changes. + * [input param] + * a pointer to bt_vendor_op_audio_state_t indicating what audio state is + * set. + * [return] + * 0 - default, don't care. + * [callback] + * None. + */ + BT_VND_OP_SET_AUDIO_STATE, + +/* [operation] + * The epilog call to the vendor module so that it can perform any + * vendor-specific processes (e.g. send a HCI_RESET to BT Controller) + * before the caller calls for cleanup(). + * [input param] + * None. + * [return] + * 0 - default, don't care. + * [callback] + * Must call epilog_cb to notify the stack of the completion of vendor + * specific epilog process once it has been done. + */ + BT_VND_OP_EPILOG, +} bt_vendor_opcode_t; + +/** Power on/off control states */ +typedef enum { + BT_VND_PWR_OFF, + BT_VND_PWR_ON, +} bt_vendor_power_state_t; + +/** Define HCI channel identifier in the file descriptors array + used in BT_VND_OP_USERIAL_OPEN operation. + */ +typedef enum { + CH_CMD, // HCI Command channel + CH_EVT, // HCI Event channel + CH_ACL_OUT, // HCI ACL downstream channel + CH_ACL_IN, // HCI ACL upstream channel + + CH_MAX // Total channels +} bt_vendor_hci_channels_t; + +/** LPM disable/enable request */ +typedef enum { + BT_VND_LPM_DISABLE, + BT_VND_LPM_ENABLE, +} bt_vendor_lpm_mode_t; + +/** LPM WAKE set state request */ +typedef enum { + BT_VND_LPM_WAKE_ASSERT, + BT_VND_LPM_WAKE_DEASSERT, +} bt_vendor_lpm_wake_state_t; + +/** Callback result values */ +typedef enum { + BT_VND_OP_RESULT_SUCCESS, + BT_VND_OP_RESULT_FAIL, +} bt_vendor_op_result_t; + +/** audio (SCO) state changes triggering VS commands for configuration */ +typedef struct { + uint16_t handle; + uint16_t peer_codec; + uint16_t state; +} bt_vendor_op_audio_state_t; + +/* + * Bluetooth Host/Controller Vendor callback structure. + */ + +/* vendor initialization/configuration callback */ +typedef void (*cfg_result_cb)(bt_vendor_op_result_t result); + +/* datapath buffer allocation callback (callout) + * + * Vendor lib needs to request a buffer through the alloc callout function + * from HCI lib if the buffer is for constructing a HCI Command packet which + * will be sent through xmit_cb to BT Controller. + * + * For each buffer allocation, the requested size needs to be big enough to + * accommodate the below header plus a complete HCI packet -- + * typedef struct + * { + * uint16_t event; + * uint16_t len; + * uint16_t offset; + * uint16_t layer_specific; + * } HC_BT_HDR; + * + * HCI lib returns a pointer to the buffer where Vendor lib should use to + * construct a HCI command packet as below format: + * + * -------------------------------------------- + * | HC_BT_HDR | HCI command | + * -------------------------------------------- + * where + * HC_BT_HDR.event = 0x2000; + * HC_BT_HDR.len = Length of HCI command; + * HC_BT_HDR.offset = 0; + * HC_BT_HDR.layer_specific = 0; + * + * For example, a HCI_RESET Command will be formed as + * ------------------------ + * | HC_BT_HDR |03|0c|00| + * ------------------------ + * with + * HC_BT_HDR.event = 0x2000; + * HC_BT_HDR.len = 3; + * HC_BT_HDR.offset = 0; + * HC_BT_HDR.layer_specific = 0; + */ +typedef void* (*malloc_cb)(int size); + +/* datapath buffer deallocation callback (callout) */ +typedef void (*mdealloc_cb)(void *p_buf); + +/* define callback of the cmd_xmit_cb + * + * The callback function which HCI lib will call with the return of command + * complete packet. Vendor lib is responsible for releasing the buffer passed + * in at the p_mem parameter by calling dealloc callout function. + */ +typedef void (*tINT_CMD_CBACK)(void *p_mem); + +/* hci command packet transmit callback (callout) + * + * Vendor lib calls xmit_cb callout function in order to send a HCI Command + * packet to BT Controller. The buffer carrying HCI Command packet content + * needs to be first allocated through the alloc callout function. + * HCI lib will release the buffer for Vendor lib once it has delivered the + * packet content to BT Controller. + * + * Vendor lib needs also provide a callback function (p_cback) which HCI lib + * will call with the return of command complete packet. + * + * The opcode parameter gives the HCI OpCode (combination of OGF and OCF) of + * HCI Command packet. For example, opcode = 0x0c03 for the HCI_RESET command + * packet. + */ +typedef uint8_t (*cmd_xmit_cb)(uint16_t opcode, void *p_buf, tINT_CMD_CBACK p_cback); + +typedef struct { + /** set to sizeof(bt_vendor_callbacks_t) */ + size_t size; + + /* + * Callback and callout functions have implemented in HCI libray + * (libbt-hci.so). + */ + + /* notifies caller result of firmware configuration request */ + cfg_result_cb fwcfg_cb; + + /* notifies caller result of sco configuration request */ + cfg_result_cb scocfg_cb; + + /* notifies caller result of lpm enable/disable */ + cfg_result_cb lpm_cb; + + /* notifies the result of codec setting */ + cfg_result_cb audio_state_cb; + + /* buffer allocation request */ + malloc_cb alloc; + + /* buffer deallocation request */ + mdealloc_cb dealloc; + + /* hci command packet transmit request */ + cmd_xmit_cb xmit_cb; + + /* notifies caller completion of epilog process */ + cfg_result_cb epilog_cb; +} bt_vendor_callbacks_t; + +/* + * Bluetooth Host/Controller VENDOR Interface + */ +typedef struct { + /** Set to sizeof(bt_vndor_interface_t) */ + size_t size; + + /* + * Functions need to be implemented in Vendor libray (libbt-vendor.so). + */ + + /** + * Caller will open the interface and pass in the callback routines + * to the implemenation of this interface. + */ + int (*init)(const bt_vendor_callbacks_t* p_cb, unsigned char *local_bdaddr); + + /** Vendor specific operations */ + int (*op)(bt_vendor_opcode_t opcode, void *param); + + /** Closes the interface */ + void (*cleanup)(void); +} bt_vendor_interface_t; + + +/* + * External shared lib functions/data + */ + +/* Entry point of DLib -- + * Vendor library needs to implement the body of bt_vendor_interface_t + * structure and uses the below name as the variable name. HCI library + * will use this symbol name to get address of the object through the + * dlsym call. + */ +//extern const bt_vendor_interface_t BLUETOOTH_VENDOR_LIB_INTERFACE; + +#endif /* BT_VENDOR_LIB_H */ + diff --git a/components/bt/bluedroid/include/bte.h b/components/bt/bluedroid/include/bte.h new file mode 100755 index 0000000000..3338fd2d90 --- /dev/null +++ b/components/bt/bluedroid/include/bte.h @@ -0,0 +1,118 @@ +/****************************************************************************** + * + * Copyright (C) 2001-2012 Broadcom Corporation + * + * 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 constants and definitions for the bte project + * + ******************************************************************************/ +#ifndef BTE_H +#define BTE_H + +//#include +//#include +//#include +#include "bt_target.h" + +/* by default on shutdown, baudrate is reset 115kbits. this should NOT be need for platforms + * that kill BTE driver and remove/reset BT chip + */ +#ifndef BTE_RESET_BAUD_ON_BT_DISABLE +#define BTE_RESET_BAUD_ON_BT_DISABLE TRUE +#endif + +/* Target Modes (based on jumper settings on hardware [see user manual]) */ +enum +{ + /* BTE BBY */ + /* J3 J4 SW3-3 SW3-2 SW3-1 */ + /* -------------------------------------------- */ + BTE_MODE_SERIAL_APP, /* OUT OUT OFF OFF OFF Sample serial port application */ + BTE_MODE_APPL, /* IN OUT OFF OFF ON Target used with Tester through RPC */ + BTE_MODE_RESERVED, /* OUT IN OFF ON OFF Reserved */ + BTE_MODE_SAMPLE_APPS, /* IN IN OFF ON ON Sample applications (ICP/HSP) */ + BTE_MODE_DONGLE, /* not yet supported ON OFF OFF Dongle mode */ + BTE_MODE_APPL_PROTOCOL_TRACE, /* this is a fake mode do allow protocol tracing in application without rpc */ + BTE_MODE_INVALID +}; + +extern volatile UINT8 bte_target_mode; /* indicates the mode that the board is running in */ + +/* Startup options */ +extern UINT32 bte_startup_options; /* Switch and jumper settings at startup */ +void bte_get_startup_options(UINT32 *p_options); /* Platform specific function for getting startup options */ + +#define BTE_OPTIONS_TARGET_MODE_MASK 0x00000007 /* bits 2-0 indicate target mode (QuickConnect: jp3 & jp4, BBY: SW3-1 & SW3-2)*/ + + +/**************************************************************************** + * Definitions to define which type of application gets built + ****************************************************************************/ +#define BUILD_HCITOOL FALSE +#define BUILD_L2PING FALSE + + +#define LINUX_FM_DRIVER_INCLUDED FALSE + + +/* hcisu userial operations. should probably go into bt_types to avoid collisions! */ +#define BT_EVT_TO_HCISU_USERIAL_OP (0x0080 | BT_EVT_HCISU) +/* operation for above hcisu event */ +#define BT_HCISU_USERIAL_OPEN (0) /* open serial port calling USERIAL_Open() */ +#define BT_HCISU_USERIAL_CLOSE (1) /* close userial port */ +/* options associated with close op */ +#define BT_HCISU_USERIAL_CL_NO_DIS_BT 0 /* do not touch bt_wake and power gpio */ +#define BT_HCISU_USERIAL_CL_DIS_BT 1 /* put power and bt_wake into defined off state to preserve + power */ +/* status codes for callback */ +/* +#define BTE_HCISU_USERIAL_FAIL 0 +#define BTE_HCISU_USERIAL_OK 1 +typedef void (tUSERIAL_MSG_CBACK) (int status); +typedef struct tHCISU_USERIAL_MSG_tag { + BT_HDR hdr; + tUSERIAL_MSG_CBACK *p_cback; + UINT8 port; // port number + UINT8 op; + UINT8 option; // option for operation. depends on operation +} tHCISU_USERIAL_MSG; + +extern void bte_hcisu_userial_oper( tUSERIAL_MSG_CBACK *p_cback, UINT8 port, UINT8 op, UINT8 option ); +*/ + +/* Pointer to function for sending HCI commands and data to the HCI tranport */ +extern int (*p_bte_hci_send)(UINT16 port, BT_HDR *p_msg); + + +/* Protocol trace mask */ +extern UINT32 bte_proto_trace_mask; + +typedef struct tBAUD_REG_tag { + UINT8 DHBR; + UINT8 DLBR; + UINT8 ExplicitBaudRate0; + UINT8 ExplicitBaudRate1; + UINT8 ExplicitBaudRate2; + UINT8 ExplicitBaudRate3; +} tBAUD_REG; + +#include "gki.h" + +extern const tBAUD_REG baud_rate_regs[]; + +#endif /* BTE_H */ diff --git a/components/bt/bluedroid/include/bte_appl.h b/components/bt/bluedroid/include/bte_appl.h new file mode 100755 index 0000000000..4850250b8a --- /dev/null +++ b/components/bt/bluedroid/include/bte_appl.h @@ -0,0 +1,37 @@ +/****************************************************************************** + * + * Copyright (C) 2002-2012 Broadcom Corporation + * + * 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 is the interface file for the bte application task + * + ******************************************************************************/ + +#pragma once + +typedef struct { +#if ((BLE_INCLUDED == TRUE) && (SMP_INCLUDED == TRUE)) + UINT8 ble_auth_req; + UINT8 ble_io_cap; + UINT8 ble_init_key; + UINT8 ble_resp_key; + UINT8 ble_max_key_size; +#endif +} tBTE_APPL_CFG; + +extern tBTE_APPL_CFG bte_appl_cfg; diff --git a/components/bt/bluedroid/include/gki_target.h b/components/bt/bluedroid/include/gki_target.h new file mode 100755 index 0000000000..fc8445189a --- /dev/null +++ b/components/bt/bluedroid/include/gki_target.h @@ -0,0 +1,244 @@ +/****************************************************************************** + * + * Copyright (C) 1999-2012 Broadcom Corporation + * + * 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. + * + ******************************************************************************/ + +#ifndef _GKI_TARGET_H_ +#define _GKI_TARGET_H_ + +/****************************************************************************** +** +** Buffer configuration +** +******************************************************************************/ + +/* The size of the buffers in pool 0. */ +#ifndef GKI_BUF0_SIZE +#define GKI_BUF0_SIZE 64 +#endif + +/* The number of buffers in buffer pool 0. */ +#ifndef GKI_BUF0_MAX +#define GKI_BUF0_MAX 96 +#endif + +/* The ID of buffer pool 0. */ +#ifndef GKI_POOL_ID_0 +#define GKI_POOL_ID_0 0 +#endif + +/* The size of the buffers in pool 1. */ +#ifndef GKI_BUF1_SIZE +#define GKI_BUF1_SIZE 288 +#endif + +/* The number of buffers in buffer pool 1. */ +#ifndef GKI_BUF1_MAX +#define GKI_BUF1_MAX 52 +#endif + +/* The ID of buffer pool 1. */ +#ifndef GKI_POOL_ID_1 +#define GKI_POOL_ID_1 1 +#endif + +/* The size of the buffers in pool 2. */ +#ifndef GKI_BUF2_SIZE +#define GKI_BUF2_SIZE 660 +#endif + +/* The number of buffers in buffer pool 2. */ +#ifndef GKI_BUF2_MAX +#define GKI_BUF2_MAX 90 +#endif + +/* The ID of buffer pool 2. */ +#ifndef GKI_POOL_ID_2 +#define GKI_POOL_ID_2 2 +#endif + +/* The size of the buffers in pool 3. */ +#ifndef GKI_BUF3_SIZE +#define GKI_BUF3_SIZE (4096+16) +#endif + +/* The number of buffers in buffer pool 3. */ +#ifndef GKI_BUF3_MAX +#define GKI_BUF3_MAX 400 +#endif + +/* The ID of buffer pool 3. */ +#ifndef GKI_POOL_ID_3 +#define GKI_POOL_ID_3 3 +#endif + +/* The size of the largest PUBLIC fixed buffer in system. */ +#ifndef GKI_MAX_BUF_SIZE +#define GKI_MAX_BUF_SIZE GKI_BUF3_SIZE +#endif + +/* The pool ID of the largest PUBLIC fixed buffer in system. */ +#ifndef GKI_MAX_BUF_SIZE_POOL_ID +#define GKI_MAX_BUF_SIZE_POOL_ID GKI_POOL_ID_3 +#endif + +/* Pool 4 is used for BluetoothSocket L2CAP connections */ +/* The size of the buffers in pool 4. */ +#ifndef GKI_BUF4_SIZE +#define GKI_BUF4_SIZE (8080+26) +#endif + +/* The number of buffers in buffer pool 4. */ +#ifndef GKI_BUF4_MAX +#define GKI_BUF4_MAX (OBX_NUM_SERVERS + OBX_NUM_CLIENTS) +#endif + +/* The ID of buffer pool 4. */ +#ifndef GKI_POOL_ID_4 +#define GKI_POOL_ID_4 4 +#endif + +/* The number of fixed GKI buffer pools. +eL2CAP requires Pool ID 5 +If BTM_SCO_HCI_INCLUDED is FALSE, Pool ID 6 is unnecessary, otherwise set to 7 +If BTA_HL_INCLUDED is FALSE then Pool ID 7 is uncessary and set the following to 7, otherwise set to 8 +If BLE_INCLUDED is FALSE then Pool ID 8 is uncessary and set the following to 8, otherwise set to 9 +POOL_ID 9 is a public pool meant for large buffer needs such as SDP_DB +*/ +#ifndef GKI_NUM_FIXED_BUF_POOLS +#define GKI_NUM_FIXED_BUF_POOLS 10 +#endif + +/* The buffer pool usage mask. */ +#ifndef GKI_DEF_BUFPOOL_PERM_MASK +/* Setting POOL_ID 9 as a public pool meant for large buffers such as SDP_DB */ +#define GKI_DEF_BUFPOOL_PERM_MASK 0xfdf0 +#endif + +/* The following is intended to be a reserved pool for L2CAP +Flow control and retransmissions and intentionally kept out +of order */ + +/* The number of buffers in buffer pool 5. */ +#ifndef GKI_BUF5_MAX +#define GKI_BUF5_MAX 64 +#endif + +/* The ID of buffer pool 5. */ +#ifndef GKI_POOL_ID_5 +#define GKI_POOL_ID_5 5 +#endif + +/* The size of the buffers in pool 5 +** Special pool used by L2CAP retransmissions only. This size based on segment +** that will fit into both DH5 and 2-DH3 packet types after accounting for GKI +** header. 13 bytes of max headers allows us a 339 payload max. (in btui_app.txt) +** Note: 748 used for insight scriptwrapper with CAT-2 scripts. +*/ +#ifndef GKI_BUF5_SIZE +#define GKI_BUF5_SIZE 748 +#endif + +/* The following is intended to be a reserved pool for SCO +over HCI data and intentionally kept out of order */ + +/* The ID of buffer pool 6. */ +#ifndef GKI_POOL_ID_6 +#define GKI_POOL_ID_6 6 +#endif + +/* The size of the buffers in pool 6, + BUF_SIZE = max SCO data 255 + sizeof(BT_HDR) = 8 + SCO packet header 3 + padding 2 = 268 */ +#ifndef GKI_BUF6_SIZE +#define GKI_BUF6_SIZE 268 +#endif + +/* The number of buffers in buffer pool 6. */ +#ifndef GKI_BUF6_MAX +#define GKI_BUF6_MAX 60 +#endif + + +/* The following pool is a dedicated pool for HDP + If a shared pool is more desirable then + 1. set BTA_HL_LRG_DATA_POOL_ID to the desired Gki Pool ID + 2. make sure that the shared pool size is larger than 9472 + 3. adjust GKI_NUM_FIXED_BUF_POOLS accordingly since + POOL ID 7 is not needed +*/ + +/* The ID of buffer pool 7. */ +#ifndef GKI_POOL_ID_7 +#define GKI_POOL_ID_7 7 +#endif + +/* The size of the buffers in pool 7 */ +#ifndef GKI_BUF7_SIZE +#define GKI_BUF7_SIZE (10240 + 24) +#endif + +/* The number of buffers in buffer pool 7. */ +#ifndef GKI_BUF7_MAX +#define GKI_BUF7_MAX 2 +#endif + +/* The following pool is a dedicated pool for GATT + If a shared pool is more desirable then + 1. set GATT_DB_POOL_ID to the desired Gki Pool ID + 2. make sure that the shared pool size fit a common GATT database needs + 3. adjust GKI_NUM_FIXED_BUF_POOLS accordingly since + POOL ID 8 is not needed +*/ + +/* The ID of buffer pool 8. */ +#ifndef GKI_POOL_ID_8 +#define GKI_POOL_ID_8 8 +#endif + +/* The size of the buffers in pool 8 */ +#ifndef GKI_BUF8_SIZE +#define GKI_BUF8_SIZE 128 +#endif + +/* The number of buffers in buffer pool 8. */ +#ifndef GKI_BUF8_MAX +#define GKI_BUF8_MAX 30 +#endif + +/* The following pool is meant for large allocations such as SDP_DB */ +#ifndef GKI_POOL_ID_9 +#define GKI_POOL_ID_9 9 +#endif + +#ifndef GKI_BUF9_SIZE +#define GKI_BUF9_SIZE 8192 +#endif + +#ifndef GKI_BUF9_MAX +#define GKI_BUF9_MAX 5 +#endif + +/* The number of fixed and dynamic buffer pools */ +#ifndef GKI_NUM_TOTAL_BUF_POOLS +#define GKI_NUM_TOTAL_BUF_POOLS 10 +#endif + +int gki_init(void); +void gki_clean_up(void); + +//void LogMsg (UINT32 trace_set_mask, const char *fmt_str, ...); + +#endif /*_GKI_TARGET_H_*/ diff --git a/components/bt/bluedroid/main/bte_init.c b/components/bt/bluedroid/main/bte_init.c new file mode 100755 index 0000000000..0cb24b8d0f --- /dev/null +++ b/components/bt/bluedroid/main/bte_init.c @@ -0,0 +1,216 @@ +/****************************************************************************** + * + * Copyright (C) 2000-2012 Broadcom Corporation + * + * 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 module contains the routines that initialize the stack components. + * It must be called before the BTU task is started. + * + ******************************************************************************/ + +#include "bt_target.h" +#include + +/* Stack Configuation Related Init Definaton + * TODO: Now Just Unmask these defination until stack layer is OK + */ + +#ifndef BTA_INCLUDED +#define BTA_INCLUDED FALSE +#endif + +#if (defined(RFCOMM_INCLUDED) && RFCOMM_INCLUDED == TRUE) +// Include initialization functions definitions +#include "port_api.h" +#endif + +#if (defined(BNEP_INCLUDED) && BNEP_INCLUDED == TRUE) +#include "bnep_api.h" +#endif + +#if (defined(GAP_INCLUDED) && GAP_INCLUDED == TRUE) +#include "gap_api.h" +#endif + +#if (defined(PAN_INCLUDED) && PAN_INCLUDED == TRUE) +#include "pan_api.h" +#endif + +#if (defined(AVRC_INCLUDED) && AVRC_INCLUDED == TRUE) +#include "avrc_api.h" +#endif + +#if (defined(A2D_INCLUDED) && A2D_INCLUDED == TRUE) +#include "a2d_api.h" +#endif + +#if (defined(HID_HOST_INCLUDED) && HID_HOST_INCLUDED == TRUE) +#include "hidh_api.h" +#endif + +#if (defined(MCA_INCLUDED) && MCA_INCLUDED == TRUE) +#include "mca_api.h" +#endif + +#if (defined(BLE_INCLUDED) && BLE_INCLUDED == TRUE) +#include "gatt_api.h" +#if (defined(SMP_INCLUDED) && SMP_INCLUDED == TRUE) +#include "smp_api.h" +#endif +#endif + +//BTA Modules +#if BTA_INCLUDED == TRUE && BTA_DYNAMIC_MEMORY == TRUE +#include "bta_api.h" +#include "bta_sys.h" + +#include "bta_ag_int.h" + +#if BTA_HS_INCLUDED == TRUE +#include "bta_hs_int.h" +#endif + +#include "bta_dm_int.h" + +#if BTA_AR_INCLUDED==TRUE +#include "bta_ar_int.h" +#endif +#if BTA_AV_INCLUDED==TRUE +#include "bta_av_int.h" +#endif + +#if BTA_HH_INCLUDED==TRUE +#include "bta_hh_int.h" +#endif + +#if BTA_JV_INCLUDED==TRUE +#include "bta_jv_int.h" +tBTA_JV_CB *bta_jv_cb_ptr = NULL; +#endif + +#if BTA_HL_INCLUDED == TRUE +#include "bta_hl_int.h" +#endif + +#if BTA_GATT_INCLUDED == TRUE +#include "bta_gattc_int.h" +#include "bta_gatts_int.h" +#endif + +#if BTA_PAN_INCLUDED==TRUE +#include "bta_pan_int.h" +#endif + +#include "bta_sys_int.h" + +// control block for patch ram downloading +#include "bta_prm_int.h" + +#endif // BTA_INCLUDED + + +/***************************************************************************** +** F U N C T I O N S * +******************************************************************************/ + +/***************************************************************************** +** +** Function BTE_InitStack +** +** Description Initialize control block memory for each component. +** +** Note: The core stack components must be called +** before creating the BTU Task. The rest of the +** components can be initialized at a later time if desired +** as long as the component's init function is called +** before accessing any of its functions. +** +** Returns void +** +******************************************************************************/ +void BTE_InitStack(void) +{ +#if (defined(RFCOMM_INCLUDED) && RFCOMM_INCLUDED == TRUE) + //Initialize the optional stack components + RFCOMM_Init(); +#endif + + //BNEP and its profiles +#if (defined(BNEP_INCLUDED) && BNEP_INCLUDED == TRUE) + BNEP_Init(); + +#if (defined(PAN_INCLUDED) && PAN_INCLUDED == TRUE) + PAN_Init(); +#endif // PAN +#endif // BNEP Included + + + //AVDT and its profiles +#if (defined(A2D_INCLUDED) && A2D_INCLUDED == TRUE) + A2D_Init(); +#endif // AADP + +#if (defined(AVRC_INCLUDED) && AVRC_INCLUDED == TRUE) + AVRC_Init(); +#endif + +#if (defined(GAP_INCLUDED) && GAP_INCLUDED == TRUE) + GAP_Init(); +#endif + +#if (defined(HID_HOST_INCLUDED) && HID_HOST_INCLUDED == TRUE) + HID_HostInit(); +#endif + +#if (defined(MCA_INCLUDED) && MCA_INCLUDED == TRUE) + MCA_Init(); +#endif + + //BTA Modules +#if (BTA_INCLUDED == TRUE && BTA_DYNAMIC_MEMORY == TRUE) + memset((void*)bta_sys_cb_ptr, 0, sizeof(tBTA_SYS_CB)); + memset((void*)bta_dm_cb_ptr, 0, sizeof(tBTA_DM_CB)); + memset((void*)bta_dm_search_cb_ptr, 0, sizeof(tBTA_DM_SEARCH_CB)); + memset((void*)bta_dm_di_cb_ptr, 0, sizeof(tBTA_DM_DI_CB)); + memset((void*)bta_prm_cb_ptr, 0, sizeof(tBTA_PRM_CB)); + memset((void*)bta_ag_cb_ptr, 0, sizeof(tBTA_AG_CB)); +#if BTA_HS_INCLUDED == TRUE + memset((void*)bta_hs_cb_ptr, 0, sizeof(tBTA_HS_CB)); +#endif +#if BTA_AR_INCLUDED==TRUE + memset((void *)bta_ar_cb_ptr, 0, sizeof(tBTA_AR_CB)); +#endif +#if BTA_AV_INCLUDED==TRUE + memset((void *)bta_av_cb_ptr, 0, sizeof(tBTA_AV_CB)); +#endif +#if BTA_HH_INCLUDED==TRUE + memset((void *)bta_hh_cb_ptr, 0, sizeof(tBTA_HH_CB)); +#endif +#if BTA_HL_INCLUDED==TRUE + memset((void *)bta_hl_cb_ptr, 0, sizeof(tBTA_HL_CB)); +#endif +#if BTA_GATT_INCLUDED==TRUE + memset((void *)bta_gattc_cb_ptr, 0, sizeof(tBTA_GATTC_CB)); + memset((void *)bta_gatts_cb_ptr, 0, sizeof(tBTA_GATTS_CB)); +#endif +#if BTA_PAN_INCLUDED==TRUE + memset((void *)bta_pan_cb_ptr, 0, sizeof(tBTA_PAN_CB)); +#endif + +#endif // BTA_INCLUDED == TRUE +} diff --git a/components/bt/bluedroid/main/bte_main.c b/components/bt/bluedroid/main/bte_main.c new file mode 100755 index 0000000000..e41e33da31 --- /dev/null +++ b/components/bt/bluedroid/main/bte_main.c @@ -0,0 +1,324 @@ +/****************************************************************************** + * + * Copyright (C) 2009-2012 Broadcom Corporation + * + * 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. + * + ******************************************************************************/ + +/****************************************************************************** + * + * Filename: bte_main.c + * + * Description: Contains BTE core stack initialization and shutdown code + * + ******************************************************************************/ + + +#include "bt_defs.h" +#include "bte.h" +#include "btu.h" +#include "bt_trace.h" +#include "osi.h" +#include "alarm.h" +#include "fixed_queue.h" +#include "hash_map.h" +#include "hash_functions.h" +#include "controller.h" +#include "hci_layer.h" + +#include "bt_app_common.h" +//#include "bluedroid_test.h" +/* +#define LOG_TAG "bt_main" + +#include +#include +#include +#include +#include +#include +#include + +#include "osi/include/alarm.h" +#include "bta_api.h" +#include "bt_hci_bdroid.h" +#include "bte.h" +#include "btif_common.h" +#include "btu.h" +#include "btsnoop.h" +#include "bt_utils.h" +#include "btcore/include/counter.h" +#include "btcore/include/module.h" +#include "osi/include/fixed_queue.h" +#include "osi/include/future.h" +#include "gki.h" +#include "osi/include/hash_functions.h" +#include "osi/include/hash_map.h" +#include "hci_layer.h" +#include "osi/include/osi.h" +#include "osi/include/log.h" +#include "stack_config.h" +#include "osi/include/thread.h" +*/ +/******************************************************************************* +** Constants & Macros +*******************************************************************************/ + +/* Run-time configuration file for BLE*/ +/* +#ifndef BTE_BLE_STACK_CONF_FILE +#define BTE_BLE_STACK_CONF_FILE "/etc/bluetooth/ble_stack.conf" +#endif +*/ +/****************************************************************************** +** Variables +******************************************************************************/ + +/******************************************************************************* +** Static variables +*******************************************************************************/ +static const hci_t *hci; +static void bte_main_enable(void); +/******************************************************************************* +** Static functions +*******************************************************************************/ + +/******************************************************************************* +** Externs +*******************************************************************************/ +//extern void bte_load_ble_conf(const char *p_path); +fixed_queue_t *btu_hci_msg_queue; + +/****************************************************************************** +** +** Function bte_main_boot_entry +** +** Description BTE MAIN API - Entry point for BTE chip/stack initialization +** +** Returns None +** +******************************************************************************/ +void bte_main_boot_entry(void) +{ + if (gki_init()) + LOG_ERROR("%s: Init GKI Module Failure.\n", __func__); + + hci = hci_layer_get_interface(); + if (!hci) + LOG_ERROR("%s could not get hci layer interface.\n", __func__); + + btu_hci_msg_queue = fixed_queue_new(SIZE_MAX); + if (btu_hci_msg_queue == NULL) { + LOG_ERROR("%s unable to allocate hci message queue.\n", __func__); + return; + } + + //Caution: No event dispatcher defined now in hci layer + //data_dispatcher_register_default(hci->event_dispatcher, btu_hci_msg_queue); + hci->set_data_queue(btu_hci_msg_queue); + + osi_alarm_init(); + +#if (defined(BLE_INCLUDED) && (BLE_INCLUDED == TRUE)) + //bte_load_ble_conf(BTE_BLE_STACK_CONF_FILE); +#endif + //TODO: STACK CONFIG Module init + //module_init(get_module(STACK_CONFIG_MODULE)); + + // set up bt application task +#if (defined(BT_APP_DEMO) && BT_APP_DEMO == TRUE) + bt_app1_task_start_up(); + // bt_app_start_up(); +#endif + + //Enbale HCI + bte_main_enable(); + + // LOG_ERROR("Test HCI Command\n"); + // controller_get_interface()->devctl_reset(NULL); + + //LOG_ERROR("Test bta_enable_bt\n"); + //bt_test_bta_enable_bt(); + + //LOG_ERROR("Test ble_advertise\n"); + //bt_test_ble_advertise(); + +} + +/****************************************************************************** +** +** Function bte_main_shutdown +** +** Description BTE MAIN API - Shutdown code for BTE chip/stack +** +** Returns None +** +******************************************************************************/ +void bte_main_shutdown() +{ + //data_dispatcher_register_default(hci_layer_get_interface()->event_dispatcher, NULL); + hci->set_data_queue(NULL); + fixed_queue_free(btu_hci_msg_queue, NULL); + + btu_hci_msg_queue = NULL; + +/* + module_clean_up(get_module(STACK_CONFIG_MODULE)); + + module_clean_up(get_module(COUNTER_MODULE)); + module_clean_up(get_module(GKI_MODULE)); +*/ + + gki_clean_up(); +} + +/****************************************************************************** +** +** Function bte_main_enable +** +** Description BTE MAIN API - Creates all the BTE tasks. Should be called +** part of the Bluetooth stack enable sequence +** +** Returns None +** +******************************************************************************/ +static void bte_main_enable(void) +{ + LOG_DEBUG("Enable HCI\n"); + if (hci_start_up()) { + LOG_ERROR("Start HCI Host Layer Failure\n"); + return; + } + + //Now Test Case Not Supported BTU + LOG_ERROR("Startup BTU\n"); + BTU_StartUp(); +} + +/****************************************************************************** +** +** Function bte_main_disable +** +** Description BTE MAIN API - Destroys all the BTE tasks. Should be called +** part of the Bluetooth stack disable sequence +** +** Returns None +** +******************************************************************************/ +void bte_main_disable(void) +{ +/* + APPL_TRACE_DEBUG("%s", __FUNCTION__); + + module_shut_down(get_module(HCI_MODULE)); + module_shut_down(get_module(BTSNOOP_MODULE)); +*/ + + hci_shut_down(); + + BTU_ShutDown(); +} + +/****************************************************************************** +** +** Function bte_main_postload_cfg +** +** Description BTE MAIN API - Stack postload configuration +** +** Returns None +** +******************************************************************************/ +void bte_main_postload_cfg(void) +{ + hci->do_postload(); +} + +#if (defined(HCILP_INCLUDED) && HCILP_INCLUDED == TRUE) +/****************************************************************************** +** +** Function bte_main_enable_lpm +** +** Description BTE MAIN API - Enable/Disable low power mode operation +** +** Returns None +** +******************************************************************************/ +void bte_main_enable_lpm(BOOLEAN enable) +{ + /*Enable Low power ?*/ + //hci->send_low_power_command(enable ? LPM_ENABLE : LPM_DISABLE); +} + +/****************************************************************************** +** +** Function bte_main_lpm_allow_bt_device_sleep +** +** Description BTE MAIN API - Allow BT controller goest to sleep +** +** Returns None +** +******************************************************************************/ +void bte_main_lpm_allow_bt_device_sleep() +{ + /**/ + //hci->send_low_power_command(LPM_WAKE_DEASSERT); +} + +/****************************************************************************** +** +** Function bte_main_lpm_wake_bt_device +** +** Description BTE MAIN API - Wake BT controller up if it is in sleep mode +** +** Returns None +** +******************************************************************************/ +void bte_main_lpm_wake_bt_device() +{ + //hci->send_low_power_command(LPM_WAKE_ASSERT); +} +#endif // HCILP_INCLUDED + +/****************************************************************************** +** +** Function bte_main_hci_send +** +** Description BTE MAIN API - This function is called by the upper stack to +** send an HCI message. The function displays a protocol trace +** message (if enabled), and then calls the 'transmit' function +** associated with the currently selected HCI transport +** +** Returns None +** +******************************************************************************/ +void bte_main_hci_send (BT_HDR *p_msg, UINT16 event) +{ + UINT16 sub_event = event & BT_SUB_EVT_MASK; /* local controller ID */ + + p_msg->event = event; + + //counter_add("main.tx.packets", 1); + //counter_add("main.tx.bytes", p_msg->len); + + if((sub_event == LOCAL_BR_EDR_CONTROLLER_ID) || \ + (sub_event == LOCAL_BLE_CONTROLLER_ID)) + { + hci->transmit_downward(event, p_msg); + } + else + { + //APPL_TRACE_ERROR("Invalid Controller ID. Discarding message."); + GKI_freebuf(p_msg); + } +} diff --git a/components/bt/bluedroid/mk.sh b/components/bt/bluedroid/mk.sh new file mode 100755 index 0000000000..6665fd6001 --- /dev/null +++ b/components/bt/bluedroid/mk.sh @@ -0,0 +1,12 @@ +#!/bin/bash + +FIND_F=component.mk +MV_F=Makefile.backup + +for mkf in `find . -name "$FIND_F"` +do + echo $mkf + mkf_n=`echo $mkf | sed -n "s/$FIND_F/$MV_F/p"` + echo $mkf_n + mv $mkf $mkf_n +done diff --git a/components/bt/bluedroid/osi/alarm.c b/components/bt/bluedroid/osi/alarm.c new file mode 100755 index 0000000000..405ffaabe3 --- /dev/null +++ b/components/bt/bluedroid/osi/alarm.c @@ -0,0 +1,184 @@ +/****************************************************************************** + * + * Copyright (C) 2014 Google, Inc. + * + * 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. + * + ******************************************************************************/ +#include +#include +#include +#include "bt_defs.h" +#include "bt_trace.h" +#include "alarm.h" +#include "allocator.h" +#include "list.h" +#include "thread.h" +#include "freertos/FreeRTOSConfig.h" +#include "freertos/xtensa_api.h" +#include "rom/ets_sys.h" + +#define RTC_TIMER_TICKS_TO_MS(ticks) ((ticks/625)<<1 + (ticks-(ticks/625)*625)/312) + + +#define BT_ALARM_START_WAIT_TICKS 100 +#define BT_ALARM_STOP_WAIT_TICKS 100 +#define BT_ALARM_FREE_WAIT_TICKS 100 +#define BT_ALARM_CHG_PERIOD_WAIT_TICKS 100 + +static struct alarm_t alarm_cbs[ALARM_CBS_NUM]; + +void osi_alarm_init(void) +{ + memset(&alarm_cbs[0], 0x00, sizeof(alarm_cbs)); +} + +static struct alarm_t *alarm_cbs_lookfor_available(void) +{ + int i; + + for (i = 0; i < ALARM_CBS_NUM; i++) { + if (alarm_cbs[i].alarm_hdl == NULL) { //available + ets_printf(">>>> %d %08x<<<<\n", i, &alarm_cbs[i]); + return &alarm_cbs[i]; + } + } + + return NULL; +} + +static void alarm_cb_handler(TimerHandle_t xTimer) +{ + struct alarm_t *alarm; + + ets_printf("*********************************************************\n"); + if (!xTimer) { + ets_printf("TimerName: NULL\n"); + return; + } + + alarm = pvTimerGetTimerID(xTimer); + ets_printf("TimerID %08x, Name %s\n", alarm, pcTimerGetTimerName(xTimer)); + if (alarm->cb) { + alarm->cb(alarm->cb_data); + } +} + +osi_alarm_t *osi_alarm_new(char *alarm_name, osi_alarm_callback_t callback, void *data, period_ms_t timer_expire) +{ + struct alarm_t *timer_id; + TimerHandle_t t; + + if (timer_expire == 0) + timer_expire = 1000; + + /* TODO mutex lock */ + timer_id = alarm_cbs_lookfor_available(); + if (!timer_id) { + ets_printf("%s full\n", __func__); + return NULL; + } + + t = xTimerCreate(alarm_name, timer_expire / portTICK_PERIOD_MS, pdFALSE, timer_id, alarm_cb_handler); + if (!t) { + ets_printf("%s error\n", __func__); + return NULL; + } + + timer_id->alarm_hdl = t; + timer_id->cb = callback; + timer_id->cb_data = data; + /* TODO mutex unlock */ + + return timer_id; +} + +int osi_alarm_free(osi_alarm_t *alarm) +{ + if (!alarm) { + ets_printf("%s null\n", __func__); + return -1; + } + + if (xTimerDelete(alarm->alarm_hdl, BT_ALARM_FREE_WAIT_TICKS) != pdPASS) { + ets_printf("%s error\n", __func__); + return -2; + } + + /* TODO mutex lock */ + memset(alarm, 0x00, sizeof(osi_alarm_t)); + /* TODO mutex unlock */ + + return 0; +} + + +int osi_alarm_set(osi_alarm_t *alarm, period_ms_t timeout) { + if (!alarm) { + ets_printf("%s null\n", __func__); + return -1; + } + + if (xTimerChangePeriod(alarm->alarm_hdl, timeout / portTICK_PERIOD_MS, BT_ALARM_CHG_PERIOD_WAIT_TICKS) != pdPASS) { + ets_printf("%s chg period error\n", __func__); + return -2; + } + + if (xTimerStart(alarm->alarm_hdl, BT_ALARM_START_WAIT_TICKS) != pdPASS) { + ets_printf("%s start error\n", __func__); + return -3; + } + + return 0; +} + + +int osi_alarm_cancel(osi_alarm_t *alarm) { + if (!alarm) { + ets_printf("%s null\n", __func__); + return -1; + } + + if (xTimerStop(alarm->alarm_hdl, BT_ALARM_STOP_WAIT_TICKS) != pdPASS) { + ets_printf("%s error\n", __func__); + return -2; + } + + return 0; +} + +static uint32_t alarm_current_tick(void) { + return xTaskGetTickCount(); +} + +// todo: this is not accurate +// max return value: 0xffffffff / 312 = 13765920 = 0xD20D20 +period_ms_t osi_alarm_now(void) { + return RTC_TIMER_TICKS_TO_MS((alarm_current_tick())); +} + +period_ms_t osi_alarm_get_remaining_ms(const osi_alarm_t *alarm) +{ + /* TODO: use FreeRTOS timer.c implement ??? */ + return 0xffffffff; +} + +// pre-condition: 0 <= t1, t2 <= 0xD20D20 +// return value: 0<= ret <=0XD20D20 +period_ms_t osi_alarm_time_diff(period_ms_t t1, period_ms_t t2) { +#define MAX_ALARM_TIME_MS (0xD20D20) + int32_t diff = (int32_t)(t1) - (int32_t)(t2); + if (diff < 0) + diff += MAX_ALARM_TIME_MS; + return (period_ms_t)diff; +} diff --git a/components/bt/bluedroid/osi/allocator.c b/components/bt/bluedroid/osi/allocator.c new file mode 100755 index 0000000000..2e42c03167 --- /dev/null +++ b/components/bt/bluedroid/osi/allocator.c @@ -0,0 +1,58 @@ +/****************************************************************************** + * + * Copyright (C) 2014 Google, Inc. + * + * 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. + * + ******************************************************************************/ +#include +#include + +#include "bt_defs.h" +#include "allocator.h" + +extern void *pvPortZalloc(size_t size); +extern void vPortFree(void *pv); + +char *osi_strdup(const char *str) { + size_t size = strlen(str) + 1; // + 1 for the null terminator + char *new_string = (char *)calloc(1, size); + + if (!new_string) + return NULL; + + memcpy(new_string, str, size); + return new_string; +} + +void *osi_malloc(size_t size) { + return calloc(1, size); +} + +void *osi_calloc(size_t size) { + return calloc(1, size); +} + +void osi_free(void *ptr) { + free(ptr); +} + +const allocator_t allocator_malloc = { + osi_malloc, + osi_free +}; + +const allocator_t allocator_calloc = { + osi_calloc, + osi_free +}; diff --git a/components/bt/bluedroid/osi/buffer.c b/components/bt/bluedroid/osi/buffer.c new file mode 100755 index 0000000000..4b96e2df24 --- /dev/null +++ b/components/bt/bluedroid/osi/buffer.c @@ -0,0 +1,96 @@ +/****************************************************************************** + * + * Copyright (C) 2014 Google, Inc. + * + * 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. + * + ******************************************************************************/ +#include +#include "bt_trace.h" +#include "allocator.h" +#include "buffer.h" +#include "bt_defs.h" +#include "bt_trace.h" + +struct buffer_t { + buffer_t *root; + size_t refcount; + size_t length; + uint8_t data[]; +}; + +buffer_t *buffer_new(size_t size) { + assert(size > 0); + + buffer_t *buffer = osi_malloc(sizeof(buffer_t) + size); + if (!buffer) { + LOG_ERROR("%s unable to allocate buffer of %zu bytes.", __func__, size); + return NULL; + } + + buffer->root = buffer; + buffer->refcount = 1; + buffer->length = size; + + return buffer; +} + +buffer_t *buffer_new_ref(const buffer_t *buf) { + assert(buf != NULL); + return buffer_new_slice(buf, buf->length); +} + +buffer_t *buffer_new_slice(const buffer_t *buf, size_t slice_size) { + assert(buf != NULL); + assert(slice_size > 0); + assert(slice_size <= buf->length); + + buffer_t *ret = osi_calloc(sizeof(buffer_t)); + if (!ret) { + LOG_ERROR("%s unable to allocate new buffer for slice of length %zu.", __func__, slice_size); + return NULL; + } + + ret->root = buf->root; + ret->refcount = SIZE_MAX; + ret->length = slice_size; + + ++buf->root->refcount; + + return ret; +} + +void buffer_free(buffer_t *buffer) { + if (!buffer) + return; + + if (buffer->root != buffer) { + // We're a leaf node. Delete the root node if we're the last referent. + if (--buffer->root->refcount == 0) + osi_free(buffer->root); + osi_free(buffer); + } else if (--buffer->refcount == 0) { + // We're a root node. Roots are only deleted when their refcount goes to 0. + osi_free(buffer); + } +} + +void *buffer_ptr(const buffer_t *buf) { + assert(buf != NULL); + return buf->root->data + buf->root->length - buf->length; +} + +size_t buffer_length(const buffer_t *buf) { + assert(buf != NULL); + return buf->length; +} diff --git a/components/bt/bluedroid/osi/fixed_queue.c b/components/bt/bluedroid/osi/fixed_queue.c new file mode 100755 index 0000000000..4d63365b80 --- /dev/null +++ b/components/bt/bluedroid/osi/fixed_queue.c @@ -0,0 +1,187 @@ +/****************************************************************************** + * + * Copyright (C) 2014 Google, Inc. + * + * 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. + * + ******************************************************************************/ + +#include "bt_defs.h" +#include "allocator.h" +#include "fixed_queue.h" +#include "list.h" +#include "osi.h" +#include "bt_trace.h" + +typedef struct fixed_queue_t { + + list_t *list; + //semaphore_t *enqueue_sem; + //semaphore_t *dequeue_sem; + pthread_mutex_t lock; + size_t capacity; + + fixed_queue_cb dequeue_ready; +/* + reactor_object_t *dequeue_object; + fixed_queue_cb dequeue_ready; + void *dequeue_context; +*/ +} fixed_queue_t; + +//static void internal_dequeue_ready(void *context); + +fixed_queue_t *fixed_queue_new(size_t capacity) { + fixed_queue_t *ret = osi_calloc(sizeof(fixed_queue_t)); + if (!ret) + goto error; + + pthread_mutex_init(&ret->lock, NULL); + ret->capacity = capacity; + + ret->list = list_new(NULL); + if (!ret->list) + goto error; + +/* + ret->enqueue_sem = semaphore_new(capacity); + if (!ret->enqueue_sem) + goto error; + + ret->dequeue_sem = semaphore_new(0); + if (!ret->dequeue_sem) + goto error; +*/ + return ret; + +error:; + fixed_queue_free(ret, NULL); + return NULL; +} + +void fixed_queue_free(fixed_queue_t *queue, fixed_queue_free_cb free_cb) { + const list_node_t *node; + if (!queue) + return; + +// fixed_queue_unregister_dequeue(queue); + + if (free_cb) + for (node = list_begin(queue->list); node != list_end(queue->list); node = list_next(node)) + free_cb(list_node(node)); + + list_free(queue->list); +// semaphore_free(queue->enqueue_sem); +// semaphore_free(queue->dequeue_sem); + pthread_mutex_destroy(&queue->lock); + osi_free(queue); +} + +bool fixed_queue_is_empty(fixed_queue_t *queue) { + bool is_empty = false; + assert(queue != NULL); + + pthread_mutex_lock(&queue->lock); + is_empty = list_is_empty(queue->list); + pthread_mutex_unlock(&queue->lock); + + return is_empty; +} + +size_t fixed_queue_capacity(fixed_queue_t *queue) { + assert(queue != NULL); + + return queue->capacity; +} + +void fixed_queue_enqueue(fixed_queue_t *queue, void *data) { + assert(queue != NULL); + assert(data != NULL); + +// semaphore_wait(queue->enqueue_sem); + + pthread_mutex_lock(&queue->lock); + + list_append(queue->list, data); + pthread_mutex_unlock(&queue->lock); + +// semaphore_post(queue->dequeue_sem); +} + +void *fixed_queue_dequeue(fixed_queue_t *queue) { + void *ret = NULL; + assert(queue != NULL); + +// semaphore_wait(queue->dequeue_sem); + + pthread_mutex_lock(&queue->lock); + ret = list_front(queue->list); + list_remove(queue->list, ret); + pthread_mutex_unlock(&queue->lock); + +// semaphore_post(queue->enqueue_sem); + + return ret; +} + +/* +void *fixed_queue_try_dequeue(fixed_queue_t *queue) { + void *ret = NULL; + assert(queue != NULL); + + if (!semaphore_try_wait(queue->dequeue_sem)) + return NULL; + + pthread_mutex_lock(&queue->lock); + ret = list_front(queue->list); + list_remove(queue->list, ret); + pthread_mutex_unlock(&queue->lock); + + semaphore_post(queue->enqueue_sem); + + return ret; +} + +int fixed_queue_get_dequeue_fd(const fixed_queue_t *queue) { + assert(queue != NULL); + return semaphore_get_fd(queue->dequeue_sem); +} +*/ +void fixed_queue_register_dequeue(fixed_queue_t *queue, fixed_queue_cb ready_cb) { + assert(queue != NULL); + assert(ready_cb != NULL); + + queue->dequeue_ready = ready_cb; +} + +void fixed_queue_unregister_dequeue(fixed_queue_t *queue) { + assert(queue != NULL); + + queue->dequeue_ready = NULL; +} + +void fixed_queue_process(fixed_queue_t *queue) { + if (queue == NULL) + return; + + if (queue->dequeue_ready) + queue->dequeue_ready(queue); +} +/* +static void internal_dequeue_ready(void *context) { + assert(context != NULL); + + fixed_queue_t *queue = context; + queue->dequeue_ready(queue, queue->dequeue_context); +} +*/ diff --git a/components/bt/bluedroid/osi/hash_functions.c b/components/bt/bluedroid/osi/hash_functions.c new file mode 100755 index 0000000000..f279bd4564 --- /dev/null +++ b/components/bt/bluedroid/osi/hash_functions.c @@ -0,0 +1,42 @@ +/****************************************************************************** + * + * Copyright (C) 2014 Google, Inc. + * + * 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. + * + ******************************************************************************/ + +#include + +#include "hash_functions.h" + +hash_index_t hash_function_naive(const void *key) { + return (hash_index_t)key; +} + +hash_index_t hash_function_integer(const void *key) { + return ((hash_index_t)key) * 2654435761; +} + +hash_index_t hash_function_pointer(const void *key) { + return ((hash_index_t)key) * 2654435761; +} + +hash_index_t hash_function_string(const void *key) { + hash_index_t hash = 5381; + const char *name = (const char *)key; + size_t string_len = strlen(name); + for (size_t i = 0; i < string_len; ++i) + hash = ((hash << 5) + hash ) + name[i]; + return hash; +} diff --git a/components/bt/bluedroid/osi/hash_map.c b/components/bt/bluedroid/osi/hash_map.c new file mode 100755 index 0000000000..9a18fb78a7 --- /dev/null +++ b/components/bt/bluedroid/osi/hash_map.c @@ -0,0 +1,247 @@ +/****************************************************************************** + * + * Copyright (C) 2014 Google, Inc. + * + * 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. + * + ******************************************************************************/ + +#include "bt_defs.h" +#include "bt_trace.h" +#include "list.h" +#include "hash_map.h" +#include "allocator.h" + +struct hash_map_t; + +typedef struct hash_map_bucket_t { + list_t *list; +} hash_map_bucket_t; + +typedef struct hash_map_t { + hash_map_bucket_t *bucket; + size_t num_bucket; + size_t hash_size; + hash_index_fn hash_fn; + key_free_fn key_fn; + data_free_fn data_fn; + const allocator_t *allocator; + key_equality_fn keys_are_equal; +} hash_map_t; + +// Hidden constructor for list, only to be used by us. +list_t *list_new_internal(list_free_cb callback, const allocator_t *zeroed_allocator); + +static void bucket_free_(void *data); +static bool default_key_equality(const void *x, const void *y); +static hash_map_entry_t *find_bucket_entry_(list_t *hash_bucket_list, + const void *key); + +// Hidden constructor, only to be used by the allocation tracker. Behaves the same as +// |hash_map_new|, except you get to specify the allocator. +hash_map_t *hash_map_new_internal( + size_t num_bucket, + hash_index_fn hash_fn, + key_free_fn key_fn, + data_free_fn data_fn, + key_equality_fn equality_fn, + const allocator_t *zeroed_allocator) { + assert(hash_fn != NULL); + assert(num_bucket > 0); + assert(zeroed_allocator != NULL); + + hash_map_t *hash_map = zeroed_allocator->alloc(sizeof(hash_map_t)); + if (hash_map == NULL) + return NULL; + + hash_map->hash_fn = hash_fn; + hash_map->key_fn = key_fn; + hash_map->data_fn = data_fn; + hash_map->allocator = zeroed_allocator; + hash_map->keys_are_equal = equality_fn ? equality_fn : default_key_equality; + + hash_map->num_bucket = num_bucket; + hash_map->bucket = zeroed_allocator->alloc(sizeof(hash_map_bucket_t) * num_bucket); + if (hash_map->bucket == NULL) { + zeroed_allocator->free(hash_map); + return NULL; + } + return hash_map; +} + +hash_map_t *hash_map_new( + size_t num_bucket, + hash_index_fn hash_fn, + key_free_fn key_fn, + data_free_fn data_fn, + key_equality_fn equality_fn) { + return hash_map_new_internal(num_bucket, hash_fn, key_fn, data_fn, equality_fn, &allocator_calloc); +} + +void hash_map_free(hash_map_t *hash_map) { + if (hash_map == NULL) + return; + hash_map_clear(hash_map); + hash_map->allocator->free(hash_map->bucket); + hash_map->allocator->free(hash_map); +} + +/* +bool hash_map_is_empty(const hash_map_t *hash_map) { + assert(hash_map != NULL); + return (hash_map->hash_size == 0); +} + +size_t hash_map_size(const hash_map_t *hash_map) { + assert(hash_map != NULL); + return hash_map->hash_size; +} + +size_t hash_map_num_buckets(const hash_map_t *hash_map) { + assert(hash_map != NULL); + return hash_map->num_bucket; +} +*/ + +bool hash_map_has_key(const hash_map_t *hash_map, const void *key) { + assert(hash_map != NULL); + + hash_index_t hash_key = hash_map->hash_fn(key) % hash_map->num_bucket; + list_t *hash_bucket_list = hash_map->bucket[hash_key].list; + + hash_map_entry_t *hash_map_entry = find_bucket_entry_(hash_bucket_list, key); + return (hash_map_entry != NULL); +} + +bool hash_map_set(hash_map_t *hash_map, const void *key, void *data) { + assert(hash_map != NULL); + assert(data != NULL); + + hash_index_t hash_key = hash_map->hash_fn(key) % hash_map->num_bucket; + + if (hash_map->bucket[hash_key].list == NULL) { + hash_map->bucket[hash_key].list = list_new_internal(bucket_free_, hash_map->allocator); + if (hash_map->bucket[hash_key].list == NULL) + return false; + } + list_t *hash_bucket_list = hash_map->bucket[hash_key].list; + + hash_map_entry_t *hash_map_entry = find_bucket_entry_(hash_bucket_list, key); + + if (hash_map_entry) { + // Calls hash_map callback to delete the hash_map_entry. + bool rc = list_remove(hash_bucket_list, hash_map_entry); + assert(rc == true); + } else { + hash_map->hash_size++; + } + hash_map_entry = hash_map->allocator->alloc(sizeof(hash_map_entry_t)); + if (hash_map_entry == NULL) + return false; + + hash_map_entry->key = key; + hash_map_entry->data = data; + hash_map_entry->hash_map = hash_map; + + return list_append(hash_bucket_list, hash_map_entry); +} + +bool hash_map_erase(hash_map_t *hash_map, const void *key) { + assert(hash_map != NULL); + + hash_index_t hash_key = hash_map->hash_fn(key) % hash_map->num_bucket; + list_t *hash_bucket_list = hash_map->bucket[hash_key].list; + + hash_map_entry_t *hash_map_entry = find_bucket_entry_(hash_bucket_list, key); + if (hash_map_entry == NULL) { + return false; + } + + hash_map->hash_size--; + + return list_remove(hash_bucket_list, hash_map_entry); +} + +void *hash_map_get(const hash_map_t *hash_map, const void *key) { + assert(hash_map != NULL); + + hash_index_t hash_key = hash_map->hash_fn(key) % hash_map->num_bucket; + list_t *hash_bucket_list = hash_map->bucket[hash_key].list; + + hash_map_entry_t *hash_map_entry = find_bucket_entry_(hash_bucket_list, key); + if (hash_map_entry != NULL) + return hash_map_entry->data; + + return NULL; +} + +void hash_map_clear(hash_map_t *hash_map) { + assert(hash_map != NULL); + + for (hash_index_t i = 0; i < hash_map->num_bucket; i++){ + if (hash_map->bucket[i].list == NULL) + continue; + list_free(hash_map->bucket[i].list); + hash_map->bucket[i].list = NULL; + } +} + +void hash_map_foreach(hash_map_t *hash_map, hash_map_iter_cb callback, void *context) { + assert(hash_map != NULL); + assert(callback != NULL); + + for (hash_index_t i = 0; i < hash_map->num_bucket; ++i){ + if (hash_map->bucket[i].list == NULL) + continue; + for (const list_node_t *iter = list_begin(hash_map->bucket[i].list); + iter != list_end(hash_map->bucket[i].list); + iter = list_next(iter)) { + hash_map_entry_t *hash_map_entry = (hash_map_entry_t *)list_node(iter); + if (!callback(hash_map_entry, context)) + return; + } + } +} + +static void bucket_free_(void *data) { + assert(data != NULL); + hash_map_entry_t *hash_map_entry = (hash_map_entry_t *)data; + const hash_map_t *hash_map = hash_map_entry->hash_map; + + if (hash_map->key_fn) + hash_map->key_fn((void *)hash_map_entry->key); + if (hash_map->data_fn) + hash_map->data_fn(hash_map_entry->data); + hash_map->allocator->free(hash_map_entry); +} + +static hash_map_entry_t * find_bucket_entry_(list_t *hash_bucket_list, + const void *key) { + + if (hash_bucket_list == NULL) + return NULL; + + for (const list_node_t *iter = list_begin(hash_bucket_list); + iter != list_end(hash_bucket_list); + iter = list_next(iter)) { + hash_map_entry_t *hash_map_entry = (hash_map_entry_t *)list_node(iter); + if (hash_map_entry->hash_map->keys_are_equal(hash_map_entry->key, key)) { + return hash_map_entry; + } + } + return NULL; +} + +static bool default_key_equality(const void *x, const void *y) { + return x == y; +} diff --git a/components/bt/bluedroid/osi/include/alarm.h b/components/bt/bluedroid/osi/include/alarm.h new file mode 100755 index 0000000000..b4cd1347c2 --- /dev/null +++ b/components/bt/bluedroid/osi/include/alarm.h @@ -0,0 +1,76 @@ +/****************************************************************************** + * + * Copyright (C) 2014 Google, Inc. + * + * 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. + * + ******************************************************************************/ + +#ifndef _ALARM_H_ +#define _ALARM_H_ + +#include +#include +#include + +typedef uint32_t period_ms_t; +typedef void (*osi_alarm_callback_t)(void *data); + +#define ALARM_CBS_NUM 20 +#define ALARM_ID_BASE 1000 +typedef struct alarm_t { + /* timer id point to here */ + TimerHandle_t alarm_hdl; + osi_alarm_callback_t cb; + void *cb_data; +} osi_alarm_t; + +void osi_alarm_init(void); + +// Creates a new alarm object. The returned object must be freed by calling +// |alarm_free|. Returns NULL on failure. +osi_alarm_t *osi_alarm_new(char *alarm_name, osi_alarm_callback_t callback, void *data, period_ms_t timer_expire); + +// Frees an alarm object created by |alarm_new|. |alarm| may be NULL. If the +// alarm is pending, it will be cancelled. It is not safe to call |alarm_free| +// from inside the callback of |alarm|. +int osi_alarm_free(osi_alarm_t *alarm); + +// Sets an alarm to fire |cb| after the given |deadline|. Note that |deadline| is the +// number of milliseconds relative to the current time. |data| is a context variable +// for the callback and may be NULL. |cb| will be called back in the context of an +// unspecified thread (i.e. it will not be called back in the same thread as the caller). +// |alarm| and |cb| may not be NULL. +int osi_alarm_set(osi_alarm_t *alarm, period_ms_t timeout); + +// This function cancels the |alarm| if it was previously set. When this call +// returns, the caller has a guarantee that the callback is not in progress and +// will not be called if it hasn't already been called. This function is idempotent. +// |alarm| may not be NULL. +int osi_alarm_cancel(osi_alarm_t *alarm); + +period_ms_t osi_alarm_now(void); + +// Figure out how much time until next expiration. +// Returns 0 if not armed. |alarm| may not be NULL. +// TODO: Remove this function once PM timers can be re-factored +period_ms_t osi_alarm_get_remaining_ms(const osi_alarm_t *alarm); + +// Alarm-related state cleanup +//void alarm_cleanup(void); + +// Compute time difference (t1-t2) considering tick counter wrap +// t1 and t2 should be no greater than the time of MAX ticks +period_ms_t osi_alarm_time_diff(period_ms_t t1, period_ms_t t2); + +#endif /*_ALARM_H_*/ diff --git a/components/bt/bluedroid/osi/include/allocator.h b/components/bt/bluedroid/osi/include/allocator.h new file mode 100755 index 0000000000..74bdfb73a0 --- /dev/null +++ b/components/bt/bluedroid/osi/include/allocator.h @@ -0,0 +1,43 @@ +/****************************************************************************** + * + * Copyright (C) 2014 Google, Inc. + * + * 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. + * + ******************************************************************************/ + +#ifndef _ALLOCATOR_H_ +#define _ALLOCATOR_H_ + +#include +//#include + +typedef void *(*alloc_fn)(size_t size); +typedef void (*free_fn)(void *ptr); + +typedef struct { + alloc_fn alloc; + free_fn free; +} allocator_t; + +// allocator_t abstractions for the osi_*alloc and osi_free functions +extern const allocator_t allocator_malloc; +extern const allocator_t allocator_calloc; + +char *osi_strdup(const char *str); + +void *osi_malloc(size_t size); +void *osi_calloc(size_t size); +void osi_free(void *ptr); + +#endif /* _ALLOCATOR_H_ */ diff --git a/components/bt/bluedroid/osi/include/buffer.h b/components/bt/bluedroid/osi/include/buffer.h new file mode 100755 index 0000000000..fd1b2fa373 --- /dev/null +++ b/components/bt/bluedroid/osi/include/buffer.h @@ -0,0 +1,59 @@ +/****************************************************************************** + * + * Copyright (C) 2014 Google, Inc. + * + * 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. + * + ******************************************************************************/ + +#ifndef _BUFFER_H_ +#define _BUFFER_H_ + +#include +#include + +typedef struct buffer_t buffer_t; + +// Returns a new buffer of |size| bytes. Returns NULL if a buffer could not be +// allocated. |size| must be non-zero. The caller must release this buffer with +// |buffer_free|. +buffer_t *buffer_new(size_t size); + +// Creates a new reference to the buffer |buf|. A reference is indistinguishable +// from the original: writes to the original will be reflected in the reference +// and vice versa. In other words, this function creates an alias to |buf|. The +// caller must release the returned buffer with |buffer_free|. Note that releasing +// the returned buffer does not release |buf|. |buf| must not be NULL. +buffer_t *buffer_new_ref(const buffer_t *buf); + +// Creates a new reference to the last |slice_size| bytes of |buf|. See +// |buffer_new_ref| for a description of references. |slice_size| must be +// greater than 0 and may be at most |buffer_length| +// (0 < slice_size <= buffer_length). |buf| must not be NULL. +buffer_t *buffer_new_slice(const buffer_t *buf, size_t slice_size); + +// Frees a buffer object. |buf| may be NULL. +void buffer_free(buffer_t *buf); + +// Returns a pointer to a writeable memory region for |buf|. All references +// and slices that share overlapping bytes will also be written to when +// writing to the returned pointer. The caller may safely write up to +// |buffer_length| consecutive bytes starting at the address returned by +// this function. |buf| must not be NULL. +void *buffer_ptr(const buffer_t *buf); + +// Returns the length of the writeable memory region referred to by |buf|. +// |buf| must not be NULL. +size_t buffer_length(const buffer_t *buf); + +#endif /*_BUFFER_H_*/ diff --git a/components/bt/bluedroid/osi/include/fixed_queue.h b/components/bt/bluedroid/osi/include/fixed_queue.h new file mode 100755 index 0000000000..9cbb846d58 --- /dev/null +++ b/components/bt/bluedroid/osi/include/fixed_queue.h @@ -0,0 +1,102 @@ +/****************************************************************************** + * + * Copyright (C) 2014 Google, Inc. + * + * 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. + * + ******************************************************************************/ + +#ifndef _FIXED_QUEUE_H_ +#define _FIXED_QUEUE_H_ + +#include + +struct fixed_queue_t; +typedef struct fixed_queue_t fixed_queue_t; +//typedef struct reactor_t reactor_t; + +typedef void (*fixed_queue_free_cb)(void *data); +typedef void (*fixed_queue_cb)(fixed_queue_t *queue); + +// Creates a new fixed queue with the given |capacity|. If more elements than +// |capacity| are added to the queue, the caller is blocked until space is +// made available in the queue. Returns NULL on failure. The caller must free +// the returned queue with |fixed_queue_free|. +fixed_queue_t *fixed_queue_new(size_t capacity); + +// Freeing a queue that is currently in use (i.e. has waiters +// blocked on it) results in undefined behaviour. +void fixed_queue_free(fixed_queue_t *queue, fixed_queue_free_cb free_cb); + +// Returns a value indicating whether the given |queue| is empty. |queue| may +// not be NULL. +bool fixed_queue_is_empty(fixed_queue_t *queue); + +// Returns the maximum number of elements this queue may hold. |queue| may +// not be NULL. +size_t fixed_queue_capacity(fixed_queue_t *queue); + +// Enqueues the given |data| into the |queue|. The caller will be blocked +// if nore more space is available in the queue. Neither |queue| nor |data| +// may be NULL. +void fixed_queue_enqueue(fixed_queue_t *queue, void *data); + +// Dequeues the next element from |queue|. If the queue is currently empty, +// this function will block the caller until an item is enqueued. This +// function will never return NULL. |queue| may not be NULL. +void *fixed_queue_dequeue(fixed_queue_t *queue); + +// Tries to enqueue |data| into the |queue|. This function will never block +// the caller. If the queue capacity would be exceeded by adding one more +// element, this function returns false immediately. Otherwise, this function +// returns true. Neither |queue| nor |data| may be NULL. +bool fixed_queue_try_enqueue(fixed_queue_t *queue, void *data); + +// Tries to dequeue an element from |queue|. This function will never block +// the caller. If the queue is empty, this function returns NULL immediately. +// Otherwise, the next element in the queue is returned. |queue| may not be +// NULL. +//void *fixed_queue_try_dequeue(fixed_queue_t *queue); + +// Returns the first element from |queue|, if present, without dequeuing it. +// This function will never block the caller. Returns NULL if there are no elements +// in the queue. |queue| may not be NULL. +//void *fixed_queue_try_peek(fixed_queue_t *queue); + +// This function returns a valid file descriptor. Callers may perform one +// operation on the fd: select(2). If |select| indicates that the file +// descriptor is readable, the caller may call |fixed_queue_enqueue| without +// blocking. The caller must not close the returned file descriptor. |queue| +// may not be NULL. +//int fixed_queue_get_enqueue_fd(const fixed_queue_t *queue); + +// This function returns a valid file descriptor. Callers may perform one +// operation on the fd: select(2). If |select| indicates that the file +// descriptor is readable, the caller may call |fixed_queue_dequeue| without +// blocking. The caller must not close the returned file descriptor. |queue| +// may not be NULL. +//int fixed_queue_get_dequeue_fd(const fixed_queue_t *queue); + +// Registers |queue| with |reactor| for dequeue operations. When there is an element +// in the queue, ready_cb will be called. The |context| parameter is passed, untouched, +// to the callback routine. Neither |queue|, nor |reactor|, nor |read_cb| may be NULL. +// |context| may be NULL. +void fixed_queue_register_dequeue(fixed_queue_t *queue, fixed_queue_cb ready_cb); + +// Unregisters the dequeue ready callback for |queue| from whichever reactor +// it is registered with, if any. This function is idempotent. +void fixed_queue_unregister_dequeue(fixed_queue_t *queue); + +void fixed_queue_process(fixed_queue_t *queue); + +#endif diff --git a/components/bt/bluedroid/osi/include/hash_functions.h b/components/bt/bluedroid/osi/include/hash_functions.h new file mode 100755 index 0000000000..2edbeb8b74 --- /dev/null +++ b/components/bt/bluedroid/osi/include/hash_functions.h @@ -0,0 +1,33 @@ +/****************************************************************************** + * + * Copyright (C) 2014 Google, Inc. + * + * 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. + * + ******************************************************************************/ + +#ifndef _HASH_FUNCTIONS_H_ +#define _HASH_FUNCTIONS_H_ + +#include "hash_map.h" + +hash_index_t hash_function_naive(const void *key); + +hash_index_t hash_function_integer(const void *key); + +// Hashes a pointer based only on its address value +hash_index_t hash_function_pointer(const void *key); + +hash_index_t hash_function_string(const void *key); + +#endif /* _HASH_FUNCTIONS_H_ */ diff --git a/components/bt/bluedroid/osi/include/hash_map.h b/components/bt/bluedroid/osi/include/hash_map.h new file mode 100755 index 0000000000..6b8220b6c1 --- /dev/null +++ b/components/bt/bluedroid/osi/include/hash_map.h @@ -0,0 +1,110 @@ +/****************************************************************************** + * + * Copyright (C) 2014 Google, Inc. + * + * 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. + * + ******************************************************************************/ + +#ifndef _HASH_MAP_H_ +#define _HASH_MAP_H_ + +#include +#include + +struct hash_map_t; +typedef struct hash_map_t hash_map_t; + +typedef struct hash_map_entry_t { + const void *key; + void *data; + const hash_map_t *hash_map; +} hash_map_entry_t; + +typedef size_t hash_index_t; + +// Takes a key structure and returns a hash value. +typedef hash_index_t (*hash_index_fn)(const void *key); +typedef bool (*hash_map_iter_cb)(hash_map_entry_t *hash_entry, void *context); + +typedef bool (*key_equality_fn)(const void *x, const void *y); + +typedef void (*key_free_fn)(void *data); +typedef void (*data_free_fn)(void *data); + +// Returns a new, empty hash_map. Returns NULL if not enough memory could be allocated +// for the hash_map structure. The returned hash_map must be freed with |hash_map_free|. +// The |num_bucket| specifies the number of hashable buckets for the map and must not +// be zero. The |hash_fn| specifies a hash function to be used and must not be NULL. +// The |key_fn| and |data_fn| are called whenever a hash_map element is removed from +// the hash_map. They can be used to release resources held by the hash_map element, +// e.g. memory or file descriptor. |key_fn| and |data_fn| may be NULL if no cleanup +// is necessary on element removal. |equality_fn| is used to check for key equality. +// If |equality_fn| is NULL, default pointer equality is used. +hash_map_t *hash_map_new( + size_t size, + hash_index_fn hash_fn, + key_free_fn key_fn, + data_free_fn data_fn, + key_equality_fn equality_fn); + +// Frees the hash_map. This function accepts NULL as an argument, in which case it +// behaves like a no-op. +void hash_map_free(hash_map_t *hash_map); + +// Returns true if the hash_map is empty (has no elements), false otherwise. +// Note that a NULL |hash_map| is not the same as an empty |hash_map|. This function +// does not accept a NULL |hash_map|. +//bool hash_map_is_empty(const hash_map_t *hash_map); + +// Returns the number of elements in the hash map. This function does not accept a +// NULL |hash_map|. +//size_t hash_map_size(const hash_map_t *hash_map); + +// Returns the number of buckets in the hash map. This function does not accept a +// NULL |hash_map|. +//size_t hash_map_num_buckets(const hash_map_t *hash_map); + +// Returns true if the hash_map has a valid entry for the presented key. +// This function does not accept a NULL |hash_map|. +bool hash_map_has_key(const hash_map_t *hash_map, const void *key); + +// Returns the element indexed by |key| in the hash_map without removing it. |hash_map| +// may not be NULL. Returns NULL if no entry indexed by |key|. +void *hash_map_get(const hash_map_t *hash_map, const void *key); + +// Sets the value |data| indexed by |key| into the |hash_map|. Neither |data| nor +// |hash_map| may be NULL. This function does not make copies of |data| nor |key| +// so the pointers must remain valid at least until the element is removed from the +// hash_map or the hash_map is freed. Returns true if |data| could be set, false +// otherwise (e.g. out of memory). +bool hash_map_set(hash_map_t *hash_map, const void *key, void *data); + +// Removes data indexed by |key| from the hash_map. |hash_map| may not be NULL. +// If |key_fn| or |data_fn| functions were specified in |hash_map_new|, they +// will be called back with |key| or |data| respectively. This function returns true +// if |key| was found in the hash_map and removed, false otherwise. +bool hash_map_erase(hash_map_t *hash_map, const void *key); + +// Removes all elements in the hash_map. Calling this function will return the hash_map +// to the same state it was in after |hash_map_new|. |hash_map| may not be NULL. +void hash_map_clear(hash_map_t *hash_map); + +// Iterates through the entire |hash_map| and calls |callback| for each data +// element and passes through the |context| argument. If the hash_map is +// empty, |callback| will never be called. It is not safe to mutate the +// hash_map inside the callback. Neither |hash_map| nor |callback| may be NULL. +// If |callback| returns false, the iteration loop will immediately exit. +void hash_map_foreach(hash_map_t *hash_map, hash_map_iter_cb callback, void *context); + +#endif /* _HASH_MAP_H_ */ diff --git a/components/bt/bluedroid/osi/include/list.h b/components/bt/bluedroid/osi/include/list.h new file mode 100755 index 0000000000..770979672d --- /dev/null +++ b/components/bt/bluedroid/osi/include/list.h @@ -0,0 +1,110 @@ +#ifndef _LIST_H_ +#define _LIST_H_ + +#include +#include +struct list_node_t; +typedef struct list_node_t list_node_t; + +struct list_t; +typedef struct list_t list_t; + +typedef void (*list_free_cb)(void *data); +typedef bool (*list_iter_cb)(void *data); + +// Returns a new, empty list. Returns NULL if not enough memory could be allocated +// for the list structure. The returned list must be freed with |list_free|. The +// |callback| specifies a function to be called whenever a list element is removed +// from the list. It can be used to release resources held by the list element, e.g. +// memory or file descriptor. |callback| may be NULL if no cleanup is necessary on +// element removal. +list_t *list_new(list_free_cb callback); + + +list_node_t *list_free_node(list_t *list, list_node_t *node); +//list_node_t *list_free_node(list_t *list, list_node_t *node); +// Frees the list. This function accepts NULL as an argument, in which case it +// behaves like a no-op. +void list_free(list_t *list); + +// Returns true if |list| is empty (has no elements), false otherwise. +// |list| may not be NULL. +bool list_is_empty(const list_t *list); + +// Returns true if the list contains |data|, false otherwise. +// |list| may not be NULL. +bool list_contains(const list_t *list, const void *data); + +// Returns the length of the |list|. |list| may not be NULL. +size_t list_length(const list_t *list); + +// Returns the first element in the list without removing it. |list| may not +// be NULL or empty. +void *list_front(const list_t *list); + +// Returns the last element in the list without removing it. |list| may not +// be NULL or empty. +//void *list_back(const list_t *list); + +// Inserts |data| after |prev_node| in |list|. |data|, |list|, and |prev_node| +// may not be NULL. This function does not make a copy of |data| so the pointer +// must remain valid at least until the element is removed from the list or the +// list is freed. Returns true if |data| could be inserted, false otherwise +// (e.g. out of memory). +bool list_insert_after(list_t *list, list_node_t *prev_node, void *data); + +// Inserts |data| at the beginning of |list|. Neither |data| nor |list| may be NULL. +// This function does not make a copy of |data| so the pointer must remain valid +// at least until the element is removed from the list or the list is freed. +// Returns true if |data| could be inserted, false otherwise (e.g. out of memory). +bool list_prepend(list_t *list, void *data); + +// Inserts |data| at the end of |list|. Neither |data| nor |list| may be NULL. +// This function does not make a copy of |data| so the pointer must remain valid +// at least until the element is removed from the list or the list is freed. +// Returns true if |data| could be inserted, false otherwise (e.g. out of memory). +bool list_append(list_t *list, void *data); + +// Removes |data| from the list. Neither |list| nor |data| may be NULL. If |data| +// is inserted multiple times in the list, this function will only remove the first +// instance. If a free function was specified in |list_new|, it will be called back +// with |data|. This function returns true if |data| was found in the list and removed, +// false otherwise. +//list_node_t list_remove_node(list_t *list, list_node_t *prev_node, list_node_t *node); +//list_node_t list_insert_node(list_t *list, list_node_t *prev_node, list_node_t *node); + +bool list_remove(list_t *list, void *data); + +// Removes all elements in the list. Calling this function will return the list to the +// same state it was in after |list_new|. |list| may not be NULL. +void list_clear(list_t *list); + +// Iterates through the entire |list| and calls |callback| for each data element. +// If the list is empty, |callback| will never be called. It is safe to mutate the +// list inside the callback. If an element is added before the node being visited, +// there will be no callback for the newly-inserted node. Neither |list| nor +// |callback| may be NULL. +void list_foreach(const list_t *list, list_iter_cb callback); + +// Returns an iterator to the first element in |list|. |list| may not be NULL. +// The returned iterator is valid as long as it does not equal the value returned +// by |list_end|. +list_node_t *list_begin(const list_t *list); + +// Returns an iterator that points past the end of the list. In other words, +// this function returns the value of an invalid iterator for the given list. +// When an iterator has the same value as what's returned by this function, you +// may no longer call |list_next| with the iterator. |list| may not be NULL. +list_node_t *list_end(const list_t *list); + +// Given a valid iterator |node|, this function returns the next value for the +// iterator. If the returned value equals the value returned by |list_end|, the +// iterator has reached the end of the list and may no longer be used for any +// purpose. +list_node_t *list_next(const list_node_t *node); + +// Returns the value stored at the location pointed to by the iterator |node|. +// |node| must not equal the value returned by |list_end|. +void *list_node(const list_node_t *node); + +#endif /* _LIST_H_ */ diff --git a/components/bt/bluedroid/osi/include/osi.h b/components/bt/bluedroid/osi/include/osi.h new file mode 100755 index 0000000000..3308255b2d --- /dev/null +++ b/components/bt/bluedroid/osi/include/osi.h @@ -0,0 +1,26 @@ + +#ifndef _OSI_H_ +#define _OSI_H_ + +#include +#include + +#define UNUSED_ATTR __attribute__((unused)) +#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) +#define INVALID_FD (-1) + +#define CONCAT(a, b) a##b + +// Use during compile time to check conditional values +// NOTE: The the failures will present as a generic error +// "error: initialization makes pointer from integer without a cast" +// but the file and line number will present the condition that +// failed. +#define DUMMY_COUNTER(c) CONCAT(__osi_dummy_, c) +#define DUMMY_PTR DUMMY_COUNTER(__COUNTER__) + +#define COMPILE_ASSERT(x) char * DUMMY_PTR = !(x) + +typedef uint32_t timeout_t; + +#endif /*_OSI_H_*/ diff --git a/components/bt/bluedroid/osi/include/osi_arch.h b/components/bt/bluedroid/osi/include/osi_arch.h new file mode 100755 index 0000000000..85e60a6978 --- /dev/null +++ b/components/bt/bluedroid/osi/include/osi_arch.h @@ -0,0 +1,45 @@ +#ifndef __os_ARCH_H__ +#define __os_ARCH_H__ + +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "freertos/queue.h" +#include "freertos/semphr.h" + +#define OSI_ARCH_TIMEOUT 0xffffffffUL + +typedef xSemaphoreHandle osi_sem_t; +typedef xSemaphoreHandle osi_mutex_t; + +#define osi_mutex_valid( x ) ( ( ( *x ) == NULL) ? pdFALSE : pdTRUE ) +#define osi_mutex_set_invalid( x ) ( ( *x ) = NULL ) +#define osi_sem_valid( x ) ( ( ( *x ) == NULL) ? pdFALSE : pdTRUE ) +#define osi_sem_set_invalid( x ) ( ( *x ) = NULL ) + +int osi_mutex_new(osi_mutex_t *pxMutex); + +void osi_mutex_lock(osi_mutex_t *pxMutex); + +int osi_mutex_trylock(osi_mutex_t *pxMutex); + +void osi_mutex_unlock(osi_mutex_t *pxMutex); + +void osi_mutex_free(osi_mutex_t *pxMutex); + +int osi_sem_new(osi_sem_t *sem, uint8_t count); + +void osi_sem_signal(osi_sem_t *sem); + +uint32_t osi_sem_wait(osi_sem_t *sem, uint32_t timeout); + +void osi_sem_free(osi_sem_t *sem); + +void osi_arch_init(void); + +uint32_t osi_now(void); + +void osi_delay_ms(uint32_t ms); + + +#endif /* __os_ARCH_H__ */ + diff --git a/components/bt/bluedroid/osi/include/thread.h b/components/bt/bluedroid/osi/include/thread.h new file mode 100644 index 0000000000..5d869ccb3b --- /dev/null +++ b/components/bt/bluedroid/osi/include/thread.h @@ -0,0 +1,25 @@ +#ifndef __THREAD_H__ +#define __THREAD_H__ + +#include "freertos/xtensa_api.h" +#include "freertos/FreeRTOSConfig.h" +#include "freertos/FreeRTOS.h" +#include "freertos/queue.h" +#include "freertos/task.h" + +#define portBASE_TYPE int + +struct task_evt { + uint32_t sig; + uint32_t par; +}; +typedef struct task_evt TaskEvt_t; + +void btu_task_post(void); +void hci_host_task_post(void); +void hci_hal_h4_task_post(void); +void hci_drv_task_post(void); +void bt_alarm_task_post(void); + + +#endif /* __THREAD_H__ */ diff --git a/components/bt/bluedroid/osi/list.c b/components/bt/bluedroid/osi/list.c new file mode 100755 index 0000000000..f5d8c9a84c --- /dev/null +++ b/components/bt/bluedroid/osi/list.c @@ -0,0 +1,228 @@ + +#include "bt_defs.h" + +#include "allocator.h" +#include "list.h" +#include "osi.h" + +struct list_node_t { + struct list_node_t *next; + void *data; +}; + +typedef struct list_t { + list_node_t *head; + list_node_t *tail; + size_t length; + list_free_cb free_cb; + const allocator_t *allocator; +} list_t; + +//static list_node_t *list_free_node_(list_t *list, list_node_t *node); + +// Hidden constructor, only to be used by the hash map for the allocation tracker. +// Behaves the same as |list_new|, except you get to specify the allocator. +list_t *list_new_internal(list_free_cb callback, const allocator_t *zeroed_allocator) { + list_t *list = (list_t *)zeroed_allocator->alloc(sizeof(list_t)); + if (!list) + return NULL; + + list->head = list->tail = NULL; + list->length = 0; + list->free_cb = callback; + list->allocator = zeroed_allocator; + return list; +} + +list_t *list_new(list_free_cb callback) { + return list_new_internal(callback, &allocator_calloc); +} + +void list_free(list_t *list) { + if (!list) + return; + + list_clear(list); + list->allocator->free(list); +} + +bool list_is_empty(const list_t *list) { + assert(list != NULL); + return (list->length == 0); +} + +/* +bool list_contains(const list_t *list, const void *data) { + const list_node_t *node; + assert(list != NULL); + assert(data != NULL); + + for (node = list_begin(list); node != list_end(list); node = list_next(node)) { + if (list_node(node) == data) + return true; + } + + return false; +} +*/ + +size_t list_length(const list_t *list) { + assert(list != NULL); + return list->length; +} + +void *list_front(const list_t *list) { + assert(list != NULL); + assert(!list_is_empty(list)); + + return list->head->data; +} + +/* +void *list_back(const list_t *list) { + assert(list != NULL); + assert(!list_is_empty(list)); + + return list->tail->data; +} +*/ + +bool list_insert_after(list_t *list, list_node_t *prev_node, void *data) { + list_node_t *node; + assert(list != NULL); + assert(prev_node != NULL); + assert(data != NULL); + + node = (list_node_t *)list->allocator->alloc(sizeof(list_node_t)); + if (!node) + return false; + + node->next = prev_node->next; + node->data = data; + prev_node->next = node; + if (list->tail == prev_node) + list->tail = node; + ++list->length; + return true; +} + +bool list_prepend(list_t *list, void *data) { + list_node_t *node; + assert(list != NULL); + assert(data != NULL); + + node = (list_node_t *)list->allocator->alloc(sizeof(list_node_t)); + if (!node) + return false; + node->next = list->head; + node->data = data; + list->head = node; + if (list->tail == NULL) + list->tail = list->head; + ++list->length; + return true; +} + +bool list_append(list_t *list, void *data) { + list_node_t *node; + assert(list != NULL); + assert(data != NULL); + + node = (list_node_t *)list->allocator->alloc(sizeof(list_node_t)); + if (!node) { + //ets_printf("list_append failed\n"); + return false; +} + node->next = NULL; + node->data = data; + if (list->tail == NULL) { + list->head = node; + list->tail = node; + } else { + list->tail->next = node; + list->tail = node; + } + ++list->length; + return true; +} + +bool list_remove(list_t *list, void *data) { + assert(list != NULL); + assert(data != NULL); + + if (list_is_empty(list)) + return false; + + if (list->head->data == data) { + list_node_t *next = list_free_node(list, list->head); + if (list->tail == list->head) + list->tail = next; + list->head = next; + return true; + } + + for (list_node_t *prev = list->head, *node = list->head->next; node; prev = node, node = node->next) + if (node->data == data) { + prev->next = list_free_node(list, node); + if (list->tail == node) + list->tail = prev; + return true; + } + + return false; +} + +void list_clear(list_t *list) { + assert(list != NULL); + for (list_node_t *node = list->head; node; ) + node = list_free_node(list, node); + list->head = NULL; + list->tail = NULL; + list->length = 0; +} + +void list_foreach(const list_t *list, list_iter_cb callback) { + assert(list != NULL); + assert(callback != NULL); + + for (list_node_t *node = list->head; node; ) { + list_node_t *next = node->next; + callback(node->data); + node = next; + } +} + +list_node_t *list_begin(const list_t *list) { + assert(list != NULL); + return list->head; +} + +list_node_t *list_end(UNUSED_ATTR const list_t *list) { + assert(list != NULL); + return NULL; +} + +list_node_t *list_next(const list_node_t *node) { + assert(node != NULL); + return node->next; +} + +void *list_node(const list_node_t *node) { + assert(node != NULL); + //ets_printf("node %08x\n", node); + return node->data; +} + +list_node_t *list_free_node(list_t *list, list_node_t *node) { + assert(list != NULL); + assert(node != NULL); + + list_node_t *next = node->next; + + if (list->free_cb) + list->free_cb(node->data); + list->allocator->free(node); + --list->length; + + return next; +} diff --git a/components/bt/bluedroid/osi/osi_arch.c b/components/bt/bluedroid/osi/osi_arch.c new file mode 100755 index 0000000000..1eda38f99f --- /dev/null +++ b/components/bt/bluedroid/osi/osi_arch.c @@ -0,0 +1,197 @@ +/* + * Copyright (c) 2001-2003 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the bluedroid stack. + * + * Author: Adam Dunkels + * + */ + +#include "osi_arch.h" + +/** Create a new mutex + * @param mutex pointer to the mutex to create + * @return a new mutex */ +int +osi_mutex_new(osi_mutex_t *pxMutex) +{ + int xReturn = -1; + + *pxMutex = xSemaphoreCreateMutex(); + + if (*pxMutex != NULL) { + xReturn = 0; + } + + //LWIP_DEBUGF(THREAD_SAFE_DEBUG, ("osi_mutex_new: m=%p\n", *pxMutex)); + + return xReturn; +} + +/** Lock a mutex + * @param mutex the mutex to lock */ +void +osi_mutex_lock(osi_mutex_t *pxMutex) +{ + while (xSemaphoreTake(*pxMutex, portMAX_DELAY) != pdPASS); +} + +int +osi_mutex_trylock(osi_mutex_t *pxMutex) +{ + if (xSemaphoreTake(*pxMutex, 0) == pdPASS) return 0; + else return -1; +} + +/** Unlock a mutex + * @param mutex the mutex to unlock */ +void +osi_mutex_unlock(osi_mutex_t *pxMutex) +{ + xSemaphoreGive(*pxMutex); +} + +/** Delete a semaphore + * @param mutex the mutex to delete */ +void +osi_mutex_free(osi_mutex_t *pxMutex) +{ + //LWIP_DEBUGF(THREAD_SAFE_DEBUG, ("osi_mutex_free: m=%p\n", *pxMutex)); + vQueueDelete(*pxMutex); +} + +/*-----------------------------------------------------------------------------------*/ +// Creates and returns a new semaphore. The "count" argument specifies +// the initial state of the semaphore. TBD finish and test +int +osi_sem_new(osi_sem_t *sem, uint8_t count) +{ + int xReturn = -1; + vSemaphoreCreateBinary(*sem); + + if ((*sem) != NULL) { + if (count == 0) { // Means it can't be taken + xSemaphoreTake(*sem, 1); + } + + xReturn = 0; + } else { + ; // TBD need assert + } + + return xReturn; +} + +/*-----------------------------------------------------------------------------------*/ +// Signals a semaphore +void +osi_sem_signal(osi_sem_t *sem) +{ + xSemaphoreGive(*sem); +} + +/*-----------------------------------------------------------------------------------*/ +/* + Blocks the thread while waiting for the semaphore to be + signaled. If the "timeout" argument is non-zero, the thread should + only be blocked for the specified time (measured in + milliseconds). + + If the timeout argument is non-zero, the return value is the number of + milliseconds spent waiting for the semaphore to be signaled. If the + semaphore wasn't signaled within the specified time, the return value is + OSI_ARCH_TIMEOUT. If the thread didn't have to wait for the semaphore + (i.e., it was already signaled), the function may return zero. + + Notice that lwIP implements a function with a similar name, + osi_sem_wait(), that uses the osi_arch_sem_wait() function. +*/ +uint32_t +osi_sem_wait(osi_sem_t *sem, uint32_t timeout) +{ + portTickType StartTime, EndTime, Elapsed; + unsigned long ulReturn; + + StartTime = xTaskGetTickCount(); + + if (timeout != 0) { + if (xSemaphoreTake(*sem, timeout / portTICK_RATE_MS) == pdTRUE) { + EndTime = xTaskGetTickCount(); + Elapsed = (EndTime - StartTime) * portTICK_RATE_MS; + + if (Elapsed == 0) { + Elapsed = 1; + } + + ulReturn = Elapsed; + } else { + ulReturn = OSI_ARCH_TIMEOUT; + } + } else { // must block without a timeout + while (xSemaphoreTake(*sem, portMAX_DELAY) != pdTRUE); + + EndTime = xTaskGetTickCount(); + Elapsed = (EndTime - StartTime) * portTICK_RATE_MS; + + if (Elapsed == 0) { + Elapsed = 1; + } + + ulReturn = Elapsed; + } + + return ulReturn ; // return time blocked +} + +/*-----------------------------------------------------------------------------------*/ +// Deallocates a semaphore +void +osi_sem_free(osi_sem_t *sem) +{ + vSemaphoreDelete(*sem); +} + +/*-----------------------------------------------------------------------------------*/ +// Initialize osi arch +void +osi_arch_init(void) +{ +} + +/*-----------------------------------------------------------------------------------*/ +uint32_t +osi_now(void) +{ + return xTaskGetTickCount(); +} + + +void osi_delay_ms(uint32_t ms) +{ + vTaskDelay(ms/portTICK_RATE_MS); +} + + diff --git a/components/bt/bluedroid/profiles/baterry/baterry_prf.c b/components/bt/bluedroid/profiles/baterry/baterry_prf.c new file mode 100644 index 0000000000..6e5d5cfd4f --- /dev/null +++ b/components/bt/bluedroid/profiles/baterry/baterry_prf.c @@ -0,0 +1,614 @@ +/*************************************************************** +* * +* * This file is for battery service based on bta layer +* * +***************************************************************/ +#include +#include +#include +#include + +//#include "bluedroid_test.h" +#include "bta_api.h" +#include "bta_gatt_api.h" +#include "controller.h" + +#include "gatt_int.h" +#include "bt_trace.h" +#include "btm_api.h" +#include "bt_types.h" +#include "gatt_profile.h" + +#if BLE_INCLUDED == true + +#define BA_MAX_CHAR_NUM 1 +#define BA_MAX_ATTR_NUM (BA_MAX_CHAR_NUM * 5 + 1) +/*max 3 descriptors, 1 desclaration and 1 value*/ + +#ifndef BATTER_LEVEL_PROP +#define BATTER_LEVEL_PROP (GATT_CHAR_PROP_BIT_READ|GATT_CHAR_PROP_BIT_NOTIFY) +#endif + +#ifndef BATTER_LEVEL_PERM +#define BATTER_LEVEL_PERM (GATT_PERM_READ) +#endif + +#define BT_BD_ADDR_STR "%02x:%02x:%02x:%02x:%02x:%02x" +#define BT_BD_ADDR_HEX(addr) addr[0], addr[1], addr[2], addr[3], addr[4], addr[5] +tBTA_GATTS_IF server_if; + +tBATTERY_CB battery_cb; +tGATT_CHAR_PROP prop = GATT_CHAR_PROP_BIT_READ; +tBA_REG_INFO ba_reg_info; +UINT8 attr_handle_bit = 0x00; + +extern tDIS_CB dis_cb; +tBT_UUID bas_uuid = {LEN_UUID_16, {UUID_SERVCLASS_BATTERY}}; +/****************************************************************************** +** Function bas_gatts_callback +** +** Description battery service register callback function +*******************************************************************************/ +static void bas_gatts_callback(tBTA_GATTS_EVT event, tBTA_GATTS* p_data) +{ + switch (event) + { + case BTA_GATTS_REG_EVT: + { + tBTA_GATT_STATUS status = p_data->reg_oper.status; + server_if = p_data->reg_oper.server_if; + LOG_ERROR("BAS register completed: event=%d, status=%d, server_if=%d\n", + event, status, server_if); + + UINT8 app_id = 0xff; + bas_init(server_if, app_id); + + tDIS_ATTR_MASK mask = 0x01ff; + DIS_Init(server_if, mask); + } + break; + + /*connect callback*/ + case BTA_GATTS_CONNECT_EVT: + { + LOG_ERROR("\ndevice is connected "BT_BD_ADDR_STR", server_if=%d,reason=0x%x,connect_id=%d\n", + BT_BD_ADDR_HEX(p_data->conn.remote_bda), p_data->conn.server_if, + p_data->conn.reason, p_data->conn.conn_id); + /*return whether the remote device is currently connected*/ + int is_connected = BTA_DmGetConnectionState(p_data->conn.remote_bda); + LOG_ERROR("is_connected=%d\n",is_connected); + } + break; + + /*create service callback*/ + case BTA_GATTS_CREATE_EVT: + { + LOG_ERROR("create service:server_if=%d,service_id=0x%x,service_uuid=0x%x\n", + p_data->create.server_if, p_data->create.service_id, + p_data->create.uuid.uu.uuid16); + UINT16 service_uuid = p_data->create.uuid.uu.uuid16; + UINT16 service_id = p_data->create.service_id; + if (service_uuid == 0x180f) + { + tBT_UUID uuid = {LEN_UUID_16, {GATT_UUID_BATTERY_LEVEL}}; + bas_AddChar(service_id, &uuid); + } + if (service_uuid == 0x180a) + { + dis_cb.service_handle = service_id; + dis_cb.max_handle = service_id + DIS_MAX_ATTR_NUM; + dis_AddChar(service_id); + } + + } + break; + + case BTA_GATTS_ADD_CHAR_EVT: + { + LOG_ERROR("create characteristic:server_if=%d,service_id=0x%x,char_uuid=0x%x\n", + p_data->add_result.server_if, p_data->add_result.service_id, + p_data->add_result.char_uuid.uu.uuid16); + UINT16 char_uuid = p_data->add_result.char_uuid.uu.uuid16; + UINT16 service_id = p_data->add_result.service_id; + if(char_uuid == GATT_UUID_BATTERY_LEVEL) + bas_AddCharDescr(service_id, p_data->add_result.attr_id); + if(char_uuid == GATT_UUID_SYSTEM_ID | GATT_UUID_MODEL_NUMBER_STR | GATT_UUID_PNP_ID | + GATT_UUID_SERIAL_NUMBER_STR | GATT_UUID_FW_VERSION_STR | GATT_UUID_HW_VERSION_STR | + GATT_UUID_SW_VERSION_STR | GATT_UUID_MANU_NAME | GATT_UUID_IEEE_DATA) + { + switch (char_uuid) + { + case GATT_UUID_SYSTEM_ID: + dis_cb.dis_attr[0].handle = service_id; break; + case GATT_UUID_MODEL_NUMBER_STR: + dis_cb.dis_attr[1].handle = service_id; break; + case GATT_UUID_SERIAL_NUMBER_STR: + dis_cb.dis_attr[2].handle = service_id; break; + case GATT_UUID_FW_VERSION_STR: + dis_cb.dis_attr[3].handle = service_id; break; + case GATT_UUID_HW_VERSION_STR: + dis_cb.dis_attr[4].handle = service_id; break; + case GATT_UUID_SW_VERSION_STR: + dis_cb.dis_attr[5].handle = service_id; break; + case GATT_UUID_MANU_NAME: + dis_cb.dis_attr[6].handle = service_id; break; + case GATT_UUID_IEEE_DATA: + dis_cb.dis_attr[7].handle = service_id; break; + case GATT_UUID_PNP_ID: + dis_cb.dis_attr[8].handle = service_id; break; + } + } + } + break; + + case BTA_GATTS_ADD_CHAR_DESCR_EVT: + { + + LOG_ERROR("create descriptor:server_if=%d,service_id=0x%x,attr_id=0x%x,char_uuid=0x%x\n", + p_data->add_result.server_if, p_data->add_result.service_id, + p_data->add_result.attr_id, p_data->add_result.char_uuid.uu.uuid16); + bas_AddCharDescr(p_data->add_result.service_id, p_data->add_result.attr_id); + } + break; + + case BTA_GATTS_START_EVT: + { + LOG_ERROR("start service:server_if=%d,service_id=0x%x\n", p_data->srvc_oper.server_if, + p_data->srvc_oper.service_id); + bas_service_cmpl(p_data->srvc_oper.service_id, p_data->srvc_oper.status); + + /*start advertising*/ + if(p_data->srvc_oper.status == GATT_SUCCESS) + BTA_GATTS_Listen(server_if, true, NULL); + // BTA_GATTC_Broadcast(client_if, true); //non-connectable + } + break; + + case BTA_GATTS_READ_EVT: + { + UINT32 trans_id = p_data->req_data.trans_id; + UINT16 conn_id = p_data->req_data.conn_id; + UINT16 handle = p_data->req_data.p_data->read_req.handle; + bool is_long = p_data->req_data.p_data->read_req.is_long; + LOG_ERROR("read request:event=0x%x,handle=0x%x,trans_id=0x%x,conn_id=0x%x\n", + event, handle, trans_id, conn_id); + + if (dis_valid_handle_range(handle)) + { + tGATT_VALUE p_value; + p_value.handle = handle; + p_value.conn_id = conn_id; + p_value.offset = p_data->req_data.p_data->read_req.offset; + dis_s_read_attr_value(p_data->req_data.p_data, &p_value, trans_id, conn_id); + } + else + bas_s_read_attr_value(p_data->req_data.p_data, trans_id, conn_id); + } + break; + + case BTA_GATTS_WRITE_EVT: + { + + UINT32 trans_id = p_data->req_data.trans_id; + UINT16 conn_id = p_data->req_data.conn_id; + UINT16 handle = p_data->req_data.p_data->write_req.handle; + LOG_ERROR("write request:event=0x%x,handle=0x%x,trans_id=0x%x,conn_id=0x%x\n", + event, handle, trans_id, conn_id); + bas_s_write_attr_value(p_data->req_data.p_data, trans_id, conn_id, + p_data->req_data.remote_bda); + } + break; + + case BTA_GATTS_EXEC_WRITE_EVT: + { + UINT32 trans_id = p_data->req_data.trans_id; + UINT16 conn_id = p_data->req_data.conn_id; + UINT8 exec_write = p_data->req_data.p_data->exec_write; + LOG_ERROR("execute write request:event=0x%x,exce_write=0x%x,trans_id=0x%x,conn_id=0x%x\n", + event, exec_write, trans_id, conn_id); + } + break; + + case BTA_GATTS_MTU_EVT: + { + UINT32 trans_id = p_data->req_data.trans_id; + UINT16 conn_id = p_data->req_data.conn_id; + UINT16 mtu = p_data->req_data.p_data->mtu; + LOG_ERROR("exchange mtu request:event=0x%x,mtu=0x%x,trans_id=0x%x,conn_id=0x%x\n", + event, mtu, trans_id, conn_id); + } + break; + + case BTA_GATTS_CONF_EVT: + { + + UINT32 trans_id = p_data->req_data.trans_id; + UINT16 conn_id = p_data->req_data.conn_id; + LOG_ERROR("configue request:trans_id=0x%x,conn_id=0x%x\n", + trans_id, conn_id); + } + break; + + default: + LOG_ERROR("unsettled event: %d\n", event); + } + +} +/****************************************************************************** +** Function bas_callback +** +** Description battery service callback for client request +*******************************************************************************/ +static void bas_callback(UINT32 trans_id, UINT16 conn_id, UINT8 app_id, + UINT8 event, tBA_WRITE_DATA *p_data) +{ + tBA_RSP_DATA p_rsp; + tGATT_STATUS st = GATT_SUCCESS; + switch(event) + { + case BA_READ_LEVEL_REQ : + { + LOG_ERROR("read battery level\n"); + p_rsp.ba_level = 60; //battery level + Battery_Rsp(trans_id, conn_id, app_id, st, event, &p_rsp); + } + break; + + case BA_READ_PRE_FMT_REQ : + { + LOG_ERROR("read presentation format\n"); + } + break; + + case BA_READ_CLT_CFG_REQ : + { + LOG_ERROR("read client characteristic configuration request\n"); + p_rsp.clt_cfg = 0x0001; //notification + Battery_Rsp(trans_id, conn_id, app_id, st, event, &p_rsp); + } + break; + + case BA_READ_RPT_REF_REQ : + { + LOG_ERROR("read report reference descriptor\n"); + } + break; + + /*battery level notify*/ + case BA_WRITE_CLT_CFG_REQ : + { + LOG_ERROR("write client characteristic configuration request\n"); + Battery_Rsp(trans_id, conn_id, app_id, st, event, NULL); + + int battery_level = 50; + Battery_Notify(conn_id, app_id, p_data->remote_bda, battery_level); + } + break; + + default: + break; + } + + return; +} +/***************************************************************************** +** Function bas_s_read_attr_value +** +** Description it will be called when client sends a read request +******************************************************************************/ +void bas_s_read_attr_value(tGATTS_DATA *p_data, UINT32 trans_id, UINT16 conn_id) +{ + + tBA_INST *p_inst = &battery_cb.battery_inst[0]; + UINT8 i; + tGATT_STATUS st = GATT_NOT_FOUND; + UINT16 handle = p_data->read_req.handle; + + + for (i = 0; i < BA_MAX_INT_NUM; i ++, p_inst ++) + { + // read battery level + if (handle == p_inst->ba_level_hdl || + handle == p_inst->clt_cfg_hdl || + handle == p_inst->rpt_ref_hdl || + handle == p_inst->pres_fmt_hdl) + { + if (p_data->read_req.is_long) + st = GATT_NOT_LONG; + + if (p_inst->p_cback) + { + if (handle == p_inst->ba_level_hdl) p_inst->pending_evt = BA_READ_LEVEL_REQ; + if (handle == p_inst->clt_cfg_hdl) p_inst->pending_evt = BA_READ_CLT_CFG_REQ; + if (handle == p_inst->pres_fmt_hdl) p_inst->pending_evt = BA_READ_PRE_FMT_REQ; + if (handle == p_inst->rpt_ref_hdl) p_inst->pending_evt = BA_READ_RPT_REF_REQ ; + + // p_inst->pending_clcb_idx = clcb_idx; + p_inst->pending_handle = handle; + //act = SRVC_ACT_PENDING; + (*p_inst->p_cback)(trans_id, conn_id, p_inst->app_id, p_inst->pending_evt, NULL); + } + else /* application is not registered */ + st = GATT_ERR_UNLIKELY; + break; + } + /* else attribute not found */ + } +} + +/***************************************************************************** +** Function bas_s_write_attr_value +** +** Description it will be called when client sends a write request +******************************************************************************/ +void bas_s_write_attr_value(tGATTS_DATA *p_data, UINT32 trans_id, UINT16 conn_id, BD_ADDR bd_addr) +{ + tBA_WRITE_DATA cfg; + UINT8 *p = p_data->write_req.value; + tBA_INST *p_inst = &battery_cb.battery_inst[0]; + UINT8 i; + tGATT_STATUS st = GATT_NOT_FOUND; + UINT16 handle = p_data->write_req.handle; + + + for (i = 0; i < BA_MAX_INT_NUM; i ++, p_inst ++) + { + if (handle == p_inst->clt_cfg_hdl) + { + memcpy(cfg.remote_bda, bd_addr, BD_ADDR_LEN); + STREAM_TO_UINT16(cfg.clt_cfg, p); + + if (p_inst->p_cback) + { + p_inst->pending_evt = BA_WRITE_CLT_CFG_REQ; + p_inst->pending_handle = handle; + cfg.need_rsp = p_data->write_req.need_rsp; + (*p_inst->p_cback)(trans_id, conn_id, p_inst->app_id, p_inst->pending_evt, &cfg); + } + else /* all other handle is not writable */ + st = GATT_WRITE_NOT_PERMIT; + break; + } + + } +} +/*************************************************************** +** +** Function bas_register +** +** Description register app for battery service +** +****************************************************************/ +void bas_register(void) +{ + BTA_GATTS_AppRegister(&bas_uuid, bas_gatts_callback); + +} +/*************************************************************** +** +** Function bas_init +** +** Description register battery service +** +****************************************************************/ +void bas_init(tBTA_GATTS_IF gatt_if, UINT16 app_id) +{ + + tBA_INST *p_inst; + + ba_reg_info.is_pri = true; + ba_reg_info.ba_level_descr = BA_LEVEL_NOTIFY; + ba_reg_info.transport = GATT_TRANSPORT_LE; + ba_reg_info.p_cback = bas_callback; + if (battery_cb.inst_id == BA_MAX_INT_NUM) + { + GATT_TRACE_ERROR("MAX battery service has been reached\n"); + return; + } + + p_inst = &battery_cb.battery_inst[battery_cb.inst_id]; + + LOG_ERROR("create battery service\n"); + LOG_ERROR("inst_id=%d\n", battery_cb.inst_id); + BTA_GATTS_CreateService (gatt_if, &bas_uuid, battery_cb.inst_id , + BA_MAX_ATTR_NUM, ba_reg_info.is_pri); + + battery_cb.inst_id ++; + + p_inst->app_id = app_id; + p_inst->p_cback = ba_reg_info.p_cback; + +} + +/*************************************************************** +** +** Function bas_AddChar +** +** Description add characteristic for battery service +** +****************************************************************/ +void bas_AddChar(UINT16 service_id, tBT_UUID *char_uuid) +{ + if (ba_reg_info.ba_level_descr & BA_LEVEL_NOTIFY) + prop |= GATT_CHAR_PROP_BIT_NOTIFY; + attr_handle_bit = 0x01; + BTA_GATTS_AddCharacteristic(service_id, char_uuid, BATTER_LEVEL_PERM, prop); + +} + +/*************************************************************** +** +** Function bas_AddCharDescr +** +** Description add descriptor for battery service if needed +** +****************************************************************/ +void bas_AddCharDescr(UINT16 service_id, UINT16 attr_id) +{ + tBT_UUID uuid; + uuid.len = LEN_UUID_16; + + battery_cb.inst_id --; + tBA_INST *p_inst = &battery_cb.battery_inst[battery_cb.inst_id++]; + /*store the attribute handles*/ + if(attr_handle_bit == 0x01) + p_inst->ba_level_hdl = attr_id; + else if(attr_handle_bit == 0x02) + p_inst->clt_cfg_hdl = attr_id; + else if(attr_handle_bit == 0x04) + p_inst->pres_fmt_hdl = attr_id; + else if(attr_handle_bit == 0x08) + p_inst->rpt_ref_hdl = attr_id; + + + if (ba_reg_info.ba_level_descr != 0) + { + if (ba_reg_info.ba_level_descr & BA_LEVEL_NOTIFY) + { + uuid.uu.uuid16 = GATT_UUID_CHAR_CLIENT_CONFIG; + ba_reg_info.ba_level_descr &= 0xfe; + attr_handle_bit = 0x02; + BTA_GATTS_AddCharDescriptor(service_id, (GATT_PERM_READ|GATT_PERM_WRITE), &uuid); + return; + } + + /* need presentation format descriptor? */ + if (ba_reg_info.ba_level_descr & BA_LEVEL_PRE_FMT) + { + uuid.uu.uuid16 = GATT_UUID_CHAR_PRESENT_FORMAT; + BTA_GATTS_AddCharDescriptor(service_id, GATT_PERM_READ, &uuid); + ba_reg_info.ba_level_descr &= 0xfd; + attr_handle_bit = 0x04; + return; + } + /* need report reference format descriptor? */ + if (ba_reg_info.ba_level_descr & BA_LEVEL_RPT_REF) + { + uuid.uu.uuid16 = GATT_UUID_RPT_REF_DESCR; + ba_reg_info.ba_level_descr &= 0xfb; + BTA_GATTS_AddCharDescriptor(service_id, GATT_PERM_READ, &uuid); + attr_handle_bit = 0x08; + return; + } + } + + else + BTA_GATTS_StartService(service_id, ba_reg_info.transport); + +} + +/*************************************************************** +** +** Function bas_service_cmpl +** +** Description create battery service complete +** +****************************************************************/ +void bas_service_cmpl(UINT16 service_id, tBTA_GATT_STATUS status) +{ + if(status != GATT_SUCCESS) + { + battery_cb.inst_id --; + BTA_GATTS_DeleteService(service_id); + } + +} +/******************************************************************************* +** +** Function Battery_Rsp +** +** Description Respond to a battery service request +** +*******************************************************************************/ +void Battery_Rsp (UINT32 trans_id, UINT16 conn_id, UINT8 app_id, + tGATT_STATUS st, UINT8 event, tBA_RSP_DATA *p_rsp) +{ + tBA_INST *p_inst = &battery_cb.battery_inst[0]; + tGATTS_RSP rsp; + UINT8 *pp; + + UINT8 i = 0; + while (i < BA_MAX_INT_NUM) + { + if (p_inst->app_id == app_id && p_inst->ba_level_hdl != 0) + break; + i ++; + } + + if (i == BA_MAX_INT_NUM) + return; + + memset(&rsp, 0, sizeof(tGATTS_RSP)); + + if (p_inst->pending_evt == event) + { + switch (event) + { + case BA_READ_CLT_CFG_REQ: + rsp.attr_value.handle = p_inst->pending_handle; + rsp.attr_value.len = 2; + pp = rsp.attr_value.value; + UINT16_TO_STREAM(pp, p_rsp->clt_cfg); + BTA_GATTS_SendRsp(conn_id, trans_id, st, &rsp); + //srvc_sr_rsp(p_inst->pending_clcb_idx, st, &rsp); + break; + + case BA_READ_LEVEL_REQ: + rsp.attr_value.handle = p_inst->pending_handle; + rsp.attr_value.len = 1; + pp = rsp.attr_value.value; + UINT8_TO_STREAM(pp, p_rsp->ba_level); + BTA_GATTS_SendRsp(conn_id, trans_id, st, &rsp); + //srvc_sr_rsp(p_inst->pending_clcb_idx, st, &rsp); + break; + + case BA_WRITE_CLT_CFG_REQ: + BTA_GATTS_SendRsp(conn_id, trans_id, st, NULL); + //srvc_sr_rsp(p_inst->pending_clcb_idx, st, NULL); + break; + + case BA_READ_RPT_REF_REQ: + rsp.attr_value.handle = p_inst->pending_handle; + rsp.attr_value.len = 2; + pp = rsp.attr_value.value; + UINT8_TO_STREAM(pp, p_rsp->rpt_ref.rpt_id); + UINT8_TO_STREAM(pp, p_rsp->rpt_ref.rpt_type); + BTA_GATTS_SendRsp(conn_id, trans_id, st, &rsp); + //srvc_sr_rsp(p_inst->pending_clcb_idx, st, &rsp); + break; + + default: + break; + } + // p_inst->pending_clcb_idx = 0; + p_inst->pending_evt = 0; + p_inst->pending_handle = 0; + } + return; +} +/******************************************************************************* +** +** Function Battery_Notify +** +** Description Send battery level notification +** +*******************************************************************************/ +void Battery_Notify (UINT16 conn_id, UINT8 app_id, BD_ADDR remote_bda, UINT8 battery_level) +{ + tBA_INST *p_inst = &battery_cb.battery_inst[0]; + UINT8 i = 0; + + while (i < BA_MAX_INT_NUM) + { + if (p_inst->app_id == app_id && p_inst->ba_level_hdl != 0) + break; + i ++; + } + + if (i == BA_MAX_INT_NUM || p_inst->clt_cfg_hdl == 0) + return; + BTA_GATTS_HandleValueIndication(conn_id, p_inst->ba_level_hdl, 1, &battery_level, false); + //srvc_sr_notify(remote_bda, p_inst->ba_level_hdl, 1, &battery_level); + +} +#endif diff --git a/components/bt/bluedroid/profiles/diss/diss_profile.c b/components/bt/bluedroid/profiles/diss/diss_profile.c new file mode 100644 index 0000000000..c53c22d041 --- /dev/null +++ b/components/bt/bluedroid/profiles/diss/diss_profile.c @@ -0,0 +1,310 @@ +/****************************************************************************** + * + * Copyright (C) 1999-2013 Broadcom Corporation + * + * 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. + * + ******************************************************************************/ + +#include "bt_target.h" +//#include "bt_utils.h" +//#include "gatt_api.h" + +#define LOG_TAG "bt_srvc" +//#include "osi/include/log.h" +#include "stdio.h" +#include "stdint.h" +#include "string.h" + +#include "bta_api.h" +#include "bta_gatt_api.h" +#include "controller.h" + +#include "gatt_int.h" +#include "bt_trace.h" +#include "btm_api.h" +#include "bt_types.h" +#include "gatt_profile.h" + +#if BLE_INCLUDED == TRUE + +#define UINT64_TO_STREAM(p, u64) {*(p)++ = (UINT8)(u64); *(p)++ = (UINT8)((u64) >> 8);*(p)++ = (UINT8)((u64) >> 16); *(p)++ = (UINT8)((u64) >> 24); \ + *(p)++ = (UINT8)((u64) >> 32); *(p)++ = (UINT8)((u64) >> 40);*(p)++ = (UINT8)((u64) >> 48); *(p)++ = (UINT8)((u64) >> 56);} + +#define STREAM_TO_UINT64(u64, p) {u64 = (((UINT64)(*(p))) + ((((UINT64)(*((p) + 1)))) << 8) + ((((UINT64)(*((p) + 2)))) << 16) + ((((UINT64)(*((p) + 3)))) << 24) \ + + ((((UINT64)(*((p) + 4)))) << 32) + ((((UINT64)(*((p) + 5)))) << 40) + ((((UINT64)(*((p) + 6)))) << 48) + ((((UINT64)(*((p) + 7)))) << 56)); (p) += 8;} + +tBT_UUID uuid = {LEN_UUID_16, {UUID_SERVCLASS_DEVICE_INFO}}; +UINT16 i = 0; +tDIS_ATTR_MASK dis_mask; +static const UINT16 dis_attr_uuid[DIS_MAX_CHAR_NUM] = +{ + GATT_UUID_SYSTEM_ID, + GATT_UUID_MODEL_NUMBER_STR, + GATT_UUID_SERIAL_NUMBER_STR, + GATT_UUID_FW_VERSION_STR, + GATT_UUID_HW_VERSION_STR, + GATT_UUID_SW_VERSION_STR, + GATT_UUID_MANU_NAME, + GATT_UUID_IEEE_DATA, + GATT_UUID_PNP_ID +}; + +tDIS_CB dis_cb; + +static tDIS_ATTR_MASK dis_uuid_to_attr(UINT16 uuid) +{ + switch (uuid) + { + case GATT_UUID_SYSTEM_ID: + return DIS_ATTR_SYS_ID_BIT; + case GATT_UUID_MODEL_NUMBER_STR: + return DIS_ATTR_MODEL_NUM_BIT; + case GATT_UUID_SERIAL_NUMBER_STR: + return DIS_ATTR_SERIAL_NUM_BIT; + case GATT_UUID_FW_VERSION_STR: + return DIS_ATTR_FW_NUM_BIT; + case GATT_UUID_HW_VERSION_STR: + return DIS_ATTR_HW_NUM_BIT; + case GATT_UUID_SW_VERSION_STR: + return DIS_ATTR_SW_NUM_BIT; + case GATT_UUID_MANU_NAME: + return DIS_ATTR_MANU_NAME_BIT; + case GATT_UUID_IEEE_DATA: + return DIS_ATTR_IEEE_DATA_BIT; + case GATT_UUID_PNP_ID: + return DIS_ATTR_PNP_ID_BIT; + default: + return 0; + }; +} + +/******************************************************************************* +** dis_valid_handle_range +** +** validate a handle to be a DIS attribute handle or not. +*******************************************************************************/ +BOOLEAN dis_valid_handle_range(UINT16 handle) +{ + if (handle >= dis_cb.service_handle && handle <= dis_cb.max_handle) + return TRUE; + else + return FALSE; +} +/******************************************************************************* +** dis_write_attr_value +** +** Process write DIS attribute request. +*******************************************************************************/ +UINT8 dis_write_attr_value(tGATT_WRITE_REQ * p_data, tGATT_STATUS *p_status) +{ + UNUSED(p_data); + + *p_status = GATT_WRITE_NOT_PERMIT; + return GATT_SUCCESS; +} +/******************************************************************************* +** DIS Attributes Database Server Request callback +*******************************************************************************/ + +/******************************************************************************* +** dis_s_read_attr_value +** +** Process read DIS attribute request. +*******************************************************************************/ +void dis_s_read_attr_value (tGATTS_DATA *p_data, tGATT_VALUE *p_value, UINT32 trans_id, UINT16 conn_id) +{ + tDIS_DB_ENTRY *p_db_attr = dis_cb.dis_attr; + UINT8 *p = p_value->value, i, *pp; + UINT16 offset = p_data->read_req.offset; + tGATT_STATUS st = GATT_NOT_FOUND; + UINT16 handle = p_data->read_req.handle; + bool is_long = p_data->read_req.is_long; + + for (i = 0; i < DIS_MAX_CHAR_NUM; i ++, p_db_attr ++) + { + if (handle == p_db_attr->handle) + { + if ((p_db_attr->uuid == GATT_UUID_PNP_ID || p_db_attr->uuid == GATT_UUID_SYSTEM_ID)&& + is_long == TRUE) + { + st = GATT_NOT_LONG; + break; + } + st = GATT_SUCCESS; + + switch (p_db_attr->uuid) + { + case GATT_UUID_MANU_NAME: + case GATT_UUID_MODEL_NUMBER_STR: + case GATT_UUID_SERIAL_NUMBER_STR: + case GATT_UUID_FW_VERSION_STR: + case GATT_UUID_HW_VERSION_STR: + case GATT_UUID_SW_VERSION_STR: + case GATT_UUID_IEEE_DATA: + pp = dis_cb.dis_value.data_string[p_db_attr->uuid - GATT_UUID_MODEL_NUMBER_STR]; + if (pp != NULL) + { + if (strlen ((char *)pp) > GATT_MAX_ATTR_LEN) + p_value->len = GATT_MAX_ATTR_LEN; + else + p_value->len = (UINT16)strlen ((char *)pp); + } + else + p_value->len = 0; + + if (offset > p_value->len) + { + st = GATT_INVALID_OFFSET; + break; + } + else + { + p_value->len -= offset; + pp += offset; + ARRAY_TO_STREAM(p, pp, p_value->len); + GATT_TRACE_EVENT("GATT_UUID_MANU_NAME len=0x%04x", p_value->len); + } + break; + + + case GATT_UUID_SYSTEM_ID: + UINT64_TO_STREAM(p, dis_cb.dis_value.system_id); /* int_min */ + p_value->len = DIS_SYSTEM_ID_SIZE; + break; + + case GATT_UUID_PNP_ID: + UINT8_TO_STREAM(p, dis_cb.dis_value.pnp_id.vendor_id_src); + UINT16_TO_STREAM(p, dis_cb.dis_value.pnp_id.vendor_id); + UINT16_TO_STREAM(p, dis_cb.dis_value.pnp_id.product_id); + UINT16_TO_STREAM(p, dis_cb.dis_value.pnp_id.product_version); + p_value->len = DIS_PNP_ID_SIZE; + break; + + } + break; + } + } + tGATTS_RSP rsp; + rsp.attr_value = *p_value; + BTA_GATTS_SendRsp(conn_id, trans_id, st, &rsp); + +} + + +/******************************************************************************* +** +** Function DIS_Init +** +** Description Initialize the Device Information Service Server. +** +*******************************************************************************/ +void DIS_Init (tBTA_GATTS_IF gatt_if, tDIS_ATTR_MASK dis_attr_mask) +{ + + tGATT_STATUS status; + dis_mask = dis_attr_mask; + if (dis_cb.enabled) + { + GATT_TRACE_ERROR("DIS already initalized"); + return; + } + + memset(&dis_cb, 0, sizeof(tDIS_CB)); + + BTA_GATTS_CreateService (gatt_if , &uuid, 0, DIS_MAX_ATTR_NUM, TRUE); + +} +/******************************************************************************* +** +** Function dis_AddChar +** +** Description add characteristic for dis +** +*******************************************************************************/ + +void dis_AddChar(UINT16 service_id) +{ + //dis_cb.service_handle = service_id; + //dis_cb.max_handle = service_id + DIS_MAX_ATTR_NUM; + tDIS_DB_ENTRY *p_db_attr = &dis_cb.dis_attr[0]; + while(dis_mask != 0 && i < DIS_MAX_CHAR_NUM) + { + uuid.uu.uuid16 = p_db_attr->uuid = dis_attr_uuid[i]; + BTA_GATTS_AddCharacteristic(dis_cb.service_handle, &uuid, GATT_PERM_READ, + GATT_CHAR_PROP_BIT_READ); + p_db_attr ++; + i ++; + dis_mask >>= 1; + } + /*start service*/ + BTA_GATTS_StartService(dis_cb.service_handle, GATT_TRANSPORT_LE_BR_EDR); + dis_cb.enabled = TRUE; +} +/******************************************************************************* +** +** Function DIS_SrUpdate +** +** Description Update the DIS server attribute values +** +*******************************************************************************/ +tDIS_STATUS DIS_SrUpdate(tDIS_ATTR_BIT dis_attr_bit, tDIS_ATTR *p_info) +{ + UINT8 i = 1; + tDIS_STATUS st = DIS_SUCCESS; + + if (dis_attr_bit & DIS_ATTR_SYS_ID_BIT) + { + dis_cb.dis_value.system_id = p_info->system_id; + } + else if (dis_attr_bit & DIS_ATTR_PNP_ID_BIT) + { + dis_cb.dis_value.pnp_id.vendor_id = p_info->pnp_id.vendor_id; + dis_cb.dis_value.pnp_id.vendor_id_src = p_info->pnp_id.vendor_id_src; + dis_cb.dis_value.pnp_id.product_id = p_info->pnp_id.product_id; + dis_cb.dis_value.pnp_id.product_version = p_info->pnp_id.product_version; + } + else + { + st = DIS_ILLEGAL_PARAM; + + while (dis_attr_bit && i < (DIS_MAX_CHAR_NUM -1 )) + { + if (dis_attr_bit & (UINT16)(1 << i)) + { + if (dis_cb.dis_value.data_string[i - 1] != NULL) + GKI_freebuf(dis_cb.dis_value.data_string[i - 1]); +/* coverity[OVERRUN-STATIC] False-positive : when i = 8, (1 << i) == DIS_ATTR_PNP_ID_BIT, and it will never come down here +CID 49902: Out-of-bounds read (OVERRUN_STATIC) +Overrunning static array "dis_cb.dis_value.data_string", with 7 elements, at position 7 with index variable "i". +*/ + if ((dis_cb.dis_value.data_string[i - 1] = (UINT8 *)GKI_getbuf((UINT16)(p_info->data_str.len + 1))) != NULL) + { + + memcpy(dis_cb.dis_value.data_string[i - 1], p_info->data_str.p_data, p_info->data_str.len); + dis_cb.dis_value.data_string[i - 1][p_info->data_str.len] = 0; /* make sure null terminate */ + st = DIS_SUCCESS; + } + else + st = DIS_NO_RESOURCES; + + break; + } + i ++; + } + } + return st; +} +#endif /* BLE_INCLUDED */ + + diff --git a/components/bt/bluedroid/profiles/hid_le/hid_le_prf.c b/components/bt/bluedroid/profiles/hid_le/hid_le_prf.c new file mode 100644 index 0000000000..25b7c8c45f --- /dev/null +++ b/components/bt/bluedroid/profiles/hid_le/hid_le_prf.c @@ -0,0 +1,300 @@ +/** + **************************************************************************************** + * + * @file hid_le_prf.c + * + * @brief Application entry point + * + * Copyright (C) Espressif 2016 + * Created by Yulong at 2016/9/7 + * + * + **************************************************************************************** + */ +#include +#include "hid_le_prf.h" +#include "prf_defs.h" +#include "bta_gatt_api.h" + +tHIDD_LE_ENV hidd_le_env; + +tBT_UUID char_info_uuid = {LEN_UUID_16, {CHAR_HID_INFO_UUID}}; +tBT_UUID char_ctnl_pt_uuid = {LEN_UUID_16, {CHAR_HID_CTNL_PT_UUID}}; +tBT_UUID char_report_map_uuid = {LEN_UUID_16, {CHAR_REPORT_MAP_UUID}}; +tBT_UUID char_proto_mode_uuid = {LEN_UUID_16, {CHAR_PROTOCOL_MODE_UUID}}; +tBT_UUID char_kb_in_report_uuid = {LEN_UUID_16, {CHAR_BOOT_KB_IN_REPORT_UUID}}; +tBT_UUID char_kb_out_report_uuid = {LEN_UUID_16,{CHAR_BOOT_KB_OUT_REPORT_UUID}}; +tBT_UUID char_mouse_in_report_uuid = {LEN_UUID_16,{CHAR_BOOT_MOUSE_IN_REPORT_UUID}}; + + + +/// Full HID device Database Description - Used to add attributes into the database +const tCHAR_DESC hids_char_db[HIDD_LE_CHAR_MAX] = +{ + // HID Information Characteristic Value + [HIDD_LE_INFO_CHAR] = { + &char_info_uuid, + GATT_PERM_READ, + GATT_CHAR_PROP_BIT_READ + }, + + // HID Control Point Characteristic Value + [HIDD_LE_CTNL_PT_CHAR] = { + &char_ctnl_pt_uuid, + GATT_PERM_WRITE, + GATT_CHAR_PROP_BIT_WRITE_NR + }, + + // Report Map Characteristic Value + [HIDD_LE_REPORT_MAP_CHAR] = { + &char_report_map_uuid, + GATT_PERM_READ, + GATT_CHAR_PROP_BIT_READ + }, + + // Protocol Mode Characteristic Declaration + [HIDD_LE_PROTO_MODE_CHAR] = { + &char_proto_mode_uuid, + GATT_PERM_READ, + GATT_CHAR_PROP_BIT_READ, + }, + + // Boot Keyboard Input Report Characteristic Value + [HIDD_LE_BOOT_KB_IN_REPORT_CHAR] = { + &char_kb_in_report_uuid, + GATT_PERM_READ, + (GATT_CHAR_PROP_BIT_READ|GATT_CHAR_PROP_BIT_NOTIFY), + + }, + + // Boot Keyboard Output Report Characteristic Value + [HIDD_LE_BOOT_KB_OUT_REPORT_CHAR] = { + &char_kb_out_report_uuid, + GATT_PERM_READ, + (GATT_CHAR_PROP_BIT_READ|GATT_CHAR_PROP_BIT_WRITE|GATT_CHAR_PROP_BIT_WRITE_NR) + }, + + // Boot Mouse Input Report Characteristic Value + [HIDD_LE_BOOT_MOUSE_IN_REPORT_CHAR] = { + &char_mouse_in_report_uuid, + GATT_PERM_READ, + (GATT_CHAR_PROP_BIT_READ|GATT_CHAR_PROP_BIT_NOTIFY), + }, +}; + + +//tBT_UUID hid_uuid = {LEN_UUID_16, {ATT_SVC_BUTTON}}; + +static void HID_AddCharacteristic(const tCHAR_DESC *char_desc); + +/***************************************************************************** +** Constants +*****************************************************************************/ +static void hidd_le_profile_cb(tBTA_GATTS_EVT event, tBTA_GATTS *p_data); + +/******************************************************************************* +** +** Function hidd_le_profile_cb +** +** Description the callback function after the hid device profile has been register to the BTA manager module +** +** Returns NULL +** +*******************************************************************************/ +static void HID_AddCharacteristic(const tCHAR_DESC *char_desc) +{ + UINT16 service_id; + if(char_desc == NULL) + { + LOG_ERROR("Invalid hid characteristic"); + return; + } + //check the hid device serivce has been register to the data base or not + if(!hidd_le_env.enabled) + { + LOG_ERROR("The hid device didn't register yet"); + return; + } + //get the service id from the env whitch has been register + service_id = hidd_le_env.hidd_clcb.cur_srvc_id; + if(char_desc->char_uuid != 0x00) + { + // start added the charact to the data base + BTA_GATTS_AddCharacteristic(service_id, + char_desc->char_uuid, + char_desc->perm, + char_desc->prop); + } +} + + +/******************************************************************************* +** +** Function hidd_le_profile_cb +** +** Description the callback function after the hid device profile has been register to the BTA manager module +** +** Returns NULL +** +*******************************************************************************/ +static void hidd_le_profile_cb(tBTA_GATTS_EVT event, tBTA_GATTS *p_data) +{ + tBTA_GATTS_RSP rsp; + tBT_UUID uuid = {LEN_UUID_16, {ATT_SVC_HID}}; + static UINT8 hid_char_idx; + tHIDD_CLCB *p_clcb = NULL; + switch(event) + { + case BTA_GATTS_REG_EVT: + //check the register of the hid device profile has been succeess or not + if(p_data->reg_oper.status != BTA_GATT_OK) + { + LOG_ERROR("button profile register failed\n"); + } + //save the gatt interface in the hid device ENV + hidd_le_env.gatt_if = p_data->reg_oper.server_if; + //set the env flag to enable + hidd_le_env.enabled = true; + //create the hid device service to the service data base. + if(p_data->reg_oper.uuid.uu.uuid16 == ATT_SVC_HID) + { + hidd_le_CreateService(true); + } + break; + case BTA_GATTS_CREATE_EVT: + if(p_data->create.uuid.uu.uuid16 == ATT_SVC_HID) + { + ///store the service id to the env + hidd_le_env.hidd_clcb.cur_srvc_id = p_data->create.service_id; + //start the button service after created + BTA_GATTS_StartService(p_data->create.service_id,BTA_GATT_TRANSPORT_LE); + hid_char_idx = HIDD_LE_INFO_CHAR; + //added the info character to the data base. + HID_AddCharacteristic(&hids_char_db[hid_char_idx]); + hid_char_idx++; + } + + break; + case BTA_GATTS_ADD_INCL_SRVC_EVT: + + break; + case BTA_GATTS_ADD_CHAR_EVT: + if(hid_char_idx < HIDD_LE_CHAR_MAX) //added the characteristic until the index overflow + { + HID_AddCharacteristic(&hids_char_db[hid_char_idx]); + if((p_data->add_result.char_uuid.uu.uuid16 == CHAR_BOOT_KB_IN_REPORT_UUID) || + (p_data->add_result.char_uuid.uu.uuid16 == CHAR_BOOT_MOUSE_IN_REPORT_UUID)) + { + // add the gattc config descriptor to the notify charateristic + //tBTA_GATT_PERM perm = (GATT_PERM_WRITE|GATT_PERM_WRITE); + uuid.uu.uuid16 = GATT_UUID_CHAR_CLIENT_CONFIG; + + BTA_GATTS_AddCharDescriptor (hidd_le_env.hidd_clcb.cur_srvc_id, + GATT_PERM_WRITE, + &uuid); + } + } + hid_char_idx++; + break; + case BTA_GATTS_ADD_CHAR_DESCR_EVT: + + break; + case BTA_GATTS_WRITE_EVT: + BTA_GATTS_SendRsp(p_data->req_data.conn_id,p_data->req_data.trans_id, + p_data->req_data.status,NULL); + break; + case BTA_GATTS_CONNECT_EVT: + p_clcb = &hidd_le_env.hidd_clcb; + + if(!p_clcb->in_use) + { + p_clcb->in_use = TRUE; + p_clcb->conn_id = p_data->conn.conn_id;; + LOG_ERROR("hidd->conn_id = %x\n",p_data->conn.conn_id); + p_clcb->connected = TRUE; + memcpy(p_clcb->remote_bda, p_data->conn.remote_bda,BD_ADDR_LEN); + } + break; + case BTA_GATTS_DISCONNECT_EVT: + p_clcb = &hidd_le_env.hidd_clcb; + //set the connection flag to true + p_clcb->connected = false; + p_clcb->in_use = TRUE; + memset(p_clcb->remote_bda,0,BD_ADDR_LEN); + break; + case BTA_GATTS_START_EVT: + break; + case BTA_GATTS_CONGEST_EVT: + if(hidd_le_env.hidd_clcb.connected && (hidd_le_env.hidd_clcb.conn_id == p_data->conn.conn_id)) + { + //set the connection channal congested flag to true + hidd_le_env.hidd_clcb.congest = p_data->congest.congested; + } + break; + default: + break; + } +} + +/******************************************************************************* +** +** Function hidd_le_CreateService +** +** Description Create a Service for the hid device profile +** +** Parameters is_primary: this service is the primary service or not,true is the primary service +** false is not the primary service +** p_service_uuid: service UUID. +** +** Returns NULL +** +*******************************************************************************/ +void hidd_le_CreateService(BOOLEAN is_primary) +{ + tBTA_GATTS_IF server_if ; + tBT_UUID uuid = {LEN_UUID_16, {ATT_SVC_HID}}; + //the number of the hid device attributes in the hid service. + UINT16 num_handle = HIDD_LE_IDX_NB; + UINT8 inst = 0x00; + server_if = hidd_le_env.gatt_if; + hidd_le_env.inst_id = inst; + //start create the hid device service + BTA_GATTS_CreateService(server_if,&uuid,inst,num_handle,is_primary); +} + + + + +/******************************************************************************* +** +** Function hidd_le_init +** +** Description Initializa the GATT Service for button profiles. +** Returns NULL +*******************************************************************************/ +tGATT_STATUS hidd_le_init (void) +{ + tBT_UUID app_uuid = {LEN_UUID_16,{ATT_SVC_HID}}; + + if(hidd_le_env.enabled) + { + LOG_ERROR("hid device svc already initaliezd"); + return GATT_ERROR; + } + else + { + memset(&hidd_le_env,0,sizeof(tHIDD_LE_ENV)); + } + + + /* register the hid deivce profile to the BTA_GATTS module*/ + BTA_GATTS_AppRegister(&app_uuid,hidd_le_profile_cb); + + hidd_le_env.enabled = TRUE; + + return GATT_SUCCESS; +} + + + + diff --git a/components/bt/bluedroid/profiles/include/button_pro.h b/components/bt/bluedroid/profiles/include/button_pro.h new file mode 100644 index 0000000000..5d36aa2199 --- /dev/null +++ b/components/bt/bluedroid/profiles/include/button_pro.h @@ -0,0 +1,110 @@ +/** + **************************************************************************************** + * + * @file button_pro.h + * + * @brief Application entry point + * + * Copyright (C) Espressif 2016 + * Created by Yulong at 2016/8/18 + * + * + **************************************************************************************** + */ + +#include "bt_target.h" +#include "gatt_api.h" +#include "gattdefs.h" + +#define KEY_SUCCESS GATT_SUCCESS +#define KEY_ILLEGAL_PARAM GATT_ILLEGAL_PARAMETER +#define KEY_NO_RESOURCES GATT_NO_RESOURCES + +//define the key serivce uuid +#define ATT_SVC_BUTTON 0xFFFF +//define the key Char uuid +#define ATT_CHAR_BUTTON_WIT 0xFF01 +#define ATT_CHAR_BUTTON_NTF 0xFF02 + +#define BUTTON_PRESS_NTF_CFG 0x01 + +#define BUTTON_VAL_MAX_LEN (10) + +#define BUTT_MAX_APPS GATT_CL_MAX_LCB + +#define BUT_MAX_STRING_DATA 7 + + +#ifndef BUT_MAX_INT_NUM +#define BUT_MAX_INT_NUM 4 +#endif + + +/// button Service Attributes Indexes +enum +{ + KEY_IDX_SVC, + KEY_IDX_BUTTON_WIT_CHAR, + KEY_IDX_BUTTON_WIT_VAL, + KEY_IDX_BUTTON_NTF_CHAR, + KEY_IDX_BUTTON_NTF_VAL, + KEY_IDX_BUTTON_NTF_CFG, + + KEY_IDX_NB, +}; + +typedef struct +{ + BD_ADDR remote_bda; + BOOLEAN need_rsp; + UINT16 clt_cfg; +}tBUT_WRITE_DATA; + +typedef struct +{ + BOOLEAN in_use; + BOOLEAN congest; + UINT16 conn_id; + BOOLEAN connected; + BD_ADDR remote_bda; + UINT32 trans_id; + UINT8 cur_srvc_id; + +}tBUT_CLCB; + + +typedef struct +{ + UINT8 app_id; + UINT16 but_wirt_hdl; + UINT16 but_ntf_hdl; + UINT16 but_cfg_hdl; + +}tBUT_INST; + + +/* service engine control block */ +typedef struct +{ + tBUT_CLCB clcb; /* connection link*/ + tGATT_IF gatt_if; + BOOLEAN enabled; + BOOLEAN is_primery; + tBUT_INST button_inst; + UINT8 inst_id; +}tBUTTON_CB_ENV; + +void Button_CreateService(void); + +tBUT_CLCB *button_env_clcb_alloc(UINT16 conn_id, BD_ADDR bda); + +UINT16 button_env_find_conn_id_by_bd_adddr(BD_ADDR bda); + +BOOLEAN button_env_clcb_dealloc(UINT16 conn_id); + +tGATT_STATUS button_init(void); + +void button_msg_notify(UINT8 len, UINT8 *button_msg); + +extern tBUTTON_CB_ENV button_cb_env; + diff --git a/components/bt/bluedroid/profiles/include/gatt_profile.h b/components/bt/bluedroid/profiles/include/gatt_profile.h new file mode 100644 index 0000000000..095a76c508 --- /dev/null +++ b/components/bt/bluedroid/profiles/include/gatt_profile.h @@ -0,0 +1,348 @@ +/****************************************************************************** + * + * Copyright (C) 1999-2013 Broadcom Corporation + * + * 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. + * + ******************************************************************************/ + +/******************************************************************************* +** +** Header file for profile folder. +** +********************************************************************************/ + +#ifndef SRVC_DIS_API_H +#define SRVC_DIS_API_H + +#include "bt_target.h" +#include "gatt_api.h" +#include "gattdefs.h" + +#define DIS_SUCCESS GATT_SUCCESS +#define DIS_ILLEGAL_PARAM GATT_ILLEGAL_PARAMETER +#define DIS_NO_RESOURCES GATT_NO_RESOURCES +typedef UINT8 tDIS_STATUS; + + +/***************************************************************************** +** Data structure for DIS +*****************************************************************************/ + +#define DIS_ATTR_SYS_ID_BIT 0x0001 +#define DIS_ATTR_MODEL_NUM_BIT 0x0002 +#define DIS_ATTR_SERIAL_NUM_BIT 0x0004 +#define DIS_ATTR_FW_NUM_BIT 0x0008 +#define DIS_ATTR_HW_NUM_BIT 0x0010 +#define DIS_ATTR_SW_NUM_BIT 0x0020 +#define DIS_ATTR_MANU_NAME_BIT 0x0040 +#define DIS_ATTR_IEEE_DATA_BIT 0x0080 +#define DIS_ATTR_PNP_ID_BIT 0x0100 +typedef UINT16 tDIS_ATTR_MASK; + +#define DIS_ATTR_ALL_MASK 0xffff + +typedef tDIS_ATTR_MASK tDIS_ATTR_BIT ; + +#define DIS_MAX_NUM_INC_SVR 0 +#define DIS_MAX_CHAR_NUM 9 +#define DIS_MAX_ATTR_NUM (DIS_MAX_CHAR_NUM * 2 + DIS_MAX_NUM_INC_SVR + 1) + +#ifndef DIS_ATTR_DB_SIZE +#define DIS_ATTR_DB_SIZE GATT_DB_MEM_SIZE(DIS_MAX_NUM_INC_SVR, DIS_MAX_CHAR_NUM, 0) +#endif + +#define DIS_SYSTEM_ID_SIZE 8 +#define DIS_PNP_ID_SIZE 7 + + +typedef struct +{ + UINT16 uuid; + UINT16 handle; +}tDIS_DB_ENTRY; + +typedef struct +{ + UINT16 len; + UINT8 *p_data; +}tDIS_STRING; + +typedef struct +{ + UINT16 vendor_id; + UINT16 product_id; + UINT16 product_version; + UINT8 vendor_id_src; + +}tDIS_PNP_ID; + +typedef union +{ + UINT64 system_id; + tDIS_PNP_ID pnp_id; + tDIS_STRING data_str; +}tDIS_ATTR; + +#define DIS_MAX_STRING_DATA 7 + +typedef struct +{ + UINT16 attr_mask; + UINT64 system_id; + tDIS_PNP_ID pnp_id; + UINT8 *data_string[DIS_MAX_STRING_DATA]; +}tDIS_VALUE; + +//typedef void (tDIS_READ_CBACK)(BD_ADDR addr, tDIS_VALUE *p_dis_value); + +typedef struct +{ + tDIS_DB_ENTRY dis_attr[DIS_MAX_CHAR_NUM]; + tDIS_VALUE dis_value; + +// tDIS_READ_CBACK *p_read_dis_cback; + + UINT16 service_handle; + UINT16 max_handle; + + bool enabled; + + // UINT8 dis_read_uuid_idx; + // tDIS_ATTR_MASK request_mask; +}tDIS_CB; + +/***************************************************************************** +** Data structure used by Battery Service +*****************************************************************************/ + +#ifndef BA_MAX_INT_NUM +#define BA_MAX_INT_NUM 4 +#endif + +#define BATTERY_LEVEL_SIZE 1 + +typedef struct +{ + BD_ADDR remote_bda; + BOOLEAN need_rsp; + UINT16 clt_cfg; +}tBA_WRITE_DATA; + +#define BA_READ_CLT_CFG_REQ 1 +#define BA_READ_PRE_FMT_REQ 2 +#define BA_READ_RPT_REF_REQ 3 +#define BA_READ_LEVEL_REQ 4 +#define BA_WRITE_CLT_CFG_REQ 5 + +typedef void (tBA_CBACK)(UINT32 trans_id, UINT16 conn_id, UINT8 app_id, UINT8 event, tBA_WRITE_DATA *p_data); + +#define BA_LEVEL_NOTIFY 0x01 +#define BA_LEVEL_PRE_FMT 0x02 +#define BA_LEVEL_RPT_REF 0x04 +typedef UINT8 tBA_LEVEL_DESCR; + +typedef struct +{ + BOOLEAN is_pri; + tBA_LEVEL_DESCR ba_level_descr; + tGATT_TRANSPORT transport; + tBA_CBACK *p_cback; + +}tBA_REG_INFO; + +typedef union +{ + UINT8 ba_level; + UINT16 clt_cfg; + tGATT_CHAR_RPT_REF rpt_ref; + tGATT_CHAR_PRES pres_fmt; +}tBA_RSP_DATA; + +typedef struct +{ + UINT8 app_id; + UINT16 ba_level_hdl; + UINT16 clt_cfg_hdl; + UINT16 rpt_ref_hdl; + UINT16 pres_fmt_hdl; + + tBA_CBACK *p_cback; + + UINT16 pending_handle; + //UINT8 pending_clcb_idx; + UINT8 pending_evt; +}tBA_INST; + +typedef struct +{ + tBA_INST battery_inst[BA_MAX_INT_NUM]; + UINT8 inst_id; + bool enabled; +}tBATTERY_CB; +/***************************************************************************** +** External Function Declarations +*****************************************************************************/ +#ifdef __cplusplus +extern "C" +{ +#endif +/***************************************************************************** +** Service Engine API +*****************************************************************************/ +/******************************************************************************* +** +** Function srvc_eng_init +** +** Description Initializa the GATT Service engine, register a GATT application +** as for a central service management. +** +*******************************************************************************/ +//extern tGATT_STATUS srvc_eng_init (void); + + +/***************************************************************************** +** DIS Server Function +*****************************************************************************/ + +extern bool dis_valid_handle_range(UINT16 handle); +/******************************************************************************* +** +** Function DIS_Init +** +** Description Initializa the Device Information Service Server. +** +*******************************************************************************/ +extern void DIS_Init (tBTA_GATTS_IF gatt_if, tDIS_ATTR_MASK dis_attr_mask); +/******************************************************************************* +** +** Function DIS_SrUpdate +** +** Description Update the DIS server attribute values +** +*******************************************************************************/ +extern tDIS_STATUS DIS_SrUpdate(tDIS_ATTR_BIT dis_attr_bit, tDIS_ATTR *p_info); +/******************************************************************************* +** +** Function dis_AddChar +** +** Description add characteristic for dis +** +*******************************************************************************/ +extern void dis_AddChar(UINT16 service_id); +/******************************************************************************* +** dis_s_read_attr_value +** +** Process read DIS attribute request. +*******************************************************************************/ + +extern void dis_s_read_attr_value (tGATTS_DATA *p_data, tGATT_VALUE *p_value, + UINT32 trans_id, UINT16 conn_id); +/***************************************************************************** +** DIS Client Function +*****************************************************************************/ +/******************************************************************************* +** +** Function DIS_ReadDISInfo +** +** Description Read remote device DIS information. +** +** Returns void +** +*******************************************************************************/ +//extern BOOLEAN DIS_ReadDISInfo(BD_ADDR peer_bda, tDIS_READ_CBACK *p_cback, + // tDIS_ATTR_MASK mask); + +/******************************************************************************* +** BATTERY SERVICE API +*******************************************************************************/ +/*************************************************************** +** +** Function bas_register +** +** Description register app for battery service +** +****************************************************************/ +extern void bas_register(void); +/*************************************************************** +** +** Function bas_init +** +** Description register battery service +** +****************************************************************/ +extern void bas_init(tBTA_GATTS_IF gatt_if, UINT16 app_id); + +/*************************************************************** +** +** Function bas_AddChar +** +** Description add characteristic for battery service +** +****************************************************************/ +extern void bas_AddChar(UINT16 service_id, tBT_UUID *char_uuid); +/*************************************************************** +** +** Function bas_AddCharDescr +** +** Description add descriptor for battery service if needed +** +****************************************************************/ +extern void bas_AddCharDescr(UINT16 service_id, UINT16 attr_id); +/*************************************************************** +** +** Function bas_service_cmpl +** +** Description create battery service complete +** +****************************************************************/ +extern void bas_service_cmpl(UINT16 service_id, tBTA_GATT_STATUS status); +/******************************************************************************* +** +** Function Battery_Rsp +** +** Description Respond to a battery service request +** +*******************************************************************************/ +extern void Battery_Rsp (UINT32 trans_id, UINT16 conn_id, UINT8 app_id, + tGATT_STATUS st, UINT8 event, tBA_RSP_DATA *p_rsp); +/******************************************************************************* +** +** Function Battery_Notify +** +** Description Send battery level notification +** +*******************************************************************************/ +extern void Battery_Notify (UINT16 conn_id, UINT8 app_id, BD_ADDR remote_bda, UINT8 battery_level); + +/***************************************************************************** +** Function bas_s_read_attr_value +** +** Description it will be called when client send a read request +******************************************************************************/ +extern void bas_s_read_attr_value(tGATTS_DATA *p_data, UINT32 trans_id, UINT16 conn_id); +/***************************************************************************** +** Function bas_s_write_attr_value +** +** Description it will be called when client send a write request +******************************************************************************/ +extern void bas_s_write_attr_value(tGATTS_DATA *p_data, UINT32 trans_id, + UINT16 conn_id, BD_ADDR bd_addr); + +extern void gatts_server_test(void); +#ifdef __cplusplus + +} +#endif + +#endif diff --git a/components/bt/bluedroid/profiles/include/hid_le_prf.h b/components/bt/bluedroid/profiles/include/hid_le_prf.h new file mode 100644 index 0000000000..ecdf105e2f --- /dev/null +++ b/components/bt/bluedroid/profiles/include/hid_le_prf.h @@ -0,0 +1,218 @@ +/** + **************************************************************************************** + * + * @file button_pro.c + * + * @brief Application entry point + * + * Copyright (C) Espressif 2016 + * Created by Yulong at 2016/9/7 + * + * + **************************************************************************************** + */ + + +#include "bta_gatts_int.h" + +#include "bta_api.h" +#include "gatt_api.h" + +/// Maximal number of HIDS that can be added in the DB +#ifndef USE_ONE_HIDS_INSTANCE +#define HIDD_LE_NB_HIDS_INST_MAX (2) +#else +#define HIDD_LE_NB_HIDS_INST_MAX (1) +#endif + +#define ATT_SVC_HID 0x1812 + +/// Maximal number of Report Char. that can be added in the DB for one HIDS - Up to 11 +#define HIDD_LE_NB_REPORT_INST_MAX (5) + +/// Maximal length of Report Char. Value +#define HIDD_LE_REPORT_MAX_LEN (45) +/// Maximal length of Report Map Char. Value +#define HIDD_LE_REPORT_MAP_MAX_LEN (512) + +/// Length of Boot Report Char. Value Maximal Length +#define HIDD_LE_BOOT_REPORT_MAX_LEN (8) + +/// Boot KB Input Report Notification Configuration Bit Mask +#define HIDD_LE_BOOT_KB_IN_NTF_CFG_MASK (0x40) +/// Boot KB Input Report Notification Configuration Bit Mask +#define HIDD_LE_BOOT_MOUSE_IN_NTF_CFG_MASK (0x80) +/// Boot Report Notification Configuration Bit Mask +#define HIDD_LE_REPORT_NTF_CFG_MASK (0x20) + + + + + +/// HID Service Attributes Indexes +enum +{ + HIDD_LE_IDX_SVC, + + // Included Service + HIDD_LE_IDX_INCL_SVC, + + // HID Information + HIDD_LE_IDX_HID_INFO_CHAR, + HIDD_LE_IDX_HID_INFO_VAL, + + // HID Control Point + HIDD_LE_IDX_HID_CTNL_PT_CHAR, + HIDD_LE_IDX_HID_CTNL_PT_VAL, + + // Report Map + HIDD_LE_IDX_REPORT_MAP_CHAR, + HIDD_LE_IDX_REPORT_MAP_VAL, + HIDD_LE_IDX_REPORT_MAP_EXT_REP_REF, + + // Protocol Mode + HIDD_LE_IDX_PROTO_MODE_CHAR, + HIDD_LE_IDX_PROTO_MODE_VAL, + + // Boot Keyboard Input Report + HIDD_LE_IDX_BOOT_KB_IN_REPORT_CHAR, + HIDD_LE_IDX_BOOT_KB_IN_REPORT_VAL, + HIDD_LE_IDX_BOOT_KB_IN_REPORT_NTF_CFG, + + // Boot Keyboard Output Report + HIDD_LE_IDX_BOOT_KB_OUT_REPORT_CHAR, + HIDD_LE_IDX_BOOT_KB_OUT_REPORT_VAL, + + // Boot Mouse Input Report + HIDD_LE_IDX_BOOT_MOUSE_IN_REPORT_CHAR, + HIDD_LE_IDX_BOOT_MOUSE_IN_REPORT_VAL, + HIDD_LE_IDX_BOOT_MOUSE_IN_REPORT_NTF_CFG, + + // Report + HIDD_LE_IDX_REPORT_CHAR, + HIDD_LE_IDX_REPORT_VAL, + HIDD_LE_IDX_REPORT_REP_REF, + HIDD_LE_IDX_REPORT_NTF_CFG, + + HIDD_LE_IDX_NB, +}; + + +/// Attribute Table Indexes +enum +{ + HIDD_LE_INFO_CHAR, + HIDD_LE_CTNL_PT_CHAR, + HIDD_LE_REPORT_MAP_CHAR, + HIDD_LE_PROTO_MODE_CHAR, + HIDD_LE_BOOT_KB_IN_REPORT_CHAR, + HIDD_LE_BOOT_KB_OUT_REPORT_CHAR, + HIDD_LE_BOOT_MOUSE_IN_REPORT_CHAR, + HIDD_LE_REPORT_CHAR, + + HIDD_LE_CHAR_MAX //= HIDD_LE_REPORT_CHAR + HIDD_LE_NB_REPORT_INST_MAX, +}; + +/// Client Characteristic Configuration Codes +enum +{ + HIDD_LE_DESC_MASK = 0x10, + + HIDD_LE_BOOT_KB_IN_REPORT_CFG = HIDD_LE_BOOT_KB_IN_REPORT_CHAR | HIDD_LE_DESC_MASK, + HIDD_LE_BOOT_MOUSE_IN_REPORT_CFG = HIDD_LE_BOOT_MOUSE_IN_REPORT_CHAR | HIDD_LE_DESC_MASK, + HIDD_LE_REPORT_CFG = HIDD_LE_REPORT_CHAR | HIDD_LE_DESC_MASK, +}; + +/// Features Flag Values +enum +{ + HIDD_LE_CFG_KEYBOARD = 0x01, + HIDD_LE_CFG_MOUSE = 0x02, + HIDD_LE_CFG_PROTO_MODE = 0x04, + HIDD_LE_CFG_MAP_EXT_REF = 0x08, + HIDD_LE_CFG_BOOT_KB_WR = 0x10, + HIDD_LE_CFG_BOOT_MOUSE_WR = 0x20, +}; + +/// Report Char. Configuration Flag Values +enum +{ + HIDD_LE_CFG_REPORT_IN = 0x01, + HIDD_LE_CFG_REPORT_OUT = 0x02, + //HOGPD_CFG_REPORT_FEAT can be used as a mask to check Report type + HIDD_LE_CFG_REPORT_FEAT = 0x03, + HIDD_LE_CFG_REPORT_WR = 0x10, +}; + +/// Pointer to the connection clean-up function +#define HIDD_LE_CLEANUP_FNCT (NULL) + +/* + * TYPE DEFINITIONS + **************************************************************************************** + */ + + /// HIDD Features structure + typedef struct + { + /// Service Features + UINT8 svc_features; + /// Number of Report Char. instances to add in the database + UINT8 report_nb; + /// Report Char. Configuration + UINT8 report_char_cfg[HIDD_LE_NB_REPORT_INST_MAX]; + }tHIDD_FEATURE; + + + typedef struct + { + BOOLEAN in_use; + BOOLEAN congest; + UINT16 conn_id; + BOOLEAN connected; + BD_ADDR remote_bda; + UINT32 trans_id; + UINT8 cur_srvc_id; + + }tHIDD_CLCB; + + + typedef struct + { + /// hidd profile id + UINT8 app_id; + /// Notified handle + uint16_t ntf_handle; + ///Attribute Table + uint8_t att_tbl[HIDD_LE_NB_HIDS_INST_MAX][HIDD_LE_CHAR_MAX]; + /// Supported Features + tHIDD_FEATURE hidd_feature[HIDD_LE_NB_HIDS_INST_MAX]; + /// Current Protocol Mode + UINT8 proto_mode[HIDD_LE_NB_HIDS_INST_MAX]; + /// Number of HIDS added in the database + UINT8 hids_nb; + + }tHIDD_INST; + + + /* service engine control block */ + typedef struct + { + tHIDD_CLCB hidd_clcb; /* connection link*/ + tGATT_IF gatt_if; + BOOLEAN enabled; + BOOLEAN is_primery; + tHIDD_INST hidd_inst; + UINT8 inst_id; + }tHIDD_LE_ENV; + + extern tHIDD_LE_ENV hidd_le_env; + + + void hidd_le_CreateService(BOOLEAN is_primary); + + + tGATT_STATUS hidd_le_init (void); + + + diff --git a/components/bt/bluedroid/profiles/include/prf_defs.h b/components/bt/bluedroid/profiles/include/prf_defs.h new file mode 100644 index 0000000000..8d5c686990 --- /dev/null +++ b/components/bt/bluedroid/profiles/include/prf_defs.h @@ -0,0 +1,630 @@ +/** + **************************************************************************************** + * + * @file prf_defs.h + * + * @brief Application entry point + * + * Copyright (C) Espressif 2016 + * Created by Yulong at 2016/9/8 + * + * + **************************************************************************************** + */ + +#include "bta_api.h" +#include "bta_gattc_int.h" +#include "bta_gatts_int.h" +#include "bta_gatt_api.h" +#include "bt_types.h" + + +#define ATT_HANDLE_LEN 0x0002 +#define ATT_UUID_16_LEN 0x0002 +#define ATT_UUID_128_LEN 0x0010 +#define ATT_UUID_32_LEN 0x0004 + + +/* + * Type Definition + **************************************************************************************** + */ + +/// Characteristic Value Descriptor +typedef struct +{ + ///characteristic uuid + tBT_UUID *char_uuid; + ///the permition of the characteristic + tBTA_GATT_PERM perm; + /// the properties of the characteristic + tBTA_GATT_CHAR_PROP prop; +}tCHAR_DESC; + +/// UUID - 128-bit type +typedef struct +{ + /// 128-bit UUID + UINT8 uuid[ATT_UUID_128_LEN]; +}tUUID_128; + +/// UUID - 32-bit type +typedef struct +{ + /// 32-bit UUID + UINT8 uuid[ATT_UUID_32_LEN]; +}tUUID_32; + +/// include service entry element +typedef struct +{ + /// start handle value of included service + UINT16 start_hdl; + /// end handle value of included service + UINT16 end_hdl; + /// attribute value UUID + UINT16 uuid; +}tSVC_INCL_DESC; + +/// Service Changed type definition +typedef struct +{ + /// Service start handle which changed + UINT16 start_hdl; + /// Service end handle which changed + UINT16 end_hdl; +}tSVC_CHANG; + + + +/// Common 16-bit Universal Unique Identifier +enum { + ATT_INVALID_UUID = 0, + /*----------------- SERVICES ---------------------*/ + /// Generic Access Profile + SVC_GENERIC_ACCESS_UUID = 0x1800, + /// Attribute Profile + SVC_GENERIC_ATTRIBUTE_UUID, + /// Immediate alert Service + SVC_IMMEDIATE_ALERT_UUID, + /// Link Loss Service + SVC_LINK_LOSS_UUID, + /// Tx Power Service + SVC_TX_POWER_UUID, + /// Current Time Service Service + SVC_CURRENT_TIME_UUID, + /// Reference Time Update Service + SVC_REF_TIME_UPDATE_UUID, + /// Next DST Change Service + SVC_NEXT_DST_CHANGE_UUID, + /// Glucose Service + SVC_GLUCOSE_UUID = 0x1808, + /// Health Thermometer Service + SVC_HEALTH_THERMOM_UUID = 0x1809, + /// Device Information Service + SVC_DEVICE_INFO_UUID = 0x180A, + /// Heart Rate Service + SVC_HEART_RATE_UUID = 0x180D, + /// Phone Alert Status Service + SVC_PHONE_ALERT_STATUS_UUID, + /// Battery Service + SVC_BATTERY_SERVICE_UUID, + /// Blood Pressure Service + SVC_BLOOD_PRESSURE_UUID = 0x1810, + /// Alert Notification Service + SVC_ALERT_NTF_UUID = 0x1811, + /// HID Service + SVC_HID_UUID = 0x1812, + /// Scan Parameters Service + SVC_SCAN_PARAMETERS_UUID = 0x1813, + /// Running Speed and Cadence Service + SVC_RUNNING_SPEED_CADENCE_UUID = 0x1814, + /// Cycling Speed and Cadence Service + SVC_CYCLING_SPEED_CADENCE_UUID = 0x1816, + /// Cycling Power Service + SVC_CYCLING_POWER_UUID = 0x1818, + /// Location and Navigation Service + SVC_LOCATION_AND_NAVIGATION_UUID = 0x1819, + /// User Data Service + SVC_USER_DATA_UUID = 0x181C, + /// Weight Scale Service + SVC_WEIGHT_SCALE_UUID = 0x181D, + + /*------------------- UNITS ---------------------*/ + /// No defined unit + UNIT_UNITLESS_UUID = 0x2700, + /// Length Unit - Metre + UNIT_METRE_UUID, + //Mass unit - Kilogram + UNIT_KG_UUID, + ///Time unit - second + UNIT_SECOND_UUID, + ///Electric current unit - Ampere + UNIT_AMPERE_UUID, + ///Thermodynamic Temperature unit - Kelvin + UNIT_KELVIN_UUID, + /// Amount of substance unit - mole + UNIT_MOLE_UUID, + ///Luminous intensity unit - candela + UNIT_CANDELA_UUID, + ///Area unit - square metres + UNIT_SQ_METRE_UUID = 0x2710, + ///Colume unit - cubic metres + UNIT_CUBIC_METRE_UUID, + ///Velocity unit - metres per second + UNIT_METRE_PER_SECOND_UUID, + ///Acceleration unit - metres per second squared + UNIT_METRES_PER_SEC_SQ_UUID, + ///Wavenumber unit - reciprocal metre + UNIT_RECIPROCAL_METRE_UUID, + ///Density unit - kilogram per cubic metre + UNIT_DENS_KG_PER_CUBIC_METRE_UUID, + ///Surface density unit - kilogram per square metre + UNIT_KG_PER_SQ_METRE_UUID, + ///Specific volume unit - cubic metre per kilogram + UNIT_CUBIC_METRE_PER_KG_UUID, + ///Current density unit - ampere per square metre + UNIT_AMPERE_PER_SQ_METRE_UUID, + ///Magnetic field strength unit - Ampere per metre + UNIT_AMPERE_PER_METRE_UUID, + ///Amount concentration unit - mole per cubic metre + UNIT_MOLE_PER_CUBIC_METRE_UUID, + ///Mass Concentration unit - kilogram per cubic metre + UNIT_MASS_KG_PER_CUBIC_METRE_UUID, + ///Luminance unit - candela per square metre + UNIT_CANDELA_PER_SQ_METRE_UUID, + ///Refractive index unit + UNIT_REFRACTIVE_INDEX_UUID, + ///Relative permeability unit + UNIT_RELATIVE_PERMEABILITY_UUID, + ///Plane angle unit - radian + UNIT_RADIAN_UUID = 0x2720, + ///Solid angle unit - steradian + UNIT_STERADIAN_UUID, + ///Frequency unit - Hertz + UNIT_HERTZ_UUID, + ///Force unit - Newton + UNIT_NEWTON_UUID, + ///Pressure unit - Pascal + UNIT_PASCAL_UUID, + ///Energy unit - Joule + UNIT_JOULE_UUID, + ///Power unit - Watt + UNIT_WATT_UUID, + ///electric Charge unit - Coulomb + UNIT_COULOMB_UUID, + ///Electric potential difference - Volt + UNIT_VOLT_UUID, + ///Capacitance unit - Farad + UNIT_FARAD_UUID, + ///electric resistance unit - Ohm + UNIT_OHM_UUID, + ///Electric conductance - Siemens + UNIT_SIEMENS_UUID, + ///Magnetic flux unit - Weber + UNIT_WEBER_UUID, + ///Magnetic flux density unit - Tesla + UNIT_TESLA_UUID, + ///Inductance unit - Henry + UNIT_HENRY_UUID, + ///Temperature unit - degree Celsius + UNIT_CELSIUS_UUID, + ///Luminous flux unit - lumen + UNIT_LUMEN_UUID, + //Illuminance unit - lux + UNIT_LUX_UUID, + ///Activity referred to a radionuclide unit - becquerel + UNIT_BECQUEREL_UUID, + ///Absorbed dose unit - Gray + UNIT_GRAY_UUID, + ///Dose equivalent unit - Sievert + UNIT_SIEVERT_UUID, + ///Catalytic activity unit - Katal + UNIT_KATAL_UUID, + ///Synamic viscosity unit - Pascal second + UNIT_PASCAL_SECOND_UUID = 0x2740, + ///Moment of force unit - Newton metre + UNIT_NEWTON_METRE_UUID, + ///surface tension unit - Newton per metre + UNIT_NEWTON_PER_METRE_UUID, + ///Angular velocity unit - radian per second + UNIT_RADIAN_PER_SECOND_UUID, + ///Angular acceleration unit - radian per second squared + UNIT_RADIAN_PER_SECOND_SQ_UUID, + ///Heat flux density unit - Watt per square metre + UNIT_WATT_PER_SQ_METRE_UUID, + ///HEat capacity unit - Joule per Kelvin + UNIT_JOULE_PER_KELVIN_UUID, + ///Specific heat capacity unit - Joule per kilogram kelvin + UNIT_JOULE_PER_KG_KELVIN_UUID, + ///Specific Energy unit - Joule per kilogram + UNIT_JOULE_PER_KG_UUID, + ///Thermal conductivity - Watt per metre Kelvin + UNIT_WATT_PER_METRE_KELVIN_UUID, + ///Energy Density unit - joule per cubic metre + UNIT_JOULE_PER_CUBIC_METRE_UUID, + ///Electric field strength unit - volt per metre + UNIT_VOLT_PER_METRE_UUID, + ///Electric charge density unit - coulomb per cubic metre + UNIT_COULOMB_PER_CUBIC_METRE_UUID, + ///Surface charge density unit - coulomb per square metre + UNIT_SURF_COULOMB_PER_SQ_METRE_UUID, + ///Electric flux density unit - coulomb per square metre + UNIT_FLUX_COULOMB_PER_SQ_METRE_UUID, + ///Permittivity unit - farad per metre + UNIT_FARAD_PER_METRE_UUID, + ///Permeability unit - henry per metre + UNIT_HENRY_PER_METRE_UUID, + ///Molar energy unit - joule per mole + UNIT_JOULE_PER_MOLE_UUID, + ///Molar entropy unit - joule per mole kelvin + UNIT_JOULE_PER_MOLE_KELVIN_UUID, + ///Exposure unit - coulomb per kilogram + UNIT_COULOMB_PER_KG_UUID, + ///Absorbed dose rate unit - gray per second + UNIT_GRAY_PER_SECOND_UUID, + ///Radiant intensity unit - watt per steradian + UNIT_WATT_PER_STERADIAN_UUID, + ///Radiance unit - watt per square meter steradian + UNIT_WATT_PER_SQ_METRE_STERADIAN_UUID, + ///Catalytic activity concentration unit - katal per cubic metre + UNIT_KATAL_PER_CUBIC_METRE_UUID, + ///Time unit - minute + UNIT_MINUTE_UUID = 0x2760, + ///Time unit - hour + UNIT_HOUR_UUID, + ///Time unit - day + UNIT_DAY_UUID, + ///Plane angle unit - degree + UNIT_ANGLE_DEGREE_UUID, + ///Plane angle unit - minute + UNIT_ANGLE_MINUTE_UUID, + ///Plane angle unit - second + UNIT_ANGLE_SECOND_UUID, + ///Area unit - hectare + UNIT_HECTARE_UUID, + ///Volume unit - litre + UNIT_LITRE_UUID, + ///Mass unit - tonne + UNIT_TONNE_UUID, + ///Pressure unit - bar + UNIT_BAR_UUID = 0x2780, + ///Pressure unit - millimetre of mercury + UNIT_MM_MERCURY_UUID, + ///Length unit - angstrom + UNIT_ANGSTROM_UUID, + ///Length unit - nautical mile + UNIT_NAUTICAL_MILE_UUID, + ///Area unit - barn + UNIT_BARN_UUID, + ///Velocity unit - knot + UNIT_KNOT_UUID, + ///Logarithmic radio quantity unit - neper + UNIT_NEPER_UUID, + ///Logarithmic radio quantity unit - bel + UNIT_BEL_UUID, + ///Length unit - yard + UNIT_YARD_UUID = 0x27A0, + ///Length unit - parsec + UNIT_PARSEC_UUID, + ///length unit - inch + UNIT_INCH_UUID, + ///length unit - foot + UNIT_FOOT_UUID, + ///length unit - mile + UNIT_MILE_UUID, + ///pressure unit - pound-force per square inch + UNIT_POUND_FORCE_PER_SQ_INCH_UUID, + ///velocity unit - kilometre per hour + UNIT_KM_PER_HOUR_UUID, + ///velocity unit - mile per hour + UNIT_MILE_PER_HOUR_UUID, + ///angular velocity unit - revolution per minute + UNIT_REVOLUTION_PER_MINUTE_UUID, + ///energy unit - gram calorie + UNIT_GRAM_CALORIE_UUID, + ///energy unit - kilogram calorie + UNIT_KG_CALORIE_UUID, + /// energy unit - kilowatt hour + UNIT_KILOWATT_HOUR_UUID, + ///thermodynamic temperature unit - degree Fahrenheit + UNIT_FAHRENHEIT_UUID, + ///percentage + UNIT_PERCENTAGE_UUID, + ///per mille + UNIT_PER_MILLE_UUID, + ///period unit - beats per minute) + UNIT_BEATS_PER_MINUTE_UUID, + ///electric charge unit - ampere hours + UNIT_AMPERE_HOURS_UUID, + ///mass density unit - milligram per decilitre + UNIT_MILLIGRAM_PER_DECILITRE_UUID, + ///mass density unit - millimole per litre + UNIT_MILLIMOLE_PER_LITRE_UUID, + ///time unit - year + UNIT_YEAR_UUID, + ////time unit - month + UNIT_MONTH_UUID, + + + /*---------------- DECLARATIONS -----------------*/ + /// Primary service Declaration + DECL_PRIMARY_SERVICE_UUID = 0x2800, + /// Secondary service Declaration + DECL_SECONDARY_SERVICE_UUID, + /// Include Declaration + DECL_INCLUDE_UUID, + /// Characteristic Declaration + DECL_CHARACTERISTIC_UUID, + + + /*----------------- DESCRIPTORS -----------------*/ + /// Characteristic extended properties + DESC_CHAR_EXT_PROPERTIES_UUID = 0x2900, + /// Characteristic user description + DESC_CHAR_USER_DESCRIPTION_UUID, + /// Client characteristic configuration + DESC_CLIENT_CHAR_CFG_UUID, + /// Server characteristic configuration + DESC_SERVER_CHAR_CFG_UUID, + /// Characteristic Presentation Format + DESC_CHAR_PRES_FORMAT_UUID, + /// Characteristic Aggregate Format + DESC_CHAR_AGGREGATE_FORMAT_UUID, + /// Valid Range + DESC_VALID_RANGE_UUID, + /// External Report Reference + DESC_EXT_REPORT_REF_UUID, + /// Report Reference + DESC_REPORT_REF_UUID, + + + /*--------------- CHARACTERISTICS ---------------*/ + /// Device name + CHAR_DEVICE_NAME_UUID = 0x2A00, + /// Appearance + CHAR_APPEARANCE_UUID = 0x2A01, + /// Privacy flag + CHAR_PRIVACY_FLAG_UUID = 0x2A02, + /// Reconnection address + CHAR_RECONNECTION_ADDR_UUID = 0x2A03, + /// Peripheral preferred connection parameters + CHAR_PERIPH_PREF_CON_PARAM_UUID = 0x2A04, + /// Service handles changed + CHAR_SERVICE_CHANGED_UUID = 0x2A05, + /// Alert Level characteristic + CHAR_ALERT_LEVEL_UUID = 0x2A06, + /// Tx Power Level + CHAR_TX_POWER_LEVEL_UUID = 0x2A07, + /// Date Time + CHAR_DATE_TIME_UUID = 0x2A08, + /// Day of Week + CHAR_DAY_WEEK_UUID = 0x2A09, + /// Day Date Time + CHAR_DAY_DATE_TIME_UUID = 0x2A0A, + /// Exact time 256 + CHAR_EXACT_TIME_256_UUID = 0x2A0C, + /// DST Offset + CHAR_DST_OFFSET_UUID = 0x2A0D, + /// Time zone + CHAR_TIME_ZONE_UUID = 0x2A0E, + /// Local time Information + CHAR_LOCAL_TIME_INFO_UUID = 0x2A0F, + /// Time with DST + CHAR_TIME_WITH_DST_UUID = 0x2A11, + /// Time Accuracy + CHAR_TIME_ACCURACY_UUID = 0x2A12, + ///Time Source + CHAR_TIME_SOURCE_UUID = 0x2A13, + /// Reference Time Information + CHAR_REFERENCE_TIME_INFO_UUID = 0x2A14, + /// Time Update Control Point + CHAR_TIME_UPDATE_CNTL_POINT_UUID = 0x2A16, + /// Time Update State + CHAR_TIME_UPDATE_STATE_UUID = 0x2A17, + /// Glucose Measurement + CHAR_GLUCOSE_MEAS_UUID = 0x2A18, + /// Battery Level + CHAR_BATTERY_LEVEL_UUID = 0x2A19, + /// Temperature Measurement + CHAR_TEMPERATURE_MEAS_UUID = 0x2A1C, + /// Temperature Type + CHAR_TEMPERATURE_TYPE_UUID = 0x2A1D, + /// Intermediate Temperature + CHAR_INTERMED_TEMPERATURE_UUID = 0x2A1E, + /// Measurement Interval + CHAR_MEAS_INTERVAL_UUID = 0x2A21, + /// Boot Keyboard Input Report + CHAR_BOOT_KB_IN_REPORT_UUID = 0x2A22, + /// System ID + CHAR_SYS_ID_UUID = 0x2A23, + /// Model Number String + CHAR_MODEL_NB_UUID = 0x2A24, + /// Serial Number String + CHAR_SERIAL_NB_UUID = 0x2A25, + /// Firmware Revision String + CHAR_FW_REV_UUID = 0x2A26, + /// Hardware revision String + CHAR_HW_REV_UUID = 0x2A27, + /// Software Revision String + CHAR_SW_REV_UUID = 0x2A28, + /// Manufacturer Name String + CHAR_MANUF_NAME_UUID = 0x2A29, + /// IEEE Regulatory Certification Data List + CHAR_IEEE_CERTIF_UUID = 0x2A2A, + /// CT Time + CHAR_CT_TIME_UUID = 0x2A2B, + /// Scan Refresh + CHAR_SCAN_REFRESH_UUID = 0x2A31, + /// Boot Keyboard Output Report + CHAR_BOOT_KB_OUT_REPORT_UUID = 0x2A32, + /// Boot Mouse Input Report + CHAR_BOOT_MOUSE_IN_REPORT_UUID = 0x2A33, + /// Glucose Measurement Context + CHAR_GLUCOSE_MEAS_CTX_UUID = 0x2A34, + /// Blood Pressure Measurement + CHAR_BLOOD_PRESSURE_MEAS_UUID = 0x2A35, + /// Intermediate Cuff Pressure + CHAR_INTERMEDIATE_CUFF_PRESSURE_UUID = 0x2A36, + /// Heart Rate Measurement + CHAR_HEART_RATE_MEAS_UUID = 0x2A37, + /// Body Sensor Location + CHAR_BODY_SENSOR_LOCATION_UUID = 0x2A38, + /// Heart Rate Control Point + CHAR_HEART_RATE_CNTL_POINT_UUID = 0x2A39, + /// Alert Status + CHAR_ALERT_STATUS_UUID = 0x2A3F, + /// Ringer Control Point + CHAR_RINGER_CNTL_POINT_UUID = 0x2A40, + /// Ringer Setting + CHAR_RINGER_SETTING_UUID = 0x2A41, + /// Alert Category ID Bit Mask + CHAR_ALERT_CAT_ID_BIT_MASK_UUID = 0x2A42, + /// Alert Category ID + CHAR_ALERT_CAT_ID_UUID = 0x2A43, + /// Alert Notification Control Point + CHAR_ALERT_NTF_CTNL_PT_UUID = 0x2A44, + /// Unread Alert Status + CHAR_UNREAD_ALERT_STATUS_UUID = 0x2A45, + /// New Alert + CHAR_NEW_ALERT_UUID = 0x2A46, + /// Supported New Alert Category + CHAR_SUP_NEW_ALERT_CAT_UUID = 0x2A47, + /// Supported Unread Alert Category + CHAR_SUP_UNREAD_ALERT_CAT_UUID = 0x2A48, + /// Blood Pressure Feature + CHAR_BLOOD_PRESSURE_FEATURE_UUID = 0x2A49, + /// HID Information + CHAR_HID_INFO_UUID = 0x2A4A, + /// Report Map + CHAR_REPORT_MAP_UUID = 0x2A4B, + /// HID Control Point + CHAR_HID_CTNL_PT_UUID = 0x2A4C, + /// Report + CHAR_REPORT_UUID = 0x2A4D, + /// Protocol Mode + CHAR_PROTOCOL_MODE_UUID = 0x2A4E, + /// Scan Interval Window + CHAR_SCAN_INTV_WD_UUID = 0x2A4F, + /// PnP ID + CHAR_PNP_ID_UUID = 0x2A50, + /// Glucose Feature + CHAR_GLUCOSE_FEATURE_UUID = 0x2A51, + /// Record access control point + CHAR_REC_ACCESS_CTRL_PT_UUID = 0x2A52, + /// RSC Measurement + CHAR_RSC_MEAS_UUID = 0x2A53, + /// RSC Feature + CHAR_RSC_FEAT_UUID = 0x2A54, + /// SC Control Point + CHAR_SC_CNTL_PT_UUID = 0x2A55, + /// CSC Measurement + CHAR_CSC_MEAS_UUID = 0x2A5B, + /// CSC Feature + CHAR_CSC_FEAT_UUID = 0x2A5C, + /// Sensor Location + CHAR_SENSOR_LOC_UUID = 0x2A5D, + /// CP Measurement + CHAR_CP_MEAS_UUID = 0x2A63, + /// CP Vector + CHAR_CP_VECTOR_UUID = 0x2A64, + /// CP Feature + CHAR_CP_FEAT_UUID = 0x2A65, + /// CP Control Point + CHAR_CP_CNTL_PT_UUID = 0x2A66, + /// Location and Speed + CHAR_LOC_SPEED_UUID = 0x2A67, + /// Navigation + CHAR_NAVIGATION_UUID = 0x2A68, + /// Position Quality + CHAR_POS_QUALITY_UUID = 0x2A69, + /// LN Feature + CHAR_LN_FEAT_UUID = 0x2A6A, + /// LN Control Point + CHAR_LN_CNTL_PT_UUID = 0x2A6B, + + /// Weight Scale Feature + CHAR_WS_FEAT_UUID = 0x2A9E, + /// Weight Scale Measurement + CHAR_WS_MEAS_UUID = 0x2A9D, + /// User height + CHAR_UDS_USER_HEIGHT_UUID = 0x2A8E, + /// User age + CHAR_UDS_USER_AGE_UUID = 0x2A80, + /// User date of birth + CHAR_UDS_USER_DATE_OF_BIRTH_UUID = 0x2A85, + /// User database change increment + CHAR_UDS_USER_DB_CHANGE_INCR_UUID = 0x2A99, + /// User Data Index + CHAR_UDS_USER_DATA_INDEX_UUID = 0x2A9A, + /// User Data Control Point + CHAR_UDS_USER_CTRL_PT_UUID = 0x2A9F, + /// Central Address Resolution + CHAR_CENT_ADDR_RES_UUID = 0x2AA6, + /// Last define + LAST +}; + +/// Format for Characteristic Presentation +enum { + /// unsigned 1-bit: true or false + FORMAT_BOOL_UUID = 0x01, + /// unsigned 2-bit integer + FORMAT_2BIT_UUID, + /// unsigned 4-bit integer + FORMAT_NIBBLE_UUID, + /// unsigned 8-bit integer + FORMAT_UINT8_UUID, + /// unsigned 12-bit integer + FORMAT_UINT12_UUID, + /// unsigned 16-bit integer + FORMAT_UINT16_UUID, + /// unsigned 24-bit integer + FORMAT_UINT24_UUID, + /// unsigned 32-bit integer + FORMAT_UINT32_UUID, + /// unsigned 48-bit integer + FORMAT_UINT48_UUID, + /// unsigned 64-bit integer + FORMAT_UINT64_UUID, + /// unsigned 128-bit integer + FORMAT_UINT128_UUID, + /// signed 8-bit integer + FORMAT_SINT8_UUID, + /// signed 12-bit integer + FORMAT_SINT12_UUID, + /// signed 16-bit integer + FORMAT_SINT16_UUID, + /// signed 24-bit integer + FORMAT_SINT24_UUID, + /// signed 32-bit integer + FORMAT_SINT32_UUID, + /// signed 48-bit integer + FORMAT_SINT48_UUID, + /// signed 64-bit integer + FORMAT_SINT64_UUID, + /// signed 128-bit integer + FORMAT_SINT128_UUID, + /// IEEE-754 32-bit floating point + FORMAT_FLOAT32_UUID, + /// IEEE-754 64-bit floating point + FORMAT_FLOAT64_UUID, + /// IEEE-11073 16-bit SFLOAT + FORMAT_SFLOAT_UUID, + /// IEEE-11073 32-bit FLOAT + FORMAT_FLOAT_UUID, + /// IEEE-20601 format + FORMAT_DUINT16_UUID, + /// UTF-8 string + FORMAT_UTF8S_UUID, + /// UTF-16 string + FORMAT_UTF16S_UUID, + /// Opaque structure + FORMAT_STRUCT_UUID, + /// Last format + FORMAT_LAST_UUID +}; + + + + diff --git a/components/bt/bluedroid/profiles/include/srvc_api.h b/components/bt/bluedroid/profiles/include/srvc_api.h new file mode 100644 index 0000000000..09c5b3e4b9 --- /dev/null +++ b/components/bt/bluedroid/profiles/include/srvc_api.h @@ -0,0 +1,217 @@ +/****************************************************************************** + * + * Copyright (C) 1999-2013 Broadcom Corporation + * + * 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. + * + ******************************************************************************/ + +#ifndef SRVC_DIS_API_H +#define SRVC_DIS_API_H + +#include "bt_target.h" +#include "gatt_api.h" +#include "gattdefs.h" + +#define DIS_SUCCESS GATT_SUCCESS +#define DIS_ILLEGAL_PARAM GATT_ILLEGAL_PARAMETER +#define DIS_NO_RESOURCES GATT_NO_RESOURCES +typedef UINT8 tDIS_STATUS; + + +/***************************************************************************** +** Data structure for DIS +*****************************************************************************/ + +#define DIS_ATTR_SYS_ID_BIT 0x0001 +#define DIS_ATTR_MODEL_NUM_BIT 0x0002 +#define DIS_ATTR_SERIAL_NUM_BIT 0x0004 +#define DIS_ATTR_FW_NUM_BIT 0x0008 +#define DIS_ATTR_HW_NUM_BIT 0x0010 +#define DIS_ATTR_SW_NUM_BIT 0x0020 +#define DIS_ATTR_MANU_NAME_BIT 0x0040 +#define DIS_ATTR_IEEE_DATA_BIT 0x0080 +#define DIS_ATTR_PNP_ID_BIT 0x0100 +typedef UINT16 tDIS_ATTR_MASK; + +#define DIS_ATTR_ALL_MASK 0xffff + +typedef tDIS_ATTR_MASK tDIS_ATTR_BIT ; + +typedef struct +{ + UINT16 len; + UINT8 *p_data; +}tDIS_STRING; + +typedef struct +{ + UINT16 vendor_id; + UINT16 product_id; + UINT16 product_version; + UINT8 vendor_id_src; + +}tDIS_PNP_ID; + +typedef union +{ + UINT64 system_id; + tDIS_PNP_ID pnp_id; + tDIS_STRING data_str; +}tDIS_ATTR; + +#define DIS_MAX_STRING_DATA 7 + +typedef struct +{ + UINT16 attr_mask; + UINT64 system_id; + tDIS_PNP_ID pnp_id; + UINT8 *data_string[DIS_MAX_STRING_DATA]; +}tDIS_VALUE; + + +typedef void (tDIS_READ_CBACK)(BD_ADDR addr, tDIS_VALUE *p_dis_value); + +/***************************************************************************** +** Data structure used by Battery Service +*****************************************************************************/ +typedef struct +{ + BD_ADDR remote_bda; + BOOLEAN need_rsp; + UINT16 clt_cfg; +}tBA_WRITE_DATA; + +#define BA_READ_CLT_CFG_REQ 1 +#define BA_READ_PRE_FMT_REQ 2 +#define BA_READ_RPT_REF_REQ 3 +#define BA_READ_LEVEL_REQ 4 +#define BA_WRITE_CLT_CFG_REQ 5 + +typedef void (tBA_CBACK)(UINT8 app_id, UINT8 event, tBA_WRITE_DATA *p_data); + +#define BA_LEVEL_NOTIFY 0x01 +#define BA_LEVEL_PRE_FMT 0x02 +#define BA_LEVEL_RPT_REF 0x04 +typedef UINT8 tBA_LEVEL_DESCR; + +typedef struct +{ + BOOLEAN is_pri; + tBA_LEVEL_DESCR ba_level_descr; + tGATT_TRANSPORT transport; + tBA_CBACK *p_cback; + +}tBA_REG_INFO; + +typedef union +{ + UINT8 ba_level; + UINT16 clt_cfg; + tGATT_CHAR_RPT_REF rpt_ref; + tGATT_CHAR_PRES pres_fmt; +}tBA_RSP_DATA; + +/***************************************************************************** +** External Function Declarations +*****************************************************************************/ +#ifdef __cplusplus +extern "C" +{ +#endif +/***************************************************************************** +** Service Engine API +*****************************************************************************/ +/******************************************************************************* +** +** Function srvc_eng_init +** +** Description Initializa the GATT Service engine, register a GATT application +** as for a central service management. +** +*******************************************************************************/ +extern tGATT_STATUS srvc_eng_init (void); + + +/***************************************************************************** +** DIS Server Function +*****************************************************************************/ + +/******************************************************************************* +** +** Function DIS_SrInit +** +** Description Initializa the Device Information Service Server. +** +*******************************************************************************/ +extern tDIS_STATUS DIS_SrInit (tDIS_ATTR_MASK dis_attr_mask); +/******************************************************************************* +** +** Function DIS_SrUpdate +** +** Description Update the DIS server attribute values +** +*******************************************************************************/ +extern tDIS_STATUS DIS_SrUpdate(tDIS_ATTR_BIT dis_attr_bit, tDIS_ATTR *p_info); +/***************************************************************************** +** DIS Client Function +*****************************************************************************/ +/******************************************************************************* +** +** Function DIS_ReadDISInfo +** +** Description Read remote device DIS information. +** +** Returns void +** +*******************************************************************************/ +extern BOOLEAN DIS_ReadDISInfo(BD_ADDR peer_bda, tDIS_READ_CBACK *p_cback, + tDIS_ATTR_MASK mask); + +/******************************************************************************* +** BATTERY SERVICE API +*******************************************************************************/ +/******************************************************************************* +** +** Function Battery_Instantiate +** +** Description Instantiate a Battery service +** +*******************************************************************************/ +extern UINT16 Battery_Instantiate (UINT8 app_id, tBA_REG_INFO *p_reg_info); + +/******************************************************************************* +** +** Function Battery_Rsp +** +** Description Respond to a battery service request +** +*******************************************************************************/ +extern void Battery_Rsp (UINT8 app_id, tGATT_STATUS st, UINT8 event, tBA_RSP_DATA *p_rsp); +/******************************************************************************* +** +** Function Battery_Notify +** +** Description Send battery level notification +** +*******************************************************************************/ +extern void Battery_Notify (UINT8 app_id, BD_ADDR remote_bda, UINT8 battery_level); + + +#ifdef __cplusplus + +} +#endif + +#endif diff --git a/components/bt/bluedroid/profiles/include/srvc_battery_int.h b/components/bt/bluedroid/profiles/include/srvc_battery_int.h new file mode 100644 index 0000000000..a9f81ae2e0 --- /dev/null +++ b/components/bt/bluedroid/profiles/include/srvc_battery_int.h @@ -0,0 +1,81 @@ +/****************************************************************************** + * + * Copyright (C) 1999-2012 Broadcom Corporation + * + * 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. + * + ******************************************************************************/ + +#ifndef SRVC_BATTERY_INT_H +#define SRVC_BATTERY_INT_H + +#include "bt_target.h" +#include "srvc_api.h" +#include "gatt_api.h" + +#ifndef BA_MAX_INT_NUM +#define BA_MAX_INT_NUM 4 +#endif + +#define BATTERY_LEVEL_SIZE 1 + + +typedef struct +{ + UINT8 app_id; + UINT16 ba_level_hdl; + UINT16 clt_cfg_hdl; + UINT16 rpt_ref_hdl; + UINT16 pres_fmt_hdl; + + tBA_CBACK *p_cback; + + UINT16 pending_handle; + UINT8 pending_clcb_idx; + UINT8 pending_evt; + +}tBA_INST; + +typedef struct +{ + tBA_INST battery_inst[BA_MAX_INT_NUM]; + UINT8 inst_id; + BOOLEAN enabled; + +}tBATTERY_CB; + +#ifdef __cplusplus +extern "C" { +#endif + +/* Global GATT data */ +#if GATT_DYNAMIC_MEMORY == FALSE +extern tBATTERY_CB battery_cb; +#else +extern tBATTERY_CB *battery_cb_ptr; +#define battery_cb (*battery_cb_ptr) +#endif + + +extern BOOLEAN battery_valid_handle_range(UINT16 handle); + +extern UINT8 battery_s_write_attr_value(UINT8 clcb_idx, tGATT_WRITE_REQ * p_value, + tGATT_STATUS *p_status); +extern UINT8 battery_s_read_attr_value (UINT8 clcb_idx, UINT16 handle, tGATT_VALUE *p_value, BOOLEAN is_long, tGATT_STATUS* p_status); + + + +#ifdef __cplusplus +} +#endif +#endif diff --git a/components/bt/bluedroid/profiles/include/srvc_dis_int.h b/components/bt/bluedroid/profiles/include/srvc_dis_int.h new file mode 100644 index 0000000000..74573195de --- /dev/null +++ b/components/bt/bluedroid/profiles/include/srvc_dis_int.h @@ -0,0 +1,84 @@ +/****************************************************************************** + * + * Copyright (C) 1999-2012 Broadcom Corporation + * + * 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. + * + ******************************************************************************/ + +#ifndef SRVC_DIS_INT_H +#define SRVC_DIS_INT_H + +#include "bt_target.h" +#include "srvc_api.h" +#include "gatt_api.h" + +#define DIS_MAX_CHAR_NUM 9 + + +typedef struct +{ + UINT16 uuid; + UINT16 handle; +}tDIS_DB_ENTRY; + +#define DIS_SYSTEM_ID_SIZE 8 +#define DIS_PNP_ID_SIZE 7 + + + +typedef struct +{ + tDIS_DB_ENTRY dis_attr[DIS_MAX_CHAR_NUM]; + tDIS_VALUE dis_value; + + tDIS_READ_CBACK *p_read_dis_cback; + + UINT16 service_handle; + UINT16 max_handle; + + BOOLEAN enabled; + + UINT8 dis_read_uuid_idx; + + tDIS_ATTR_MASK request_mask; +}tDIS_CB; + + + +#ifdef __cplusplus +extern "C" { +#endif + +/* Global GATT data */ +#if GATT_DYNAMIC_MEMORY == FALSE +extern tDIS_CB dis_cb; +#else +extern tDIS_CB *dis_cb_ptr; +#define dis_cb (*dis_cb_ptr) +#endif + + +extern BOOLEAN dis_valid_handle_range(UINT16 handle); +extern UINT8 dis_read_attr_value (UINT8 clcb_idx, UINT16 handle, tGATT_VALUE *p_value, + BOOLEAN is_long, tGATT_STATUS *p_status); +extern UINT8 dis_write_attr_value(tGATT_WRITE_REQ * p_data, tGATT_STATUS *p_status); + +extern void dis_c_cmpl_cback (tSRVC_CLCB *p_clcb, tGATTC_OPTYPE op, + tGATT_STATUS status, tGATT_CL_COMPLETE *p_data); + + +#ifdef __cplusplus +} +#endif +#endif diff --git a/components/bt/bluedroid/profiles/include/srvc_eng_int.h b/components/bt/bluedroid/profiles/include/srvc_eng_int.h new file mode 100644 index 0000000000..edd9763991 --- /dev/null +++ b/components/bt/bluedroid/profiles/include/srvc_eng_int.h @@ -0,0 +1,88 @@ +/****************************************************************************** + * + * Copyright (C) 1999-2013 Broadcom Corporation + * + * 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. + * + ******************************************************************************/ + +#ifndef SRVC_ENG_INT_H +#define SRVC_ENG_INT_H + +#include "bt_target.h" +#include "gatt_api.h" +#include "srvc_api.h" + +#define SRVC_MAX_APPS GATT_CL_MAX_LCB + +#define SRVC_ID_NONE 0 +#define SRVC_ID_DIS 1 +#define SRVC_ID_MAX SRVC_ID_DIS + +#define SRVC_ACT_IGNORE 0 +#define SRVC_ACT_RSP 1 +#define SRVC_ACT_PENDING 2 + +typedef struct +{ + BOOLEAN in_use; + UINT16 conn_id; + BOOLEAN connected; + BD_ADDR bda; + UINT32 trans_id; + UINT8 cur_srvc_id; + + tDIS_VALUE dis_value; + +}tSRVC_CLCB; + + +/* service engine control block */ +typedef struct +{ + tSRVC_CLCB clcb[SRVC_MAX_APPS]; /* connection link*/ + tGATT_IF gatt_if; + BOOLEAN enabled; + +}tSRVC_ENG_CB; + + + +#ifdef __cplusplus +extern "C" { +#endif + +/* Global GATT data */ +#if GATT_DYNAMIC_MEMORY == FALSE +extern tSRVC_ENG_CB srvc_eng_cb; +#else +extern tSRVC_ENG_CB srvc_eng_cb_ptr; +#define srvc_eng_cb (*srvc_eng_cb_ptr) + +#endif + +extern tSRVC_CLCB *srvc_eng_find_clcb_by_conn_id(UINT16 conn_id); +extern tSRVC_CLCB *srvc_eng_find_clcb_by_bd_addr(BD_ADDR bda); +extern UINT16 srvc_eng_find_conn_id_by_bd_addr(BD_ADDR bda); + + +extern void srvc_eng_release_channel (UINT16 conn_id) ; +extern BOOLEAN srvc_eng_request_channel (BD_ADDR remote_bda, UINT8 srvc_id ); +extern void srvc_sr_rsp(UINT8 clcb_idx, tGATT_STATUS st, tGATTS_RSP *p_rsp); +extern void srvc_sr_notify(BD_ADDR remote_bda, UINT16 handle, UINT16 len, UINT8 *p_value); + + +#ifdef __cplusplus +} +#endif +#endif diff --git a/components/bt/bluedroid/profiles/sample_button/button_pro.c b/components/bt/bluedroid/profiles/sample_button/button_pro.c new file mode 100644 index 0000000000..67409bed69 --- /dev/null +++ b/components/bt/bluedroid/profiles/sample_button/button_pro.c @@ -0,0 +1,326 @@ +/** + **************************************************************************************** + * + * @file button_pro.c + * + * @brief Application entry point + * + * Copyright (C) Espressif 2016 + * Created by Yulong at 2016/8/18 + * + * + **************************************************************************************** + */ + +#include + +#include +#include +#include + + +#include "bt_target.h" +#include "bt_trace.h" +#include "bt_types.h" +#include "gatt_api.h" +#include "bta_api.h" +#include "bta_gatt_api.h" +#include "bta_gatts_int.h" + +#include "button_pro.h" + +#define ARRAY_SIZE(x) (sizeof(x)/sizeof((x)[0])) + +tBUTTON_CB_ENV button_cb_env; + + + +/***************************************************************************** +** Constants +*****************************************************************************/ +static void button_profile_cb(tBTA_GATTS_EVT event, tBTA_GATTS *p_data); + + +/******************************************************************************* +** +** Function button_profile_cb +** +** Description the callback function after the profile has been register to the BTA manager module +** +** Returns NULL +** +*******************************************************************************/ +static void button_profile_cb(tBTA_GATTS_EVT event, tBTA_GATTS *p_data) +{ + tBTA_GATTS_RSP rsp; + tBT_UUID uuid = {LEN_UUID_16, {ATT_SVC_BUTTON}}; + + //LOG_ERROR("p_data->status = %x\n",p_data->status); + //if(p_data->status != BTA_GATT_OK){ + // LOG_ERROR("button profile register failed\n"); + // return; + //} + LOG_ERROR("button profile cb event = %x\n",event); + switch(event) + { + case BTA_GATTS_REG_EVT: + + LOG_ERROR("p_data->reg_oper.status = %x\n",p_data->reg_oper.status); + LOG_ERROR("(p_data->reg_oper.uuid.uu.uuid16=%x\n",p_data->reg_oper.uuid.uu.uuid16); + if(p_data->reg_oper.status != BTA_GATT_OK) + { + LOG_ERROR("button profile register failed\n"); + } + button_cb_env.gatt_if = p_data->reg_oper.server_if; + button_cb_env.enabled = true; + //button_cb_env.button_inst.app_id = p_data->reg_oper.uuid; + //create the button service to the service data base. + if(p_data->reg_oper.uuid.uu.uuid16 == ATT_SVC_BUTTON) + { + Button_CreateService(); + } + break; + case BTA_GATTS_READ_EVT: + //tBTA_GATTS_RSP rsp; + memset(&rsp,0,sizeof(tBTA_GATTS_API_RSP)); + rsp.attr_value.handle = p_data->req_data.p_data->read_req.handle; + rsp.attr_value.len = 2; + BTA_GATTS_SendRsp(p_data->req_data.conn_id,p_data->req_data.trans_id, + p_data->req_data.status,&rsp); + break; + case BTA_GATTS_WRITE_EVT: + BTA_GATTS_SendRsp(p_data->req_data.conn_id,p_data->req_data.trans_id, + p_data->req_data.status,NULL); + break; + case BTA_GATTS_CONF_EVT: + + break; + case BTA_GATTS_CREATE_EVT: + //tBT_UUID uuid_butt_write; + uuid.uu.uuid16 = ATT_CHAR_BUTTON_WIT; + //tBTA_GATT_PERM perm = (GATT_PERM_WRITE|GATT_PERM_READ); + //tBTA_GATT_CHAR_PROP prop = (GATT_CHAR_PROP_BIT_READ|GATT_CHAR_PROP_BIT_WRITE); + //uuid = {LEN_UUID_16, {ATT_SVC_BUTTON}}; + button_cb_env.clcb.cur_srvc_id= p_data->create.service_id; + button_cb_env.is_primery = p_data->create.is_primary; + //uuid = {LEN_UUID_16, {ATT_CHAR_BUTTON_WIT}}; + //start the button service after created + BTA_GATTS_StartService(p_data->create.service_id,BTA_GATT_TRANSPORT_LE); + //add the frist button characteristic --> write characteristic + BTA_GATTS_AddCharacteristic(button_cb_env.clcb.cur_srvc_id,&uuid, + (GATT_PERM_WRITE|GATT_PERM_READ), + (GATT_CHAR_PROP_BIT_READ|GATT_CHAR_PROP_BIT_WRITE)); + break; + + case BTA_GATTS_ADD_CHAR_EVT: + if(p_data->add_result.char_uuid.uu.uuid16 == ATT_CHAR_BUTTON_WIT) + { + uuid.uu.uuid16 = ATT_CHAR_BUTTON_NTF; + //tBTA_GATT_PERM perm = GATT_PERM_READ; + tBTA_GATT_CHAR_PROP prop = (GATT_CHAR_PROP_BIT_READ|GATT_CHAR_PROP_BIT_NOTIFY); + //save the att handle to the env + button_cb_env.button_inst.but_wirt_hdl = p_data->add_result.attr_id; + //add the frist button characteristic --> Notify characteristic + BTA_GATTS_AddCharacteristic(button_cb_env.clcb.cur_srvc_id,&uuid, + GATT_PERM_READ,(GATT_CHAR_PROP_BIT_READ|GATT_CHAR_PROP_BIT_NOTIFY)); + }else if(p_data->add_result.char_uuid.uu.uuid16 == ATT_CHAR_BUTTON_NTF){ // add the gattc config descriptor to the notify charateristic + //tBTA_GATT_PERM perm = (GATT_PERM_WRITE|GATT_PERM_WRITE); + uuid.uu.uuid16 = GATT_UUID_CHAR_CLIENT_CONFIG; + button_cb_env.button_inst.but_ntf_hdl = p_data->add_result.attr_id; + BTA_GATTS_AddCharDescriptor (button_cb_env.clcb.cur_srvc_id, + (GATT_PERM_WRITE|GATT_PERM_WRITE), + &uuid); + } + + break; + case BTA_GATTS_ADD_CHAR_DESCR_EVT: + if(p_data->add_result.char_uuid.uu.uuid16 == GATT_UUID_CHAR_CLIENT_CONFIG) + { + button_cb_env.button_inst.but_cfg_hdl = p_data->add_result.attr_id; + } + break; + case BTA_GATTS_CONNECT_EVT: + //set the connection flag to true + button_env_clcb_alloc(p_data->conn.conn_id, p_data->conn.remote_bda); + break; + case BTA_GATTS_DISCONNECT_EVT: + //set the connection flag to true + button_cb_env.clcb.connected = false; + break; + case BTA_GATTS_OPEN_EVT: + break; + case BTA_GATTS_CLOSE_EVT: + if(button_cb_env.clcb.connected && (button_cb_env.clcb.conn_id == p_data->conn.conn_id)) + { + //set the connection channal congested flag to true + button_cb_env.clcb.congest = p_data->congest.congested; + } + break; + case BTA_GATTS_LISTEN_EVT: + break; + case BTA_GATTS_CONGEST_EVT: + break; + default: + break; + } +} + + +/******************************************************************************* +** +** Function Button_CreateService +** +** Description Create a Service for the button profile +** +** Returns NULL +** +*******************************************************************************/ +void Button_CreateService(void) +{ + tBTA_GATTS_IF server_if ; + tBT_UUID uuid = {LEN_UUID_16, {ATT_SVC_BUTTON}}; + UINT16 num_handle = KEY_IDX_NB; + UINT8 inst = 0x00; + server_if = button_cb_env.gatt_if; + button_cb_env.inst_id = inst; + //if(!button_cb_env.enabled) + //{ + // LOG_ERROR("button service added error."); + //} + BTA_GATTS_CreateService(server_if,&uuid,inst,num_handle,true); + +} + +/******************************************************************************* +** +** Function button_env_clcb_alloc +** +** Description The function allocates a GATT profile connection link control block +** +** Returns NULL if not found. Otherwise pointer to the connection link block. +** +*******************************************************************************/ +tBUT_CLCB *button_env_clcb_alloc (UINT16 conn_id, BD_ADDR remote_bda) +{ + tBUT_CLCB *p_clcb = NULL; + p_clcb = &button_cb_env.clcb; + + if(!p_clcb->in_use) + { + p_clcb->in_use = TRUE; + p_clcb->conn_id = conn_id; + LOG_ERROR("p_clcb->conn_id = %x\n",conn_id); + p_clcb->connected = TRUE; + memcpy(p_clcb->remote_bda,remote_bda,BD_ADDR_LEN); + } + + return p_clcb; +} + +/******************************************************************************* +** +** Function button_env_find_conn_id_by_bd_adddr +** +** Description The function searches all LCB with macthing bd address +** +** Returns total number of clcb found. +** +*******************************************************************************/ +UINT16 button_env_find_conn_id_by_bd_adddr(BD_ADDR remote_bda) +{ + UINT8 i_clcb; + tBUT_CLCB *p_clcb = NULL; + + for(i_clcb = 0, p_clcb = &button_cb_env.clcb; i_clcb < BUTT_MAX_APPS; i_clcb++, p_clcb++) + { + if(p_clcb->in_use && p_clcb->connected &&memcmp(p_clcb->remote_bda,remote_bda,BD_ADDR_LEN)) + { + return p_clcb->conn_id; + } + } + + return GATT_INVALID_CONN_ID; +} + +/******************************************************************************* +** +** Function button_env_clcb_dealloc +** +** Description The function deallocates a GATT profile connection link control block +** +** Returns True the deallocation is successful +** +*******************************************************************************/ +/* +BOOLEAN button_env_clcb_dealloc(UINT16 conn_id) +{ + UINT8 i_clcb = 0; + tBUT_CLCB *p_clcb = NULL; + + for(i_clcb = 0, p_clcb = &button_cb_env.clcb; i_clcb < BUTT_MAX_APPS; i_clcb++, p_clcb++) + { + if(p_clcb->in_use && p_clcb->connected && (p_clcb->conn_id == conn_id)) + { + unsigned j; + for(j = 0; j < ARRAY_SIZE(p_clcb->button_value.data_string);j++) + { + if(p_clcb->button_value.data_string[j]) + { + GKI_freebuf(p_clcb->button_value.data_string[j]); + } + } + memset(p_clcb, 0, sizeof(tBUT_CLCB)); + return TRUE; + } + } + + return FALSE; +}*/ + + +/******************************************************************************* +** +** Function button_init +** +** Description Initializa the GATT Service for button profiles. +** +*******************************************************************************/ +tGATT_STATUS button_init (void) +{ + tBT_UUID app_uuid = {LEN_UUID_16,{ATT_SVC_BUTTON}}; + + if(button_cb_env.enabled) + { + LOG_ERROR("button svc already initaliezd"); + return GATT_ERROR; + } + else + { + memset(&button_cb_env,0,sizeof(tBUTTON_CB_ENV)); + } + + + /* register the button profile to the BTA_GATTS module*/ + BTA_GATTS_AppRegister(&app_uuid,button_profile_cb); + + button_cb_env.enabled = TRUE; + + return GATT_SUCCESS; +} + +void button_msg_notify(UINT8 len, UINT8 *button_msg) +{ + BOOLEAN conn_status = button_cb_env.clcb.connected; + UINT16 conn_id = button_cb_env.clcb.conn_id; + UINT16 attr_id = button_cb_env.button_inst.but_ntf_hdl; + //notify rsp==false; indicate rsp==true. + BOOLEAN rsp = false; + if(!conn_status && button_cb_env.clcb.congest) + { + LOG_ERROR("the conneciton for button profile has been loss"); + return; + } + + BTA_GATTS_HandleValueIndication (conn_id, attr_id, len, + button_msg, rsp); +} diff --git a/components/bt/bluedroid/stack/avrc/avrc_api.c b/components/bt/bluedroid/stack/avrc/avrc_api.c new file mode 100755 index 0000000000..c911de5c19 --- /dev/null +++ b/components/bt/bluedroid/stack/avrc/avrc_api.c @@ -0,0 +1,1167 @@ +/****************************************************************************** + * + * Copyright (C) 2003-2012 Broadcom Corporation + * + * 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. + * + ******************************************************************************/ + +/****************************************************************************** + * + * Interface to AVRCP mandatory commands + * + ******************************************************************************/ +#include +#include "bt_trace.h" +#include "gki.h" +#include "avrc_api.h" +#include "avrc_int.h" + +/***************************************************************************** +** Global data +*****************************************************************************/ + + +#define AVRC_MAX_RCV_CTRL_EVT AVCT_BROWSE_UNCONG_IND_EVT + +#ifndef MAX +#define MAX(a, b) ((a) > (b) ? (a) : (b)) +#endif + +static const UINT8 avrc_ctrl_event_map[] = +{ + AVRC_OPEN_IND_EVT, /* AVCT_CONNECT_CFM_EVT */ + AVRC_OPEN_IND_EVT, /* AVCT_CONNECT_IND_EVT */ + AVRC_CLOSE_IND_EVT, /* AVCT_DISCONNECT_CFM_EVT */ + AVRC_CLOSE_IND_EVT, /* AVCT_DISCONNECT_IND_EVT */ + AVRC_CONG_IND_EVT, /* AVCT_CONG_IND_EVT */ + AVRC_UNCONG_IND_EVT,/* AVCT_UNCONG_IND_EVT */ + AVRC_BROWSE_OPEN_IND_EVT, /* AVCT_BROWSE_CONN_CFM_EVT */ + AVRC_BROWSE_OPEN_IND_EVT, /* AVCT_BROWSE_CONN_IND_EVT */ + AVRC_BROWSE_CLOSE_IND_EVT, /* AVCT_BROWSE_DISCONN_CFM_EVT */ + AVRC_BROWSE_CLOSE_IND_EVT, /* AVCT_BROWSE_DISCONN_IND_EVT */ + AVRC_BROWSE_CONG_IND_EVT, /* AVCT_BROWSE_CONG_IND_EVT */ + AVRC_BROWSE_UNCONG_IND_EVT /* AVCT_BROWSE_UNCONG_IND_EVT */ +}; + +#define AVRC_OP_DROP 0xFE /* use this unused opcode to indication no need to call the callback function */ +#define AVRC_OP_DROP_N_FREE 0xFD /* use this unused opcode to indication no need to call the callback function & free buffer */ + +#define AVRC_OP_UNIT_INFO_RSP_LEN 8 +#define AVRC_OP_SUB_UNIT_INFO_RSP_LEN 8 +#define AVRC_OP_REJ_MSG_LEN 11 + +/****************************************************************************** +** +** Function avrc_ctrl_cback +** +** Description This is the callback function used by AVCTP to report +** received link events. +** +** Returns Nothing. +** +******************************************************************************/ +static void avrc_ctrl_cback(UINT8 handle, UINT8 event, UINT16 result, + BD_ADDR peer_addr) +{ + UINT8 avrc_event; + + if (event <= AVRC_MAX_RCV_CTRL_EVT && avrc_cb.ccb[handle].p_ctrl_cback) + { + avrc_event = avrc_ctrl_event_map[event]; + if (event == AVCT_CONNECT_CFM_EVT) + { + if (result != 0) /* failed */ + avrc_event = AVRC_CLOSE_IND_EVT; + } + (*avrc_cb.ccb[handle].p_ctrl_cback)(handle, avrc_event, result, peer_addr); + } + /* else drop the unknown event*/ +} + +/****************************************************************************** +** +** Function avrc_get_data_ptr +** +** Description Gets a pointer to the data payload in the packet. +** +** Returns A pointer to the data payload. +** +******************************************************************************/ +static UINT8 * avrc_get_data_ptr(BT_HDR *p_pkt) +{ + return (UINT8 *)(p_pkt + 1) + p_pkt->offset; +} + +/****************************************************************************** +** +** Function avrc_copy_packet +** +** Description Copies an AVRC packet to a new buffer. In the new buffer, +** the payload offset is at least AVCT_MSG_OFFSET octets. +** +** Returns The buffer with the copied data. +** +******************************************************************************/ +static BT_HDR * avrc_copy_packet(BT_HDR *p_pkt, int rsp_pkt_len) +{ + const int offset = MAX(AVCT_MSG_OFFSET, p_pkt->offset); + const int pkt_len = MAX(rsp_pkt_len, p_pkt->len); + BT_HDR *p_pkt_copy = + (BT_HDR *)GKI_getbuf((UINT16)(BT_HDR_SIZE + offset + pkt_len)); + + /* Copy the packet header, set the new offset, and copy the payload */ + if (p_pkt_copy != NULL) { + memcpy(p_pkt_copy, p_pkt, BT_HDR_SIZE); + p_pkt_copy->offset = offset; + UINT8 *p_data = avrc_get_data_ptr(p_pkt); + UINT8 *p_data_copy = avrc_get_data_ptr(p_pkt_copy); + memcpy(p_data_copy, p_data, p_pkt->len); + } + + return p_pkt_copy; +} + +#if (AVRC_METADATA_INCLUDED == TRUE) +/****************************************************************************** +** +** Function avrc_prep_end_frag +** +** Description This function prepares an end response fragment +** +** Returns Nothing. +** +******************************************************************************/ +static void avrc_prep_end_frag(UINT8 handle) +{ + tAVRC_FRAG_CB *p_fcb; + BT_HDR *p_pkt_new; + UINT8 *p_data, *p_orig_data; + UINT8 rsp_type; + + AVRC_TRACE_DEBUG ("avrc_prep_end_frag" ); + p_fcb = &avrc_cb.fcb[handle]; + + /* The response type of the end fragment should be the same as the the PDU of "End Fragment + ** Response" Errata: https://www.bluetooth.org/errata/errata_view.cfm?errata_id=4383 + */ + p_orig_data = ((UINT8 *)(p_fcb->p_fmsg + 1) + p_fcb->p_fmsg->offset); + rsp_type = ((*p_orig_data) & AVRC_CTYPE_MASK); + + p_pkt_new = p_fcb->p_fmsg; + p_pkt_new->len -= (AVRC_MAX_CTRL_DATA_LEN - AVRC_VENDOR_HDR_SIZE - AVRC_MIN_META_HDR_SIZE); + p_pkt_new->offset += (AVRC_MAX_CTRL_DATA_LEN - AVRC_VENDOR_HDR_SIZE - AVRC_MIN_META_HDR_SIZE); + p_data = (UINT8 *)(p_pkt_new+1) + p_pkt_new->offset; + *p_data++ = rsp_type; + *p_data++ = (AVRC_SUB_PANEL << AVRC_SUBTYPE_SHIFT); + *p_data++ = AVRC_OP_VENDOR; + AVRC_CO_ID_TO_BE_STREAM(p_data, AVRC_CO_METADATA); + *p_data++ = p_fcb->frag_pdu; + *p_data++ = AVRC_PKT_END; + + /* 4=pdu, pkt_type & len */ + UINT16_TO_BE_STREAM(p_data, (p_pkt_new->len - AVRC_VENDOR_HDR_SIZE - AVRC_MIN_META_HDR_SIZE)); +} + +/****************************************************************************** +** +** Function avrc_send_continue_frag +** +** Description This function sends a continue response fragment +** +** Returns Nothing. +** +******************************************************************************/ +static void avrc_send_continue_frag(UINT8 handle, UINT8 label) +{ + tAVRC_FRAG_CB *p_fcb; + BT_HDR *p_pkt_old, *p_pkt; + UINT8 *p_old, *p_data; + UINT8 cr = AVCT_RSP; + tAVRC_RSP rej_rsp; + + p_fcb = &avrc_cb.fcb[handle]; + p_pkt = p_fcb->p_fmsg; + + AVRC_TRACE_DEBUG("%s handle = %u label = %u len = %d", + __func__, handle, label, p_pkt->len); + if (p_pkt->len > AVRC_MAX_CTRL_DATA_LEN) + { + int offset_len = MAX(AVCT_MSG_OFFSET, p_pkt->offset); + p_pkt_old = p_fcb->p_fmsg; + p_pkt = (BT_HDR *)GKI_getbuf((UINT16)(AVRC_PACKET_LEN + offset_len + BT_HDR_SIZE)); + if (p_pkt) + { + p_pkt->len = AVRC_MAX_CTRL_DATA_LEN; + p_pkt->offset = AVCT_MSG_OFFSET; + p_pkt->layer_specific = p_pkt_old->layer_specific; + p_pkt->event = p_pkt_old->event; + p_old = (UINT8 *)(p_pkt_old+1) + p_pkt_old->offset; + p_data = (UINT8 *)(p_pkt+1) + p_pkt->offset; + memcpy (p_data, p_old, AVRC_MAX_CTRL_DATA_LEN); + /* use AVRC continue packet type */ + p_data += AVRC_VENDOR_HDR_SIZE; + p_data++; /* pdu */ + *p_data++ = AVRC_PKT_CONTINUE; + /* 4=pdu, pkt_type & len */ + UINT16_TO_BE_STREAM(p_data, (AVRC_MAX_CTRL_DATA_LEN - AVRC_VENDOR_HDR_SIZE - 4)); + + /* prepare the left over for as an end fragment */ + avrc_prep_end_frag (handle); + } + else + { + /* use the current GKI buffer to send Internal error status */ + p_pkt = p_fcb->p_fmsg; + p_fcb->p_fmsg = NULL; + p_fcb->frag_enabled = FALSE; + AVRC_TRACE_ERROR ("AVRC_MsgReq no buffers for fragmentation - send internal error" ); + p_data = (UINT8 *)(p_pkt+1) + p_pkt->offset; + *p_data++ = AVRC_PDU_REQUEST_CONTINUATION_RSP; + *p_data++ = 0; + UINT16_TO_BE_STREAM(p_data, 0); + p_pkt->len = 4; + rej_rsp.pdu = AVRC_PDU_REQUEST_CONTINUATION_RSP; + rej_rsp.status = AVRC_STS_INTERNAL_ERR; + AVRC_BldResponse( handle, (tAVRC_RESPONSE *)&rej_rsp, &p_pkt); + cr = AVCT_RSP; + } + } + else + { + /* end fragment. clean the control block */ + p_fcb->frag_enabled = FALSE; + p_fcb->p_fmsg = NULL; + } + AVCT_MsgReq( handle, label, cr, p_pkt); +} + +/****************************************************************************** +** +** Function avrc_proc_vendor_command +** +** Description This function processes received vendor command. +** +** Returns if not NULL, the response to send right away. +** +******************************************************************************/ +static BT_HDR * avrc_proc_vendor_command(UINT8 handle, UINT8 label, + BT_HDR *p_pkt, tAVRC_MSG_VENDOR *p_msg) +{ + BT_HDR *p_rsp = NULL; + UINT8 *p_data; + UINT8 *p_begin; + UINT8 pkt_type; + BOOLEAN abort_frag = FALSE; + tAVRC_STS status = AVRC_STS_NO_ERROR; + tAVRC_FRAG_CB *p_fcb; + + p_begin = (UINT8 *)(p_pkt+1) + p_pkt->offset; + p_data = p_begin + AVRC_VENDOR_HDR_SIZE; + pkt_type = *(p_data + 1) & AVRC_PKT_TYPE_MASK; + + if (pkt_type != AVRC_PKT_SINGLE) + { + /* reject - commands can only be in single packets at AVRCP level */ + AVRC_TRACE_ERROR ("commands must be in single packet pdu:0x%x", *p_data ); + /* use the current GKI buffer to send the reject */ + status = AVRC_STS_BAD_CMD; + } + /* check if there are fragments waiting to be sent */ + else if (avrc_cb.fcb[handle].frag_enabled) + { + p_fcb = &avrc_cb.fcb[handle]; + if (p_msg->company_id == AVRC_CO_METADATA) + { + switch (*p_data) + { + case AVRC_PDU_ABORT_CONTINUATION_RSP: + /* aborted by CT - send accept response */ + abort_frag = TRUE; + p_begin = (UINT8 *)(p_pkt+1) + p_pkt->offset; + *p_begin = (AVRC_RSP_ACCEPT & AVRC_CTYPE_MASK); + if (*(p_data + 4) != p_fcb->frag_pdu) + { + *p_begin = (AVRC_RSP_REJ & AVRC_CTYPE_MASK); + *(p_data + 4) = AVRC_STS_BAD_PARAM; + } + else + { + p_data = (p_begin + AVRC_VENDOR_HDR_SIZE + 2); + UINT16_TO_BE_STREAM(p_data, 0); + p_pkt->len = (p_data - p_begin); + } + AVCT_MsgReq( handle, label, AVCT_RSP, p_pkt); + p_msg->hdr.opcode = AVRC_OP_DROP; /* used the p_pkt to send response */ + break; + + case AVRC_PDU_REQUEST_CONTINUATION_RSP: + if (*(p_data + 4) == p_fcb->frag_pdu) + { + avrc_send_continue_frag(handle, label); + p_msg->hdr.opcode = AVRC_OP_DROP_N_FREE; + } + else + { + /* the pdu id does not match - reject the command using the current GKI buffer */ + AVRC_TRACE_ERROR("avrc_proc_vendor_command continue pdu: 0x%x does not match \ + current re-assembly pdu: 0x%x", + *(p_data + 4), p_fcb->frag_pdu); + status = AVRC_STS_BAD_PARAM; + abort_frag = TRUE; + } + break; + + default: + /* implicit abort */ + abort_frag = TRUE; + } + } + else + { + abort_frag = TRUE; + /* implicit abort */ + } + + if (abort_frag) + { + if (p_fcb->p_fmsg) + GKI_freebuf(p_fcb->p_fmsg); + p_fcb->p_fmsg = NULL; + p_fcb->frag_enabled = FALSE; + } + } + + if (status != AVRC_STS_NO_ERROR) + { + /* use the current GKI buffer to build/send the reject message */ + p_data = (UINT8 *)(p_pkt+1) + p_pkt->offset; + *p_data++ = AVRC_RSP_REJ; + p_data += AVRC_VENDOR_HDR_SIZE; /* pdu */ + *p_data++ = 0; /* pkt_type */ + UINT16_TO_BE_STREAM(p_data, 1); /* len */ + *p_data++ = status; /* error code */ + p_pkt->len = AVRC_VENDOR_HDR_SIZE + 5; + p_rsp = p_pkt; + } + + return p_rsp; +} + +/****************************************************************************** +** +** Function avrc_proc_far_msg +** +** Description This function processes metadata fragmenation +** and reassembly +** +** Returns 0, to report the message with msg_cback . +** +******************************************************************************/ +static UINT8 avrc_proc_far_msg(UINT8 handle, UINT8 label, UINT8 cr, BT_HDR **pp_pkt, + tAVRC_MSG_VENDOR *p_msg) +{ + BT_HDR *p_pkt = *pp_pkt; + UINT8 *p_data; + UINT8 drop_code = 0; + BT_HDR *p_rsp = NULL; + BT_HDR *p_cmd = NULL; + BOOLEAN req_continue = FALSE; + BT_HDR *p_pkt_new = NULL; + UINT8 pkt_type; + UINT16 buf_len; + tAVRC_RASM_CB *p_rcb; + tAVRC_NEXT_CMD avrc_cmd; + + p_data = (UINT8 *)(p_pkt+1) + p_pkt->offset; + + /* Skip over vendor header (ctype, subunit*, opcode, CO_ID) */ + p_data += AVRC_VENDOR_HDR_SIZE; + + pkt_type = *(p_data + 1) & AVRC_PKT_TYPE_MASK; + AVRC_TRACE_DEBUG ("pkt_type %d", pkt_type ); + p_rcb = &avrc_cb.rcb[handle]; + if (p_msg->company_id == AVRC_CO_METADATA) + { + /* check if the message needs to be re-assembled */ + if (pkt_type == AVRC_PKT_SINGLE || pkt_type == AVRC_PKT_START) + { + /* previous fragments need to be dropped, when received another new message */ + p_rcb->rasm_offset = 0; + if (p_rcb->p_rmsg) + { + GKI_freebuf(p_rcb->p_rmsg); + p_rcb->p_rmsg = NULL; + } + } + + if (pkt_type != AVRC_PKT_SINGLE && cr == AVCT_RSP) + { + /* not a single response packet - need to re-assemble metadata messages */ + if (pkt_type == AVRC_PKT_START) + { + /* Allocate buffer for re-assembly */ + p_rcb->rasm_pdu = *p_data; + if ((p_rcb->p_rmsg = (BT_HDR *)GKI_getbuf(GKI_MAX_BUF_SIZE)) != NULL) + { + /* Copy START packet to buffer for re-assembling fragments*/ + memcpy(p_rcb->p_rmsg, p_pkt, sizeof(BT_HDR)); /* Copy bt hdr */ + + /* Copy metadata message */ + memcpy((UINT8 *)(p_rcb->p_rmsg + 1), + (UINT8 *)(p_pkt+1) + p_pkt->offset, p_pkt->len); + + /* offset of start of metadata response in reassembly buffer */ + p_rcb->p_rmsg->offset = p_rcb->rasm_offset = 0; + + /* Free original START packet, replace with pointer to reassembly buffer */ + GKI_freebuf(p_pkt); + *pp_pkt = p_rcb->p_rmsg; + } + else + { + /* Unable to allocate buffer for fragmented avrc message. Reuse START + buffer for reassembly (re-assembled message may fit into ACL buf) */ + AVRC_TRACE_DEBUG ("Unable to allocate buffer for fragmented avrc message, \ + reusing START buffer for reassembly"); + p_rcb->rasm_offset = p_pkt->offset; + p_rcb->p_rmsg = p_pkt; + } + + /* set offset to point to where to copy next - use the same re-asm logic as AVCT */ + p_rcb->p_rmsg->offset += p_rcb->p_rmsg->len; + req_continue = TRUE; + } + else if (p_rcb->p_rmsg == NULL) + { + /* Received a CONTINUE/END, but no corresponding START + (or previous fragmented response was dropped) */ + AVRC_TRACE_DEBUG ("Received a CONTINUE/END without no corresponding START \ + (or previous fragmented response was dropped)"); + drop_code = 5; + GKI_freebuf(p_pkt); + *pp_pkt = NULL; + } + else + { + /* get size of buffer holding assembled message */ + buf_len = GKI_get_buf_size (p_rcb->p_rmsg) - sizeof(BT_HDR); + /* adjust offset and len of fragment for header byte */ + p_pkt->offset += (AVRC_VENDOR_HDR_SIZE + AVRC_MIN_META_HDR_SIZE); + p_pkt->len -= (AVRC_VENDOR_HDR_SIZE + AVRC_MIN_META_HDR_SIZE); + /* verify length */ + if ((p_rcb->p_rmsg->offset + p_pkt->len) > buf_len) + { + AVRC_TRACE_WARNING("Fragmented message too big! - report the partial message"); + p_pkt->len = buf_len - p_rcb->p_rmsg->offset; + pkt_type = AVRC_PKT_END; + } + + /* copy contents of p_pkt to p_rx_msg */ + memcpy((UINT8 *)(p_rcb->p_rmsg + 1) + p_rcb->p_rmsg->offset, + (UINT8 *)(p_pkt + 1) + p_pkt->offset, p_pkt->len); + + if (pkt_type == AVRC_PKT_END) + { + p_rcb->p_rmsg->offset = p_rcb->rasm_offset; + p_rcb->p_rmsg->len += p_pkt->len; + p_pkt_new = p_rcb->p_rmsg; + p_rcb->rasm_offset = 0; + p_rcb->p_rmsg = NULL; + p_msg->p_vendor_data = (UINT8 *)(p_pkt_new+1) + p_pkt_new->offset; + p_msg->hdr.ctype = p_msg->p_vendor_data[0] & AVRC_CTYPE_MASK; + /* 6 = ctype, subunit*, opcode & CO_ID */ + p_msg->p_vendor_data += AVRC_VENDOR_HDR_SIZE; + p_msg->vendor_len = p_pkt_new->len - AVRC_VENDOR_HDR_SIZE; + p_data = p_msg->p_vendor_data + 1; /* skip pdu */ + *p_data++ = AVRC_PKT_SINGLE; + UINT16_TO_BE_STREAM(p_data, (p_msg->vendor_len - AVRC_MIN_META_HDR_SIZE)); + AVRC_TRACE_DEBUG("end frag:%d, total len:%d, offset:%d", p_pkt->len, + p_pkt_new->len, p_pkt_new->offset); + } + else + { + p_rcb->p_rmsg->offset += p_pkt->len; + p_rcb->p_rmsg->len += p_pkt->len; + p_pkt_new = NULL; + req_continue = TRUE; + } + GKI_freebuf(p_pkt); + *pp_pkt = p_pkt_new; + } + } + + if (cr == AVCT_CMD) + { + p_rsp = avrc_proc_vendor_command(handle, label, *pp_pkt, p_msg); + if (p_rsp) + { + AVCT_MsgReq( handle, label, AVCT_RSP, p_rsp); + drop_code = 3; + } + else if (p_msg->hdr.opcode == AVRC_OP_DROP) + { + drop_code = 1; + } + else if (p_msg->hdr.opcode == AVRC_OP_DROP_N_FREE) + drop_code = 4; + + } + else if (cr == AVCT_RSP && req_continue == TRUE) + { + avrc_cmd.pdu = AVRC_PDU_REQUEST_CONTINUATION_RSP; + avrc_cmd.status = AVRC_STS_NO_ERROR; + avrc_cmd.target_pdu = p_rcb->rasm_pdu; + if (AVRC_BldCommand ((tAVRC_COMMAND *)&avrc_cmd, &p_cmd) == AVRC_STS_NO_ERROR) + { + drop_code = 2; + AVRC_MsgReq (handle, (UINT8)(label), AVRC_CMD_CTRL, p_cmd); + } + } + } + + return drop_code; +} +#endif /* (AVRC_METADATA_INCLUDED == TRUE) */ + +/****************************************************************************** +** +** Function avrc_msg_cback +** +** Description This is the callback function used by AVCTP to report +** received AV control messages. +** +** Returns Nothing. +** +******************************************************************************/ +static void avrc_msg_cback(UINT8 handle, UINT8 label, UINT8 cr, + BT_HDR *p_pkt) +{ + UINT8 opcode; + tAVRC_MSG msg; + UINT8 *p_data; + UINT8 *p_begin; + BOOLEAN drop = FALSE; + BOOLEAN do_free = TRUE; + BT_HDR *p_rsp = NULL; + UINT8 *p_rsp_data; + int xx; + BOOLEAN reject = FALSE; +#if (BT_USE_TRACES == TRUE) + char *p_drop_msg = "dropped"; +#endif + tAVRC_MSG_VENDOR *p_msg = &msg.vendor; + + if (cr == AVCT_CMD && + (p_pkt->layer_specific & AVCT_DATA_CTRL && AVRC_PACKET_LEN < sizeof(p_pkt->len))) + { + /* Ignore the invalid AV/C command frame */ +#if (BT_USE_TRACES == TRUE) + p_drop_msg = "dropped - too long AV/C cmd frame size"; +#endif + GKI_freebuf(p_pkt); + return; + } + + if (cr == AVCT_REJ) + { + /* The peer thinks that this PID is no longer open - remove this handle */ + /* */ + GKI_freebuf(p_pkt); + AVCT_RemoveConn(handle); + return; + } + + p_data = (UINT8 *)(p_pkt+1) + p_pkt->offset; + memset(&msg, 0, sizeof(tAVRC_MSG) ); + { + msg.hdr.ctype = p_data[0] & AVRC_CTYPE_MASK; + AVRC_TRACE_DEBUG("avrc_msg_cback handle:%d, ctype:%d, offset:%d, len: %d", + handle, msg.hdr.ctype, p_pkt->offset, p_pkt->len); + msg.hdr.subunit_type = (p_data[1] & AVRC_SUBTYPE_MASK) >> AVRC_SUBTYPE_SHIFT; + msg.hdr.subunit_id = p_data[1] & AVRC_SUBID_MASK; + opcode = p_data[2]; + } + + if ( ((avrc_cb.ccb[handle].control & AVRC_CT_TARGET) && (cr == AVCT_CMD)) || + ((avrc_cb.ccb[handle].control & AVRC_CT_CONTROL) && (cr == AVCT_RSP)) ) + { + + switch(opcode) + { + case AVRC_OP_UNIT_INFO: + if (cr == AVCT_CMD) + { + /* send the response to the peer */ + p_rsp = avrc_copy_packet(p_pkt, AVRC_OP_UNIT_INFO_RSP_LEN); + p_rsp_data = avrc_get_data_ptr(p_rsp); + *p_rsp_data = AVRC_RSP_IMPL_STBL; + /* check & set the offset. set response code, set subunit_type & subunit_id, + set AVRC_OP_UNIT_INFO */ + /* 3 bytes: ctype, subunit*, opcode */ + p_rsp_data += AVRC_AVC_HDR_SIZE; + *p_rsp_data++ = 7; + /* Panel subunit & id=0 */ + *p_rsp_data++ = (AVRC_SUB_PANEL << AVRC_SUBTYPE_SHIFT); + AVRC_CO_ID_TO_BE_STREAM(p_rsp_data, avrc_cb.ccb[handle].company_id); + p_rsp->len = (UINT16) (p_rsp_data - (UINT8 *)(p_rsp + 1) - p_rsp->offset); + cr = AVCT_RSP; +#if (BT_USE_TRACES == TRUE) + p_drop_msg = "auto respond"; +#endif + } + else + { + /* parse response */ + p_data += 4; /* 3 bytes: ctype, subunit*, opcode + octet 3 (is 7)*/ + msg.unit.unit_type = (*p_data & AVRC_SUBTYPE_MASK) >> AVRC_SUBTYPE_SHIFT; + msg.unit.unit = *p_data & AVRC_SUBID_MASK; + p_data++; + AVRC_BE_STREAM_TO_CO_ID(msg.unit.company_id, p_data); + } + break; + + case AVRC_OP_SUB_INFO: + if (cr == AVCT_CMD) + { + /* send the response to the peer */ + p_rsp = avrc_copy_packet(p_pkt, AVRC_OP_SUB_UNIT_INFO_RSP_LEN); + p_rsp_data = avrc_get_data_ptr(p_rsp); + *p_rsp_data = AVRC_RSP_IMPL_STBL; + /* check & set the offset. set response code, set (subunit_type & subunit_id), + set AVRC_OP_SUB_INFO, set (page & extention code) */ + p_rsp_data += 4; + /* Panel subunit & id=0 */ + *p_rsp_data++ = (AVRC_SUB_PANEL << AVRC_SUBTYPE_SHIFT); + memset(p_rsp_data, AVRC_CMD_OPRND_PAD, AVRC_SUBRSP_OPRND_BYTES); + p_rsp_data += AVRC_SUBRSP_OPRND_BYTES; + p_rsp->len = (UINT16) (p_rsp_data - (UINT8 *)(p_rsp + 1) - p_rsp->offset); + cr = AVCT_RSP; +#if (BT_USE_TRACES == TRUE) + p_drop_msg = "auto responded"; +#endif + } + else + { + /* parse response */ + p_data += AVRC_AVC_HDR_SIZE; /* 3 bytes: ctype, subunit*, opcode */ + msg.sub.page = (*p_data++ >> AVRC_SUB_PAGE_SHIFT) & AVRC_SUB_PAGE_MASK; + xx = 0; + while (*p_data != AVRC_CMD_OPRND_PAD && xx> AVRC_SUBTYPE_SHIFT; + if (msg.sub.subunit_type[xx] == AVRC_SUB_PANEL) + msg.sub.panel = TRUE; + xx++; + } + } + break; + + case AVRC_OP_VENDOR: + p_data = (UINT8 *)(p_pkt+1) + p_pkt->offset; + p_begin = p_data; + if (p_pkt->len < AVRC_VENDOR_HDR_SIZE) /* 6 = ctype, subunit*, opcode & CO_ID */ + { + if (cr == AVCT_CMD) + reject = TRUE; + else + drop = TRUE; + break; + } + p_data += AVRC_AVC_HDR_SIZE; /* skip the first 3 bytes: ctype, subunit*, opcode */ + AVRC_BE_STREAM_TO_CO_ID(p_msg->company_id, p_data); + p_msg->p_vendor_data = p_data; + p_msg->vendor_len = p_pkt->len - (p_data - p_begin); + +#if (AVRC_METADATA_INCLUDED == TRUE) + UINT8 drop_code = 0; + if (p_msg->company_id == AVRC_CO_METADATA) + { + /* Validate length for metadata message */ + if (p_pkt->len < (AVRC_VENDOR_HDR_SIZE + AVRC_MIN_META_HDR_SIZE)) + { + if (cr == AVCT_CMD) + reject = TRUE; + else + drop = TRUE; + break; + } + + /* Check+handle fragmented messages */ + drop_code = avrc_proc_far_msg(handle, label, cr, &p_pkt, p_msg); + if (drop_code > 0) + drop = TRUE; + } + if (drop_code > 0) + { + if (drop_code != 4) + do_free = FALSE; +#if (BT_USE_TRACES == TRUE) + switch (drop_code) + { + case 1: + p_drop_msg = "sent_frag"; + break; + case 2: + p_drop_msg = "req_cont"; + break; + case 3: + p_drop_msg = "sent_frag3"; + break; + case 4: + p_drop_msg = "sent_frag_free"; + break; + default: + p_drop_msg = "sent_fragd"; + } +#endif + } +#endif /* (AVRC_METADATA_INCLUDED == TRUE) */ + break; + + case AVRC_OP_PASS_THRU: + if (p_pkt->len < 5) /* 3 bytes: ctype, subunit*, opcode & op_id & len */ + { + if (cr == AVCT_CMD) + reject = TRUE; + else + drop = TRUE; + break; + } + p_data += AVRC_AVC_HDR_SIZE; /* skip the first 3 bytes: ctype, subunit*, opcode */ + msg.pass.op_id = (AVRC_PASS_OP_ID_MASK & *p_data); + if (AVRC_PASS_STATE_MASK & *p_data) + msg.pass.state = TRUE; + else + msg.pass.state = FALSE; + p_data++; + msg.pass.pass_len = *p_data++; + if (msg.pass.pass_len != p_pkt->len - 5) + msg.pass.pass_len = p_pkt->len - 5; + if (msg.pass.pass_len) + msg.pass.p_pass_data = p_data; + else + msg.pass.p_pass_data = NULL; + break; + + + default: + if ((avrc_cb.ccb[handle].control & AVRC_CT_TARGET) && (cr == AVCT_CMD)) + { + /* reject unsupported opcode */ + reject = TRUE; + } + drop = TRUE; + break; + } + } + else /* drop the event */ + { + drop = TRUE; + } + + if (reject) + { + /* reject unsupported opcode */ + p_rsp = avrc_copy_packet(p_pkt, AVRC_OP_REJ_MSG_LEN); + p_rsp_data = avrc_get_data_ptr(p_rsp); + *p_rsp_data = AVRC_RSP_REJ; +#if (BT_USE_TRACES == TRUE) + p_drop_msg = "rejected"; +#endif + cr = AVCT_RSP; + drop = TRUE; + } + + if (p_rsp) + { + /* set to send response right away */ + AVCT_MsgReq( handle, label, cr, p_rsp); + drop = TRUE; + } + + if (drop == FALSE) + { + msg.hdr.opcode = opcode; + (*avrc_cb.ccb[handle].p_msg_cback)(handle, label, opcode, &msg); + } +#if (BT_USE_TRACES == TRUE) + else + { + AVRC_TRACE_WARNING("avrc_msg_cback %s msg handle:%d, control:%d, cr:%d, opcode:x%x", + p_drop_msg, + handle, avrc_cb.ccb[handle].control, cr, opcode); + } +#endif + + + if (do_free) + GKI_freebuf(p_pkt); +} + + + + +/****************************************************************************** +** +** Function avrc_pass_msg +** +** Description Compose a PASS THROUGH command according to p_msg +** +** Input Parameters: +** p_msg: Pointer to PASS THROUGH message structure. +** +** Output Parameters: +** None. +** +** Returns pointer to a valid GKI buffer if successful. +** NULL if p_msg is NULL. +** +******************************************************************************/ +static BT_HDR * avrc_pass_msg(tAVRC_MSG_PASS *p_msg) +{ + BT_HDR *p_cmd = NULL; + UINT8 *p_data; + + assert(p_msg != NULL); + assert(AVRC_CMD_POOL_SIZE > (AVRC_MIN_CMD_LEN+p_msg->pass_len)); + + if ((p_cmd = (BT_HDR *) GKI_getpoolbuf(AVRC_CMD_POOL_ID)) != NULL) + { + p_cmd->offset = AVCT_MSG_OFFSET; + p_cmd->layer_specific = AVCT_DATA_CTRL; + p_data = (UINT8 *)(p_cmd + 1) + p_cmd->offset; + *p_data++ = (p_msg->hdr.ctype & AVRC_CTYPE_MASK); + *p_data++ = (AVRC_SUB_PANEL << AVRC_SUBTYPE_SHIFT); /* Panel subunit & id=0 */ + *p_data++ = AVRC_OP_PASS_THRU; + *p_data = (AVRC_PASS_OP_ID_MASK&p_msg->op_id); + if (p_msg->state) + *p_data |= AVRC_PASS_STATE_MASK; + p_data++; + + if (p_msg->op_id == AVRC_ID_VENDOR) + { + *p_data++ = p_msg->pass_len; + if (p_msg->pass_len && p_msg->p_pass_data) + { + memcpy(p_data, p_msg->p_pass_data, p_msg->pass_len); + p_data += p_msg->pass_len; + } + } + else /* set msg len to 0 for other op_id */ + { + /* set msg len to 0 for other op_id */ + *p_data++ = 0; + } + p_cmd->len = (UINT16) (p_data - (UINT8 *)(p_cmd + 1) - p_cmd->offset); + } + return p_cmd; +} + +/****************************************************************************** +** +** Function AVRC_Open +** +** Description This function is called to open a connection to AVCTP. +** The connection can be either an initiator or acceptor, as +** determined by the p_ccb->stream parameter. +** The connection can be a target, a controller or for both role, +** as determined by the p_ccb->control parameter. +** By definition, a target connection is an acceptor connection +** that waits for an incoming AVCTP connection from the peer. +** The connection remains available to the application until +** the application closes it by calling AVRC_Close(). The +** application does not need to reopen the connection after an +** AVRC_CLOSE_IND_EVT is received. +** +** Input Parameters: +** p_ccb->company_id: Company Identifier. +** +** p_ccb->p_ctrl_cback: Pointer to control callback function. +** +** p_ccb->p_msg_cback: Pointer to message callback function. +** +** p_ccb->conn: AVCTP connection role. This is set to +** AVCTP_INT for initiator connections and AVCTP_ACP +** for acceptor connections. +** +** p_ccb->control: Control role. This is set to +** AVRC_CT_TARGET for target connections, AVRC_CT_CONTROL +** for control connections or (AVRC_CT_TARGET|AVRC_CT_CONTROL) +** for connections that support both roles. +** +** peer_addr: BD address of peer device. This value is +** only used for initiator connections; for acceptor +** connections it can be set to NULL. +** +** Output Parameters: +** p_handle: Pointer to handle. This parameter is only +** valid if AVRC_SUCCESS is returned. +** +** Returns AVRC_SUCCESS if successful. +** AVRC_NO_RESOURCES if there are not enough resources to open +** the connection. +** +******************************************************************************/ +UINT16 AVRC_Open(UINT8 *p_handle, tAVRC_CONN_CB *p_ccb, BD_ADDR_PTR peer_addr) +{ + UINT16 status; + tAVCT_CC cc; + + cc.p_ctrl_cback = avrc_ctrl_cback; /* Control callback */ + cc.p_msg_cback = avrc_msg_cback; /* Message callback */ + cc.pid = UUID_SERVCLASS_AV_REMOTE_CONTROL; /* Profile ID */ + cc.role = p_ccb->conn; /* Initiator/acceptor role */ + cc.control = p_ccb->control; /* Control role (Control/Target) */ + + status = AVCT_CreateConn(p_handle, &cc, peer_addr); + if (status == AVCT_SUCCESS) + { + memcpy(&avrc_cb.ccb[*p_handle], p_ccb, sizeof(tAVRC_CONN_CB)); +#if (AVRC_METADATA_INCLUDED == TRUE) + memset(&avrc_cb.fcb[*p_handle], 0, sizeof(tAVRC_FRAG_CB)); + memset(&avrc_cb.rcb[*p_handle], 0, sizeof(tAVRC_RASM_CB)); +#endif + } + AVRC_TRACE_DEBUG("AVRC_Open role: %d, control:%d status:%d, handle:%d", cc.role, cc.control, + status, *p_handle); + + return status; +} + +/****************************************************************************** +** +** Function AVRC_Close +** +** Description Close a connection opened with AVRC_Open(). +** This function is called when the +** application is no longer using a connection. +** +** Input Parameters: +** handle: Handle of this connection. +** +** Output Parameters: +** None. +** +** Returns AVRC_SUCCESS if successful. +** AVRC_BAD_HANDLE if handle is invalid. +** +******************************************************************************/ +UINT16 AVRC_Close(UINT8 handle) +{ + AVRC_TRACE_DEBUG("AVRC_Close handle:%d", handle); + return AVCT_RemoveConn(handle); +} + + +/****************************************************************************** +** +** Function AVRC_MsgReq +** +** Description This function is used to send the AVRCP byte stream in p_pkt +** down to AVCTP. +** +** It is expected that p_pkt->offset is at least AVCT_MSG_OFFSET +** p_pkt->layer_specific is AVCT_DATA_CTRL or AVCT_DATA_BROWSE +** p_pkt->event is AVRC_OP_VENDOR, AVRC_OP_PASS_THRU or AVRC_OP_BROWSE +** The above BT_HDR settings are set by the AVRC_Bld* functions. +** +** Returns AVRC_SUCCESS if successful. +** AVRC_BAD_HANDLE if handle is invalid. +** +******************************************************************************/ +UINT16 AVRC_MsgReq (UINT8 handle, UINT8 label, UINT8 ctype, BT_HDR *p_pkt) +{ +#if (AVRC_METADATA_INCLUDED == TRUE) + UINT8 *p_data; + UINT8 cr = AVCT_CMD; + BOOLEAN chk_frag = TRUE; + UINT8 *p_start = NULL; + tAVRC_FRAG_CB *p_fcb; + UINT16 len; + BT_HDR *p_pkt_new; + + if (!p_pkt) + return AVRC_BAD_PARAM; + + AVRC_TRACE_DEBUG("%s handle = %u label = %u ctype = %u len = %d", + __func__, handle, label, ctype, p_pkt->len); + + if (ctype >= AVRC_RSP_NOT_IMPL) + cr = AVCT_RSP; + + if (p_pkt->event == AVRC_OP_VENDOR) + { + /* add AVRCP Vendor Dependent headers */ + p_start = ((UINT8 *)(p_pkt + 1) + p_pkt->offset); + p_pkt->offset -= AVRC_VENDOR_HDR_SIZE; + p_pkt->len += AVRC_VENDOR_HDR_SIZE; + p_data = (UINT8 *)(p_pkt + 1) + p_pkt->offset; + *p_data++ = (ctype & AVRC_CTYPE_MASK); + *p_data++ = (AVRC_SUB_PANEL << AVRC_SUBTYPE_SHIFT); + *p_data++ = AVRC_OP_VENDOR; + AVRC_CO_ID_TO_BE_STREAM(p_data, AVRC_CO_METADATA); + } + else if (p_pkt->event == AVRC_OP_PASS_THRU) + { + /* add AVRCP Pass Through headers */ + p_start = ((UINT8 *)(p_pkt + 1) + p_pkt->offset); + p_pkt->offset -= AVRC_PASS_THRU_SIZE; + p_pkt->len += AVRC_PASS_THRU_SIZE; + p_data = (UINT8 *)(p_pkt + 1) + p_pkt->offset; + *p_data++ = (ctype & AVRC_CTYPE_MASK); + *p_data++ = (AVRC_SUB_PANEL << AVRC_SUBTYPE_SHIFT); + *p_data++ = AVRC_OP_PASS_THRU;/* opcode */ + *p_data++ = AVRC_ID_VENDOR; /* operation id */ + *p_data++ = 5; /* operation data len */ + AVRC_CO_ID_TO_BE_STREAM(p_data, AVRC_CO_METADATA); + } + + /* abandon previous fragments */ + p_fcb = &avrc_cb.fcb[handle]; + if (p_fcb->frag_enabled) + p_fcb->frag_enabled = FALSE; + + if (p_fcb->p_fmsg) + { + GKI_freebuf(p_fcb->p_fmsg); + p_fcb->p_fmsg = NULL; + } + + /* AVRCP spec has not defined any control channel commands that needs fragmentation at this level + * check for fragmentation only on the response */ + if ((cr == AVCT_RSP) && (chk_frag == TRUE)) + { + if (p_pkt->len > AVRC_MAX_CTRL_DATA_LEN) + { + int offset_len = MAX(AVCT_MSG_OFFSET, p_pkt->offset); + p_pkt_new = (BT_HDR *)GKI_getbuf((UINT16)(AVRC_PACKET_LEN + offset_len + + BT_HDR_SIZE)); + if (p_pkt_new && (p_start != NULL)) + { + p_fcb->frag_enabled = TRUE; + p_fcb->p_fmsg = p_pkt; + p_fcb->frag_pdu = *p_start; + p_pkt = p_pkt_new; + p_pkt_new = p_fcb->p_fmsg; + p_pkt->len = AVRC_MAX_CTRL_DATA_LEN; + p_pkt->offset = p_pkt_new->offset; + p_pkt->layer_specific = p_pkt_new->layer_specific; + p_pkt->event = p_pkt_new->event; + p_data = (UINT8 *)(p_pkt+1) + p_pkt->offset; + p_start -= AVRC_VENDOR_HDR_SIZE; + memcpy (p_data, p_start, AVRC_MAX_CTRL_DATA_LEN); + /* use AVRC start packet type */ + p_data += AVRC_VENDOR_HDR_SIZE; + p_data++; /* pdu */ + *p_data++ = AVRC_PKT_START; + /* 4 pdu, pkt_type & len */ + len = (AVRC_MAX_CTRL_DATA_LEN - AVRC_VENDOR_HDR_SIZE - AVRC_MIN_META_HDR_SIZE); + UINT16_TO_BE_STREAM(p_data, len); + + /* prepare the left over for as an end fragment */ + avrc_prep_end_frag (handle); + AVRC_TRACE_DEBUG ("%s p_pkt len:%d/%d, next len:%d", __func__, + p_pkt->len, len, p_fcb->p_fmsg->len ); + } + else + { + AVRC_TRACE_ERROR ("AVRC_MsgReq no buffers for fragmentation" ); + GKI_freebuf(p_pkt); + return AVRC_NO_RESOURCES; + } + } + } + + return AVCT_MsgReq( handle, label, cr, p_pkt); +#else + return AVRC_NO_RESOURCES; +#endif +} + + +/****************************************************************************** +** +** Function AVRC_PassCmd +** +** Description Send a PASS THROUGH command to the peer device. This +** function can only be called for controller role connections. +** Any response message from the peer is passed back through +** the tAVRC_MSG_CBACK callback function. +** +** Input Parameters: +** handle: Handle of this connection. +** +** label: Transaction label. +** +** p_msg: Pointer to PASS THROUGH message structure. +** +** Output Parameters: +** None. +** +** Returns AVRC_SUCCESS if successful. +** AVRC_BAD_HANDLE if handle is invalid. +** +******************************************************************************/ +UINT16 AVRC_PassCmd(UINT8 handle, UINT8 label, tAVRC_MSG_PASS *p_msg) +{ + BT_HDR *p_buf; + assert(p_msg != NULL); + if (p_msg) + { + p_msg->hdr.ctype = AVRC_CMD_CTRL; + p_buf = avrc_pass_msg(p_msg); + if (p_buf) + return AVCT_MsgReq( handle, label, AVCT_CMD, p_buf); + } + return AVRC_NO_RESOURCES; +} + +/****************************************************************************** +** +** Function AVRC_PassRsp +** +** Description Send a PASS THROUGH response to the peer device. This +** function can only be called for target role connections. +** This function must be called when a PASS THROUGH command +** message is received from the peer through the +** tAVRC_MSG_CBACK callback function. +** +** Input Parameters: +** handle: Handle of this connection. +** +** label: Transaction label. Must be the same value as +** passed with the command message in the callback function. +** +** p_msg: Pointer to PASS THROUGH message structure. +** +** Output Parameters: +** None. +** +** Returns AVRC_SUCCESS if successful. +** AVRC_BAD_HANDLE if handle is invalid. +** +******************************************************************************/ +UINT16 AVRC_PassRsp(UINT8 handle, UINT8 label, tAVRC_MSG_PASS *p_msg) +{ + BT_HDR *p_buf; + assert(p_msg != NULL); + if (p_msg) + { + p_buf = avrc_pass_msg(p_msg); + if (p_buf) + return AVCT_MsgReq( handle, label, AVCT_RSP, p_buf); + } + return AVRC_NO_RESOURCES; +} + diff --git a/components/bt/bluedroid/stack/avrc/avrc_bld_ct.c b/components/bt/bluedroid/stack/avrc/avrc_bld_ct.c new file mode 100755 index 0000000000..7e23967684 --- /dev/null +++ b/components/bt/bluedroid/stack/avrc/avrc_bld_ct.c @@ -0,0 +1,250 @@ +/****************************************************************************** + * + * Copyright (C) 2006-2013 Broadcom Corporation + * + * 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. + * + ******************************************************************************/ +#include + +#include "gki.h" +#include "avrc_api.h" +#include "avrc_defs.h" +#include "avrc_int.h" + +/***************************************************************************** +** Global data +*****************************************************************************/ + + +#if (AVRC_METADATA_INCLUDED == TRUE) +/******************************************************************************* +** +** Function avrc_bld_next_cmd +** +** Description This function builds the Request Continue or Abort command. +** +** Returns AVRC_STS_NO_ERROR, if the command is built successfully +** Otherwise, the error code. +** +*******************************************************************************/ +static tAVRC_STS avrc_bld_next_cmd (tAVRC_NEXT_CMD *p_cmd, BT_HDR *p_pkt) +{ + UINT8 *p_data, *p_start; + + AVRC_TRACE_API("avrc_bld_next_cmd"); + + /* get the existing length, if any, and also the num attributes */ + p_start = (UINT8 *)(p_pkt + 1) + p_pkt->offset; + p_data = p_start + 2; /* pdu + rsvd */ + + /* add fixed lenth 1 - pdu_id (1) */ + UINT16_TO_BE_STREAM(p_data, 1); + UINT8_TO_BE_STREAM(p_data, p_cmd->target_pdu); + p_pkt->len = (p_data - p_start); + + return AVRC_STS_NO_ERROR; +} + +/***************************************************************************** +** the following commands are introduced in AVRCP 1.4 +*****************************************************************************/ + +#if (AVRC_ADV_CTRL_INCLUDED == TRUE) +/******************************************************************************* +** +** Function avrc_bld_set_abs_volume_cmd +** +** Description This function builds the Set Absolute Volume command. +** +** Returns AVRC_STS_NO_ERROR, if the command is built successfully +** Otherwise, the error code. +** +*******************************************************************************/ +static tAVRC_STS avrc_bld_set_abs_volume_cmd (tAVRC_SET_VOLUME_CMD *p_cmd, BT_HDR *p_pkt) +{ + UINT8 *p_data, *p_start; + + AVRC_TRACE_API("avrc_bld_set_abs_volume_cmd"); + /* get the existing length, if any, and also the num attributes */ + p_start = (UINT8 *)(p_pkt + 1) + p_pkt->offset; + p_data = p_start + 2; /* pdu + rsvd */ + /* add fixed lenth 1 - volume (1) */ + UINT16_TO_BE_STREAM(p_data, 1); + UINT8_TO_BE_STREAM(p_data, (AVRC_MAX_VOLUME & p_cmd->volume)); + p_pkt->len = (p_data - p_start); + return AVRC_STS_NO_ERROR; +} + +/******************************************************************************* +** +** Function avrc_bld_vol_change_notfn +** +** Description This function builds the register notification for volume change. +** +** Returns AVRC_STS_NO_ERROR, if the command is built successfully +** Otherwise, the error code. +** +*******************************************************************************/ +static tAVRC_STS avrc_bld_vol_change_notfn(BT_HDR * p_pkt) +{ + UINT8 *p_data, *p_start; + + AVRC_TRACE_API("avrc_bld_vol_change"); + /* get the existing length, if any, and also the num attributes */ + // Set the notify value + p_start = (UINT8 *)(p_pkt + 1) + p_pkt->offset; + p_data = p_start + 2; /* pdu + rsvd */ + /* add fixed length 5 -*/ + UINT16_TO_BE_STREAM(p_data, 5); + UINT8_TO_BE_STREAM(p_data,AVRC_EVT_VOLUME_CHANGE); + UINT32_TO_BE_STREAM(p_data, 0); + p_pkt->len = (p_data - p_start); + return AVRC_STS_NO_ERROR; +} +#endif + +/******************************************************************************* +** +** Function avrc_bld_init_cmd_buffer +** +** Description This function initializes the command buffer based on PDU +** +** Returns NULL, if no GKI buffer or failure to build the message. +** Otherwise, the GKI buffer that contains the initialized message. +** +*******************************************************************************/ +static BT_HDR *avrc_bld_init_cmd_buffer(tAVRC_COMMAND *p_cmd) +{ + UINT16 offset = 0, chnl = AVCT_DATA_CTRL, len=AVRC_META_CMD_POOL_SIZE; + BT_HDR *p_pkt=NULL; + UINT8 opcode; + + opcode = avrc_opcode_from_pdu(p_cmd->pdu); + AVRC_TRACE_API("avrc_bld_init_cmd_buffer: pdu=%x, opcode=%x", p_cmd->pdu, opcode); + + switch (opcode) + { + case AVRC_OP_PASS_THRU: + offset = AVRC_MSG_PASS_THRU_OFFSET; + break; + + case AVRC_OP_VENDOR: + offset = AVRC_MSG_VENDOR_OFFSET; + break; + } + + /* allocate and initialize the buffer */ + p_pkt = (BT_HDR *)GKI_getbuf(len); + if (p_pkt) + { + UINT8 *p_data, *p_start; + + p_pkt->layer_specific = chnl; + p_pkt->event = opcode; + p_pkt->offset = offset; + p_data = (UINT8 *)(p_pkt + 1) + p_pkt->offset; + p_start = p_data; + + /* pass thru - group navigation - has a two byte op_id, so dont do it here */ + if (opcode != AVRC_OP_PASS_THRU) + *p_data++ = p_cmd->pdu; + + switch (opcode) + { + case AVRC_OP_VENDOR: + /* reserved 0, packet_type 0 */ + UINT8_TO_BE_STREAM(p_data, 0); + /* continue to the next "case to add length */ + /* add fixed lenth - 0 */ + UINT16_TO_BE_STREAM(p_data, 0); + break; + } + + p_pkt->len = (p_data - p_start); + } + p_cmd->cmd.opcode = opcode; + return p_pkt; +} + +/******************************************************************************* +** +** Function AVRC_BldCommand +** +** Description This function builds the given AVRCP command to the given +** GKI buffer +** +** Returns AVRC_STS_NO_ERROR, if the command is built successfully +** Otherwise, the error code. +** +*******************************************************************************/ +tAVRC_STS AVRC_BldCommand( tAVRC_COMMAND *p_cmd, BT_HDR **pp_pkt) +{ + tAVRC_STS status = AVRC_STS_BAD_PARAM; + BT_HDR *p_pkt; + BOOLEAN alloc = FALSE; + + AVRC_TRACE_API("AVRC_BldCommand: pdu=%x status=%x", p_cmd->cmd.pdu, p_cmd->cmd.status); + if (!p_cmd || !pp_pkt) + { + AVRC_TRACE_API("AVRC_BldCommand. Invalid parameters passed. p_cmd=%p, pp_pkt=%p", + p_cmd, pp_pkt); + return AVRC_STS_BAD_PARAM; + } + + if (*pp_pkt == NULL) + { + if ((*pp_pkt = avrc_bld_init_cmd_buffer(p_cmd)) == NULL) + { + AVRC_TRACE_API("AVRC_BldCommand: Failed to initialize command buffer"); + return AVRC_STS_INTERNAL_ERR; + } + alloc = TRUE; + } + status = AVRC_STS_NO_ERROR; + p_pkt = *pp_pkt; + + switch (p_cmd->pdu) + { + case AVRC_PDU_REQUEST_CONTINUATION_RSP: /* 0x40 */ + status = avrc_bld_next_cmd(&p_cmd->continu, p_pkt); + break; + + case AVRC_PDU_ABORT_CONTINUATION_RSP: /* 0x41 */ + status = avrc_bld_next_cmd(&p_cmd->abort, p_pkt); + break; +#if (AVRC_ADV_CTRL_INCLUDED == TRUE) + case AVRC_PDU_SET_ABSOLUTE_VOLUME: /* 0x50 */ + status = avrc_bld_set_abs_volume_cmd(&p_cmd->volume, p_pkt); + break; +#endif + + case AVRC_PDU_REGISTER_NOTIFICATION: /* 0x31 */ +#if (AVRC_ADV_CTRL_INCLUDED == TRUE) + if(AVRC_EVT_VOLUME_CHANGE==p_cmd->reg_notif.event_id) + status=avrc_bld_vol_change_notfn(p_pkt); +#endif + break; + + } + + if (alloc && (status != AVRC_STS_NO_ERROR) ) + { + GKI_freebuf(p_pkt); + *pp_pkt = NULL; + } + AVRC_TRACE_API("AVRC_BldCommand: returning %d", status); + return status; +} +#endif /* (AVRC_METADATA_INCLUDED == TRUE) */ + diff --git a/components/bt/bluedroid/stack/avrc/avrc_bld_tg.c b/components/bt/bluedroid/stack/avrc/avrc_bld_tg.c new file mode 100755 index 0000000000..32e513f2a1 --- /dev/null +++ b/components/bt/bluedroid/stack/avrc/avrc_bld_tg.c @@ -0,0 +1,916 @@ +/****************************************************************************** + * + * Copyright (C) 2003-2013 Broadcom Corporation + * + * 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. + * + ******************************************************************************/ +#include + +#include "gki.h" +#include "avrc_api.h" +#include "avrc_defs.h" +#include "avrc_int.h" + +/***************************************************************************** +** Global data +*****************************************************************************/ +#if (AVRC_METADATA_INCLUDED == TRUE) + +/******************************************************************************* +** +** Function avrc_bld_get_capability_rsp +** +** Description This function builds the Get Capability response. +** +** Returns AVRC_STS_NO_ERROR, if the response is built successfully +** Otherwise, the error code. +** +*******************************************************************************/ +static tAVRC_STS avrc_bld_get_capability_rsp (tAVRC_GET_CAPS_RSP *p_rsp, BT_HDR *p_pkt) +{ + UINT8 *p_data, *p_start, *p_len, *p_count; + UINT16 len = 0; + UINT8 xx; + UINT32 *p_company_id; + UINT8 *p_event_id; + tAVRC_STS status = AVRC_STS_NO_ERROR; + + if (!(AVRC_IS_VALID_CAP_ID(p_rsp->capability_id))) + { + AVRC_TRACE_ERROR("avrc_bld_get_capability_rsp bad parameter. p_rsp: %x", p_rsp); + status = AVRC_STS_BAD_PARAM; + return status; + } + + AVRC_TRACE_API("avrc_bld_get_capability_rsp"); + /* get the existing length, if any, and also the num attributes */ + p_start = (UINT8 *)(p_pkt + 1) + p_pkt->offset; + p_data = p_len = p_start + 2; /* pdu + rsvd */ + + BE_STREAM_TO_UINT16(len, p_data); + UINT8_TO_BE_STREAM(p_data, p_rsp->capability_id); + p_count = p_data; + + if (len == 0) + { + *p_count = p_rsp->count; + p_data++; + len = 2; /* move past the capability_id and count */ + } + else + { + p_data = p_start + p_pkt->len; + *p_count += p_rsp->count; + } + + if (p_rsp->capability_id == AVRC_CAP_COMPANY_ID) + { + p_company_id = p_rsp->param.company_id; + for (xx=0; xx< p_rsp->count; xx++) + { + UINT24_TO_BE_STREAM(p_data, p_company_id[xx]); + } + len += p_rsp->count * 3; + } + else + { + p_event_id = p_rsp->param.event_id; + *p_count = 0; + for (xx=0; xx< p_rsp->count; xx++) + { + if (AVRC_IS_VALID_EVENT_ID(p_event_id[xx])) + { + (*p_count)++; + UINT8_TO_BE_STREAM(p_data, p_event_id[xx]); + } + } + len += (*p_count); + } + UINT16_TO_BE_STREAM(p_len, len); + p_pkt->len = (p_data - p_start); + status = AVRC_STS_NO_ERROR; + + return status; +} + +/******************************************************************************* +** +** Function avrc_bld_list_app_settings_attr_rsp +** +** Description This function builds the List Application Settings Attribute +** response. +** +** Returns AVRC_STS_NO_ERROR, if the response is built successfully +** Otherwise, the error code. +** +*******************************************************************************/ +static tAVRC_STS avrc_bld_list_app_settings_attr_rsp (tAVRC_LIST_APP_ATTR_RSP *p_rsp, BT_HDR *p_pkt) +{ + UINT8 *p_data, *p_start, *p_len, *p_num; + UINT16 len = 0; + UINT8 xx; + + AVRC_TRACE_API("avrc_bld_list_app_settings_attr_rsp"); + /* get the existing length, if any, and also the num attributes */ + p_start = (UINT8 *)(p_pkt + 1) + p_pkt->offset; + p_data = p_len = p_start + 2; /* pdu + rsvd */ + + BE_STREAM_TO_UINT16(len, p_data); + p_num = p_data; + if (len == 0) + { + /* first time initialize the attribute count */ + *p_num = 0; + p_data++; + } + else + { + p_data = p_start + p_pkt->len; + } + + for (xx=0; xxnum_attr; xx++) + { + if(AVRC_IsValidPlayerAttr(p_rsp->attrs[xx])) + { + (*p_num)++; + UINT8_TO_BE_STREAM(p_data, p_rsp->attrs[xx]); + } + } + + len = *p_num + 1; + UINT16_TO_BE_STREAM(p_len, len); + p_pkt->len = (p_data - p_start); + + return AVRC_STS_NO_ERROR; +} + +/******************************************************************************* +** +** Function avrc_bld_list_app_settings_values_rsp +** +** Description This function builds the List Application Setting Values +** response. +** +** Returns AVRC_STS_NO_ERROR, if the response is built successfully +** Otherwise, the error code. +** +*******************************************************************************/ +static tAVRC_STS avrc_bld_list_app_settings_values_rsp (tAVRC_LIST_APP_VALUES_RSP *p_rsp, + BT_HDR *p_pkt) +{ + UINT8 *p_data, *p_start, *p_len, *p_num; + UINT8 xx; + UINT16 len; + + AVRC_TRACE_API("avrc_bld_list_app_settings_values_rsp"); + + p_start = (UINT8 *)(p_pkt + 1) + p_pkt->offset; + p_data = p_len = p_start + 2; /* pdu + rsvd */ + + /* get the existing length, if any, and also the num attributes */ + BE_STREAM_TO_UINT16(len, p_data); + p_num = p_data; + /* first time initialize the attribute count */ + if (len == 0) + { + *p_num = p_rsp->num_val; + p_data++; + } + else + { + p_data = p_start + p_pkt->len; + *p_num += p_rsp->num_val; + } + + + for (xx=0; xxnum_val; xx++) + { + UINT8_TO_BE_STREAM(p_data, p_rsp->vals[xx]); + } + + len = *p_num + 1; + UINT16_TO_BE_STREAM(p_len, len); + p_pkt->len = (p_data - p_start); + return AVRC_STS_NO_ERROR; +} + +/******************************************************************************* +** +** Function avrc_bld_get_cur_app_setting_value_rsp +** +** Description This function builds the Get Current Application Setting Value +** response. +** +** Returns AVRC_STS_NO_ERROR, if the response is built successfully +** Otherwise, the error code. +** +*******************************************************************************/ +static tAVRC_STS avrc_bld_get_cur_app_setting_value_rsp (tAVRC_GET_CUR_APP_VALUE_RSP *p_rsp, + BT_HDR *p_pkt) +{ + UINT8 *p_data, *p_start, *p_len, *p_count; + UINT16 len; + UINT8 xx; + + if (!p_rsp->p_vals) + { + AVRC_TRACE_ERROR("avrc_bld_get_cur_app_setting_value_rsp NULL parameter"); + return AVRC_STS_BAD_PARAM; + } + + AVRC_TRACE_API("avrc_bld_get_cur_app_setting_value_rsp"); + /* get the existing length, if any, and also the num attributes */ + p_start = (UINT8 *)(p_pkt + 1) + p_pkt->offset; + p_data = p_len = p_start + 2; /* pdu + rsvd */ + + BE_STREAM_TO_UINT16(len, p_data); + p_count = p_data; + if (len == 0) + { + /* first time initialize the attribute count */ + *p_count = 0; + p_data++; + } + else + { + p_data = p_start + p_pkt->len; + } + + for (xx=0; xxnum_val; xx++) + { + if (avrc_is_valid_player_attrib_value(p_rsp->p_vals[xx].attr_id, p_rsp->p_vals[xx].attr_val)) + { + (*p_count)++; + UINT8_TO_BE_STREAM(p_data, p_rsp->p_vals[xx].attr_id); + UINT8_TO_BE_STREAM(p_data, p_rsp->p_vals[xx].attr_val); + } + } + len = ((*p_count) << 1) + 1; + UINT16_TO_BE_STREAM(p_len, len); + p_pkt->len = (p_data - p_start); + + return AVRC_STS_NO_ERROR; +} + +/******************************************************************************* +** +** Function avrc_bld_set_app_setting_value_rsp +** +** Description This function builds the Set Application Setting Value +** response. +** +** Returns AVRC_STS_NO_ERROR, if the response is built successfully +** Otherwise, the error code. +** +*******************************************************************************/ +static tAVRC_STS avrc_bld_set_app_setting_value_rsp (tAVRC_RSP *p_rsp, BT_HDR *p_pkt) +{ + UNUSED(p_rsp); + UNUSED(p_pkt); + + /* nothing to be added. */ + AVRC_TRACE_API("avrc_bld_set_app_setting_value_rsp"); + return AVRC_STS_NO_ERROR; +} + +/******************************************************************************* +** +** Function avrc_bld_app_setting_text_rsp +** +** Description This function builds the Get Application Settings Attribute Text +** or Get Application Settings Value Text response. +** +** Returns AVRC_STS_NO_ERROR, if the response is built successfully +** Otherwise, the error code. +** +*******************************************************************************/ +static tAVRC_STS avrc_bld_app_setting_text_rsp (tAVRC_GET_APP_ATTR_TXT_RSP *p_rsp, BT_HDR *p_pkt) +{ + UINT8 *p_data, *p_start, *p_len, *p_count; + UINT16 len, len_left; + UINT8 xx; + tAVRC_STS sts = AVRC_STS_NO_ERROR; + UINT8 num_added = 0; + + if (!p_rsp->p_attrs) + { + AVRC_TRACE_ERROR("avrc_bld_app_setting_text_rsp NULL parameter"); + return AVRC_STS_BAD_PARAM; + } + /* get the existing length, if any, and also the num attributes */ + p_start = (UINT8 *)(p_pkt + 1) + p_pkt->offset; + p_data = p_len = p_start + 2; /* pdu + rsvd */ + len_left = GKI_get_buf_size(p_pkt) - BT_HDR_SIZE - p_pkt->offset - p_pkt->len; + + BE_STREAM_TO_UINT16(len, p_data); + p_count = p_data; + + if (len == 0) + { + *p_count = 0; + p_data++; + } + else + { + p_data = p_start + p_pkt->len; + } + + for (xx=0; xxnum_attr; xx++) + { + if (len_left < (p_rsp->p_attrs[xx].str_len + 4)) + { + AVRC_TRACE_ERROR("avrc_bld_app_setting_text_rsp out of room (str_len:%d, left:%d)", + xx, p_rsp->p_attrs[xx].str_len, len_left); + p_rsp->num_attr = num_added; + sts = AVRC_STS_INTERNAL_ERR; + break; + } + if ( !p_rsp->p_attrs[xx].str_len || !p_rsp->p_attrs[xx].p_str ) + { + AVRC_TRACE_ERROR("avrc_bld_app_setting_text_rsp NULL attr text[%d]", xx); + continue; + } + UINT8_TO_BE_STREAM(p_data, p_rsp->p_attrs[xx].attr_id); + UINT16_TO_BE_STREAM(p_data, p_rsp->p_attrs[xx].charset_id); + UINT8_TO_BE_STREAM(p_data, p_rsp->p_attrs[xx].str_len); + ARRAY_TO_BE_STREAM(p_data, p_rsp->p_attrs[xx].p_str, p_rsp->p_attrs[xx].str_len); + (*p_count)++; + num_added++; + } + len = p_data - p_count; + UINT16_TO_BE_STREAM(p_len, len); + p_pkt->len = (p_data - p_start); + + return sts; +} + +/******************************************************************************* +** +** Function avrc_bld_get_app_setting_attr_text_rsp +** +** Description This function builds the Get Application Setting Attribute Text +** response. +** +** Returns AVRC_STS_NO_ERROR, if the response is built successfully +** Otherwise, the error code. +** +*******************************************************************************/ +static tAVRC_STS avrc_bld_get_app_setting_attr_text_rsp (tAVRC_GET_APP_ATTR_TXT_RSP *p_rsp, + BT_HDR *p_pkt) +{ + AVRC_TRACE_API("avrc_bld_get_app_setting_attr_text_rsp"); + return avrc_bld_app_setting_text_rsp(p_rsp, p_pkt); +} + +/******************************************************************************* +** +** Function avrc_bld_get_app_setting_value_text_rsp +** +** Description This function builds the Get Application Setting Value Text +** response. +** +** Returns AVRC_STS_NO_ERROR, if the response is built successfully +** Otherwise, the error code. +** +*******************************************************************************/ +static tAVRC_STS avrc_bld_get_app_setting_value_text_rsp (tAVRC_GET_APP_ATTR_TXT_RSP *p_rsp, + BT_HDR *p_pkt) +{ + AVRC_TRACE_API("avrc_bld_get_app_setting_value_text_rsp"); + return avrc_bld_app_setting_text_rsp(p_rsp, p_pkt); +} + +/******************************************************************************* +** +** Function avrc_bld_inform_charset_rsp +** +** Description This function builds the Inform Displayable Character Set +** response. +** +** Returns AVRC_STS_NO_ERROR, if the response is built successfully +** Otherwise, the error code. +** +*******************************************************************************/ +static tAVRC_STS avrc_bld_inform_charset_rsp (tAVRC_RSP *p_rsp, BT_HDR *p_pkt) +{ + UNUSED(p_rsp); + UNUSED(p_pkt); + + /* nothing to be added. */ + AVRC_TRACE_API("avrc_bld_inform_charset_rsp"); + return AVRC_STS_NO_ERROR; +} + +/******************************************************************************* +** +** Function avrc_bld_inform_battery_status_rsp +** +** Description This function builds the Inform Battery Status +** response. +** +** Returns AVRC_STS_NO_ERROR, if the response is built successfully +** Otherwise, the error code. +** +*******************************************************************************/ +static tAVRC_STS avrc_bld_inform_battery_status_rsp (tAVRC_RSP *p_rsp, BT_HDR *p_pkt) +{ + UNUSED(p_rsp); + UNUSED(p_pkt); + + /* nothing to be added. */ + AVRC_TRACE_API("avrc_bld_inform_battery_status_rsp"); + return AVRC_STS_NO_ERROR; +} + +/******************************************************************************* +** +** Function avrc_bld_get_elem_attrs_rsp +** +** Description This function builds the Get Element Attributes +** response. +** +** Returns AVRC_STS_NO_ERROR, if the response is built successfully +** Otherwise, the error code. +** +*******************************************************************************/ +static tAVRC_STS avrc_bld_get_elem_attrs_rsp (tAVRC_GET_ELEM_ATTRS_RSP *p_rsp, BT_HDR *p_pkt) +{ + UINT8 *p_data, *p_start, *p_len, *p_count; + UINT16 len; + UINT8 xx; + + AVRC_TRACE_API("avrc_bld_get_elem_attrs_rsp"); + if (!p_rsp->p_attrs) + { + AVRC_TRACE_ERROR("avrc_bld_get_elem_attrs_rsp NULL parameter"); + return AVRC_STS_BAD_PARAM; + } + + /* get the existing length, if any, and also the num attributes */ + p_start = (UINT8 *)(p_pkt + 1) + p_pkt->offset; + p_data = p_len = p_start + 2; /* pdu + rsvd */ + + BE_STREAM_TO_UINT16(len, p_data); + p_count = p_data; + + if (len == 0) + { + *p_count = 0; + p_data++; + } + else + { + p_data = p_start + p_pkt->len; + } + + for (xx=0; xxnum_attr; xx++) + { + if (!AVRC_IS_VALID_MEDIA_ATTRIBUTE(p_rsp->p_attrs[xx].attr_id)) + { + AVRC_TRACE_ERROR("avrc_bld_get_elem_attrs_rsp invalid attr id[%d]: %d", xx, p_rsp->p_attrs[xx].attr_id); + continue; + } + if ( !p_rsp->p_attrs[xx].name.p_str ) + { + p_rsp->p_attrs[xx].name.str_len = 0; + } + UINT32_TO_BE_STREAM(p_data, p_rsp->p_attrs[xx].attr_id); + UINT16_TO_BE_STREAM(p_data, p_rsp->p_attrs[xx].name.charset_id); + UINT16_TO_BE_STREAM(p_data, p_rsp->p_attrs[xx].name.str_len); + ARRAY_TO_BE_STREAM(p_data, p_rsp->p_attrs[xx].name.p_str, p_rsp->p_attrs[xx].name.str_len); + (*p_count)++; + } + len = p_data - p_count; + UINT16_TO_BE_STREAM(p_len, len); + p_pkt->len = (p_data - p_start); + return AVRC_STS_NO_ERROR; +} + +/******************************************************************************* +** +** Function avrc_bld_get_play_status_rsp +** +** Description This function builds the Get Play Status +** response. +** +** Returns AVRC_STS_NO_ERROR, if the response is built successfully +** Otherwise, the error code. +** +*******************************************************************************/ +static tAVRC_STS avrc_bld_get_play_status_rsp (tAVRC_GET_PLAY_STATUS_RSP *p_rsp, BT_HDR *p_pkt) +{ + UINT8 *p_data, *p_start; + + AVRC_TRACE_API("avrc_bld_get_play_status_rsp"); + p_start = (UINT8 *)(p_pkt + 1) + p_pkt->offset; + p_data = p_start + 2; + + /* add fixed lenth - song len(4) + song position(4) + status(1) */ + UINT16_TO_BE_STREAM(p_data, 9); + UINT32_TO_BE_STREAM(p_data, p_rsp->song_len); + UINT32_TO_BE_STREAM(p_data, p_rsp->song_pos); + UINT8_TO_BE_STREAM(p_data, p_rsp->play_status); + p_pkt->len = (p_data - p_start); + + return AVRC_STS_NO_ERROR; +} + +/******************************************************************************* +** +** Function avrc_bld_notify_rsp +** +** Description This function builds the Notification response. +** +** Returns AVRC_STS_NO_ERROR, if the response is built successfully +** Otherwise, the error code. +** +*******************************************************************************/ +static tAVRC_STS avrc_bld_notify_rsp (tAVRC_REG_NOTIF_RSP *p_rsp, BT_HDR *p_pkt) +{ + UINT8 *p_data, *p_start; + UINT8 *p_len; + UINT16 len = 0; + UINT8 xx; + tAVRC_STS status = AVRC_STS_NO_ERROR; + + AVRC_TRACE_API("avrc_bld_notify_rsp"); + + p_start = (UINT8 *)(p_pkt + 1) + p_pkt->offset; + p_data = p_len = p_start + 2; /* pdu + rsvd */ + p_data += 2; + + UINT8_TO_BE_STREAM(p_data, p_rsp->event_id); + switch (p_rsp->event_id) + { + case AVRC_EVT_PLAY_STATUS_CHANGE: /* 0x01 */ + /* p_rsp->param.play_status >= AVRC_PLAYSTATE_STOPPED is always TRUE */ + if ((p_rsp->param.play_status <= AVRC_PLAYSTATE_REV_SEEK) || + (p_rsp->param.play_status == AVRC_PLAYSTATE_ERROR) ) + { + UINT8_TO_BE_STREAM(p_data, p_rsp->param.play_status); + len = 2; + } + else + { + AVRC_TRACE_ERROR("bad play state"); + status = AVRC_STS_BAD_PARAM; + } + break; + + case AVRC_EVT_TRACK_CHANGE: /* 0x02 */ + ARRAY_TO_BE_STREAM(p_data, p_rsp->param.track, AVRC_UID_SIZE); + len = (UINT8)(AVRC_UID_SIZE + 1); + break; + + case AVRC_EVT_TRACK_REACHED_END: /* 0x03 */ + case AVRC_EVT_TRACK_REACHED_START: /* 0x04 */ + len = 1; + break; + + case AVRC_EVT_PLAY_POS_CHANGED: /* 0x05 */ + UINT32_TO_BE_STREAM(p_data, p_rsp->param.play_pos); + len = 5; + break; + + case AVRC_EVT_BATTERY_STATUS_CHANGE: /* 0x06 */ + if (AVRC_IS_VALID_BATTERY_STATUS(p_rsp->param.battery_status)) + { + UINT8_TO_BE_STREAM(p_data, p_rsp->param.battery_status); + len = 2; + } + else + { + AVRC_TRACE_ERROR("bad battery status"); + status = AVRC_STS_BAD_PARAM; + } + break; + + case AVRC_EVT_SYSTEM_STATUS_CHANGE: /* 0x07 */ + if (AVRC_IS_VALID_SYSTEM_STATUS(p_rsp->param.system_status)) + { + UINT8_TO_BE_STREAM(p_data, p_rsp->param.system_status); + len = 2; + } + else + { + AVRC_TRACE_ERROR("bad system status"); + status = AVRC_STS_BAD_PARAM; + } + break; + + case AVRC_EVT_APP_SETTING_CHANGE: /* 0x08 */ + if (p_rsp->param.player_setting.num_attr > AVRC_MAX_APP_SETTINGS) + p_rsp->param.player_setting.num_attr = AVRC_MAX_APP_SETTINGS; + + if (p_rsp->param.player_setting.num_attr > 0) + { + UINT8_TO_BE_STREAM(p_data, p_rsp->param.player_setting.num_attr); + len = 2; + for (xx=0; xxparam.player_setting.num_attr; xx++) + { + if (avrc_is_valid_player_attrib_value(p_rsp->param.player_setting.attr_id[xx], + p_rsp->param.player_setting.attr_value[xx])) + { + UINT8_TO_BE_STREAM(p_data, p_rsp->param.player_setting.attr_id[xx]); + UINT8_TO_BE_STREAM(p_data, p_rsp->param.player_setting.attr_value[xx]); + } + else + { + AVRC_TRACE_ERROR("bad player app seeting attribute or value"); + status = AVRC_STS_BAD_PARAM; + break; + } + len += 2; + } + } + else + status = AVRC_STS_BAD_PARAM; + break; + + default: + status = AVRC_STS_BAD_PARAM; + AVRC_TRACE_ERROR("unknown event_id"); + } + + UINT16_TO_BE_STREAM(p_len, len); + p_pkt->len = (p_data - p_start); + + return status; +} + +/******************************************************************************* +** +** Function avrc_bld_next_rsp +** +** Description This function builds the Request Continue or Abort +** response. +** +** Returns AVRC_STS_NO_ERROR, if the response is built successfully +** Otherwise, the error code. +** +*******************************************************************************/ +static tAVRC_STS avrc_bld_next_rsp (tAVRC_RSP *p_rsp, BT_HDR *p_pkt) +{ + UNUSED(p_rsp); + UNUSED(p_pkt); + + /* nothing to be added. */ + AVRC_TRACE_API("avrc_bld_next_rsp"); + return AVRC_STS_NO_ERROR; +} + +/******************************************************************************* +** +** Function avrc_bld_group_navigation_rsp +** +** Description This function builds the Group Navigation +** response. +** +** Returns AVRC_STS_NO_ERROR, if the response is built successfully +** Otherwise, the error code. +** +*******************************************************************************/ +tAVRC_STS avrc_bld_group_navigation_rsp (UINT16 navi_id, BT_HDR *p_pkt) +{ + UINT8 *p_data; + + if (!AVRC_IS_VALID_GROUP(navi_id)) + { + AVRC_TRACE_ERROR("avrc_bld_group_navigation_rsp bad navigation op id: %d", navi_id); + return AVRC_STS_BAD_PARAM; + } + + AVRC_TRACE_API("avrc_bld_group_navigation_rsp"); + p_data = (UINT8 *)(p_pkt+1) + p_pkt->offset; + UINT16_TO_BE_STREAM(p_data, navi_id); + p_pkt->len = 2; + return AVRC_STS_NO_ERROR; +} + +/******************************************************************************* +** +** Function avrc_bld_rejected_rsp +** +** Description This function builds the General Response response. +** +** Returns AVRC_STS_NO_ERROR, if the response is built successfully +** Otherwise, the error code. +** +*******************************************************************************/ +static tAVRC_STS avrc_bld_rejected_rsp( tAVRC_RSP *p_rsp, BT_HDR *p_pkt ) +{ + UINT8 *p_data, *p_start; + + AVRC_TRACE_API("avrc_bld_rejected_rsp: status=%d, pdu:x%x", p_rsp->status, p_rsp->pdu); + + p_start = (UINT8 *)(p_pkt + 1) + p_pkt->offset; + p_data = p_start + 2; + AVRC_TRACE_DEBUG("pdu:x%x", *p_start); + + UINT16_TO_BE_STREAM(p_data, 1); + UINT8_TO_BE_STREAM(p_data, p_rsp->status); + p_pkt->len = p_data - p_start; + + return AVRC_STS_NO_ERROR; +} + +/******************************************************************************* +** +** Function avrc_bld_init_rsp_buffer +** +** Description This function initializes the response buffer based on PDU +** +** Returns NULL, if no GKI buffer or failure to build the message. +** Otherwise, the GKI buffer that contains the initialized message. +** +*******************************************************************************/ +static BT_HDR *avrc_bld_init_rsp_buffer(tAVRC_RESPONSE *p_rsp) +{ + UINT16 offset = AVRC_MSG_PASS_THRU_OFFSET, chnl = AVCT_DATA_CTRL, len=AVRC_META_CMD_POOL_SIZE; + BT_HDR *p_pkt=NULL; + UINT8 opcode = avrc_opcode_from_pdu(p_rsp->pdu); + + AVRC_TRACE_API("avrc_bld_init_rsp_buffer: pdu=%x, opcode=%x/%x", p_rsp->pdu, opcode, + p_rsp->rsp.opcode); + if (opcode != p_rsp->rsp.opcode && p_rsp->rsp.status != AVRC_STS_NO_ERROR && + avrc_is_valid_opcode(p_rsp->rsp.opcode)) + { + opcode = p_rsp->rsp.opcode; + AVRC_TRACE_API("opcode=%x", opcode); + } + + switch (opcode) + { + case AVRC_OP_PASS_THRU: + offset = AVRC_MSG_PASS_THRU_OFFSET; + break; + + case AVRC_OP_VENDOR: + offset = AVRC_MSG_VENDOR_OFFSET; + if (p_rsp->pdu == AVRC_PDU_GET_ELEMENT_ATTR) + len = AVRC_BROWSE_POOL_SIZE; + break; + } + + /* allocate and initialize the buffer */ + p_pkt = (BT_HDR *)GKI_getbuf(len); + if (p_pkt) + { + UINT8 *p_data, *p_start; + + p_pkt->layer_specific = chnl; + p_pkt->event = opcode; + p_pkt->offset = offset; + p_data = (UINT8 *)(p_pkt + 1) + p_pkt->offset; + p_start = p_data; + + /* pass thru - group navigation - has a two byte op_id, so dont do it here */ + if (opcode != AVRC_OP_PASS_THRU) + *p_data++ = p_rsp->pdu; + + switch (opcode) + { + case AVRC_OP_VENDOR: + /* reserved 0, packet_type 0 */ + UINT8_TO_BE_STREAM(p_data, 0); + /* continue to the next "case to add length */ + /* add fixed lenth - 0 */ + UINT16_TO_BE_STREAM(p_data, 0); + break; + } + + p_pkt->len = (p_data - p_start); + } + p_rsp->rsp.opcode = opcode; + return p_pkt; +} + +/******************************************************************************* +** +** Function AVRC_BldResponse +** +** Description This function builds the given AVRCP response to the given +** GKI buffer +** +** Returns AVRC_STS_NO_ERROR, if the response is built successfully +** Otherwise, the error code. +** +*******************************************************************************/ +tAVRC_STS AVRC_BldResponse( UINT8 handle, tAVRC_RESPONSE *p_rsp, BT_HDR **pp_pkt) +{ + tAVRC_STS status = AVRC_STS_BAD_PARAM; + BT_HDR *p_pkt; + BOOLEAN alloc = FALSE; + UNUSED(handle); + + if (!p_rsp || !pp_pkt) + { + AVRC_TRACE_API("AVRC_BldResponse. Invalid parameters passed. p_rsp=%p, pp_pkt=%p", + p_rsp, pp_pkt); + return AVRC_STS_BAD_PARAM; + } + + if (*pp_pkt == NULL) + { + if ((*pp_pkt = avrc_bld_init_rsp_buffer(p_rsp)) == NULL) + { + AVRC_TRACE_API("AVRC_BldResponse: Failed to initialize response buffer"); + return AVRC_STS_INTERNAL_ERR; + } + alloc = TRUE; + } + status = AVRC_STS_NO_ERROR; + p_pkt = *pp_pkt; + + AVRC_TRACE_API("AVRC_BldResponse: pdu=%x status=%x", p_rsp->rsp.pdu, p_rsp->rsp.status); + if (p_rsp->rsp.status != AVRC_STS_NO_ERROR) + { + return( avrc_bld_rejected_rsp(&p_rsp->rsp, p_pkt) ); + } + + switch (p_rsp->pdu) + { + case AVRC_PDU_NEXT_GROUP: + case AVRC_PDU_PREV_GROUP: + status = avrc_bld_group_navigation_rsp(p_rsp->pdu, p_pkt); + break; + + case AVRC_PDU_GET_CAPABILITIES: + status = avrc_bld_get_capability_rsp(&p_rsp->get_caps, p_pkt); + break; + + case AVRC_PDU_LIST_PLAYER_APP_ATTR: + status = avrc_bld_list_app_settings_attr_rsp(&p_rsp->list_app_attr, p_pkt); + break; + + case AVRC_PDU_LIST_PLAYER_APP_VALUES: + status = avrc_bld_list_app_settings_values_rsp(&p_rsp->list_app_values, p_pkt); + break; + + case AVRC_PDU_GET_CUR_PLAYER_APP_VALUE: + status = avrc_bld_get_cur_app_setting_value_rsp(&p_rsp->get_cur_app_val, p_pkt); + break; + + case AVRC_PDU_SET_PLAYER_APP_VALUE: + status = avrc_bld_set_app_setting_value_rsp(&p_rsp->set_app_val, p_pkt); + break; + + case AVRC_PDU_GET_PLAYER_APP_ATTR_TEXT: + status = avrc_bld_get_app_setting_attr_text_rsp(&p_rsp->get_app_attr_txt, p_pkt); + break; + + case AVRC_PDU_GET_PLAYER_APP_VALUE_TEXT: + status = avrc_bld_get_app_setting_value_text_rsp(&p_rsp->get_app_val_txt, p_pkt); + break; + + case AVRC_PDU_INFORM_DISPLAY_CHARSET: + status = avrc_bld_inform_charset_rsp(&p_rsp->inform_charset, p_pkt); + break; + + case AVRC_PDU_INFORM_BATTERY_STAT_OF_CT: + status = avrc_bld_inform_battery_status_rsp(&p_rsp->inform_battery_status, p_pkt); + break; + + case AVRC_PDU_GET_ELEMENT_ATTR: + status = avrc_bld_get_elem_attrs_rsp(&p_rsp->get_elem_attrs, p_pkt); + break; + + case AVRC_PDU_GET_PLAY_STATUS: + status = avrc_bld_get_play_status_rsp(&p_rsp->get_play_status, p_pkt); + break; + + case AVRC_PDU_REGISTER_NOTIFICATION: + status = avrc_bld_notify_rsp(&p_rsp->reg_notif, p_pkt); + break; + + case AVRC_PDU_REQUEST_CONTINUATION_RSP: /* 0x40 */ + status = avrc_bld_next_rsp(&p_rsp->continu, p_pkt); + break; + + case AVRC_PDU_ABORT_CONTINUATION_RSP: /* 0x41 */ + status = avrc_bld_next_rsp(&p_rsp->abort, p_pkt); + break; + } + + if (alloc && (status != AVRC_STS_NO_ERROR) ) + { + GKI_freebuf(p_pkt); + *pp_pkt = NULL; + } + AVRC_TRACE_API("AVRC_BldResponse: returning %d", status); + return status; +} + +#endif /* (AVRC_METADATA_INCLUDED == TRUE)*/ + diff --git a/components/bt/bluedroid/stack/avrc/avrc_opt.c b/components/bt/bluedroid/stack/avrc/avrc_opt.c new file mode 100755 index 0000000000..de1a00cef8 --- /dev/null +++ b/components/bt/bluedroid/stack/avrc/avrc_opt.c @@ -0,0 +1,232 @@ +/****************************************************************************** + * + * Copyright (C) 2003-2012 Broadcom Corporation + * + * 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. + * + ******************************************************************************/ + +/****************************************************************************** + * + * Interface to AVRCP optional commands + * + ******************************************************************************/ +#include +#include "bt_trace.h" +#include "gki.h" +#include "avrc_api.h" +#include "avrc_int.h" + +/****************************************************************************** +** +** Function avrc_vendor_msg +** +** Description Compose a VENDOR DEPENDENT command according to p_msg +** +** Input Parameters: +** p_msg: Pointer to VENDOR DEPENDENT message structure. +** +** Output Parameters: +** None. +** +** Returns pointer to a valid GKI buffer if successful. +** NULL if p_msg is NULL. +** +******************************************************************************/ +static BT_HDR * avrc_vendor_msg(tAVRC_MSG_VENDOR *p_msg) +{ + BT_HDR *p_cmd; + UINT8 *p_data; + + assert(p_msg != NULL); + +#if AVRC_METADATA_INCLUDED == TRUE + assert(AVRC_META_CMD_POOL_SIZE > (AVRC_MIN_CMD_LEN+p_msg->vendor_len)); + if ((p_cmd = (BT_HDR *) GKI_getpoolbuf(AVRC_META_CMD_POOL_ID)) != NULL) +#else + assert(AVRC_CMD_POOL_SIZE > (AVRC_MIN_CMD_LEN+p_msg->vendor_len)); + if ((p_cmd = (BT_HDR *) GKI_getpoolbuf(AVRC_CMD_POOL_ID)) != NULL) +#endif + { + p_cmd->offset = AVCT_MSG_OFFSET; + p_data = (UINT8 *)(p_cmd + 1) + p_cmd->offset; + *p_data++ = (p_msg->hdr.ctype & AVRC_CTYPE_MASK); + *p_data++ = (p_msg->hdr.subunit_type << AVRC_SUBTYPE_SHIFT) | p_msg->hdr.subunit_id; + *p_data++ = AVRC_OP_VENDOR; + AVRC_CO_ID_TO_BE_STREAM(p_data, p_msg->company_id); + if(p_msg->vendor_len && p_msg->p_vendor_data) + { + memcpy(p_data, p_msg->p_vendor_data, p_msg->vendor_len); + } + p_cmd->len = (UINT16) (p_data + p_msg->vendor_len - (UINT8 *)(p_cmd + 1) - p_cmd->offset); + p_cmd->layer_specific = AVCT_DATA_CTRL; + } + return p_cmd; +} + +/****************************************************************************** +** +** Function AVRC_UnitCmd +** +** Description Send a UNIT INFO command to the peer device. This +** function can only be called for controller role connections. +** Any response message from the peer is passed back through +** the tAVRC_MSG_CBACK callback function. +** +** Input Parameters: +** handle: Handle of this connection. +** +** label: Transaction label. +** +** Output Parameters: +** None. +** +** Returns AVRC_SUCCESS if successful. +** AVRC_BAD_HANDLE if handle is invalid. +** +******************************************************************************/ +UINT16 AVRC_UnitCmd(UINT8 handle, UINT8 label) +{ + BT_HDR *p_cmd; + UINT8 *p_data; + + if ((p_cmd = (BT_HDR *) GKI_getpoolbuf(AVRC_CMD_POOL_ID)) != NULL) + { + p_cmd->offset = AVCT_MSG_OFFSET; + p_data = (UINT8 *)(p_cmd + 1) + p_cmd->offset; + *p_data++ = AVRC_CMD_STATUS; + /* unit & id ignore */ + *p_data++ = (AVRC_SUB_UNIT << AVRC_SUBTYPE_SHIFT) | AVRC_SUBID_IGNORE; + *p_data++ = AVRC_OP_UNIT_INFO; + memset(p_data, AVRC_CMD_OPRND_PAD, AVRC_UNIT_OPRND_BYTES); + p_cmd->len = p_data + AVRC_UNIT_OPRND_BYTES - (UINT8 *)(p_cmd + 1) - p_cmd->offset; + p_cmd->layer_specific = AVCT_DATA_CTRL; + } + return AVCT_MsgReq( handle, label, AVCT_CMD, p_cmd); +} + +/****************************************************************************** +** +** Function AVRC_SubCmd +** +** Description Send a SUBUNIT INFO command to the peer device. This +** function can only be called for controller role connections. +** Any response message from the peer is passed back through +** the tAVRC_MSG_CBACK callback function. +** +** Input Parameters: +** handle: Handle of this connection. +** +** label: Transaction label. +** +** page: Specifies which part of the subunit type table +** is requested. For AVRCP it is typically zero. +** Value range is 0-7. +** +** Output Parameters: +** None. +** +** Returns AVRC_SUCCESS if successful. +** AVRC_BAD_HANDLE if handle is invalid. +** +******************************************************************************/ +UINT16 AVRC_SubCmd(UINT8 handle, UINT8 label, UINT8 page) +{ + BT_HDR *p_cmd; + UINT8 *p_data; + + if ((p_cmd = (BT_HDR *) GKI_getpoolbuf(AVRC_CMD_POOL_ID)) != NULL) + { + p_cmd->offset = AVCT_MSG_OFFSET; + p_data = (UINT8 *)(p_cmd + 1) + p_cmd->offset; + *p_data++ = AVRC_CMD_STATUS; + /* unit & id ignore */ + *p_data++ = (AVRC_SUB_UNIT << AVRC_SUBTYPE_SHIFT) | AVRC_SUBID_IGNORE; + *p_data++ = AVRC_OP_SUB_INFO; + *p_data++ = ((page&AVRC_SUB_PAGE_MASK) << AVRC_SUB_PAGE_SHIFT) | AVRC_SUB_EXT_CODE; + memset(p_data, AVRC_CMD_OPRND_PAD, AVRC_SUB_OPRND_BYTES); + p_cmd->len = p_data + AVRC_SUB_OPRND_BYTES - (UINT8 *)(p_cmd + 1) - p_cmd->offset; + p_cmd->layer_specific = AVCT_DATA_CTRL; + } + return AVCT_MsgReq( handle, label, AVCT_CMD, p_cmd); +} + +/****************************************************************************** +** +** Function AVRC_VendorCmd +** +** Description Send a VENDOR DEPENDENT command to the peer device. This +** function can only be called for controller role connections. +** Any response message from the peer is passed back through +** the tAVRC_MSG_CBACK callback function. +** +** Input Parameters: +** handle: Handle of this connection. +** +** label: Transaction label. +** +** p_msg: Pointer to VENDOR DEPENDENT message structure. +** +** Output Parameters: +** None. +** +** Returns AVRC_SUCCESS if successful. +** AVRC_BAD_HANDLE if handle is invalid. +** +******************************************************************************/ +UINT16 AVRC_VendorCmd(UINT8 handle, UINT8 label, tAVRC_MSG_VENDOR *p_msg) +{ + BT_HDR *p_buf = avrc_vendor_msg(p_msg); + if (p_buf) + return AVCT_MsgReq( handle, label, AVCT_CMD, p_buf); + else + return AVCT_NO_RESOURCES; +} + + +/****************************************************************************** +** +** Function AVRC_VendorRsp +** +** Description Send a VENDOR DEPENDENT response to the peer device. This +** function can only be called for target role connections. +** This function must be called when a VENDOR DEPENDENT +** command message is received from the peer through the +** tAVRC_MSG_CBACK callback function. +** +** Input Parameters: +** handle: Handle of this connection. +** +** label: Transaction label. Must be the same value as +** passed with the command message in the callback function. +** +** p_msg: Pointer to VENDOR DEPENDENT message structure. +** +** Output Parameters: +** None. +** +** Returns AVRC_SUCCESS if successful. +** AVRC_BAD_HANDLE if handle is invalid. +** +******************************************************************************/ +UINT16 AVRC_VendorRsp(UINT8 handle, UINT8 label, tAVRC_MSG_VENDOR *p_msg) +{ + BT_HDR *p_buf = avrc_vendor_msg(p_msg); + if (p_buf) + return AVCT_MsgReq( handle, label, AVCT_RSP, p_buf); + else + return AVCT_NO_RESOURCES; +} + + + diff --git a/components/bt/bluedroid/stack/avrc/avrc_pars_ct.c b/components/bt/bluedroid/stack/avrc/avrc_pars_ct.c new file mode 100755 index 0000000000..3db5a8dc98 --- /dev/null +++ b/components/bt/bluedroid/stack/avrc/avrc_pars_ct.c @@ -0,0 +1,149 @@ +/****************************************************************************** + * + * Copyright (C) 2006-2013 Broadcom Corporation + * + * 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. + * + ******************************************************************************/ +#include + +#include "gki.h" +#include "avrc_api.h" +#include "avrc_defs.h" +#include "avrc_int.h" + +/***************************************************************************** +** Global data +*****************************************************************************/ + +#if (AVRC_METADATA_INCLUDED == TRUE) + +/******************************************************************************* +** +** Function avrc_pars_vendor_rsp +** +** Description This function parses the vendor specific commands defined by +** Bluetooth SIG +** +** Returns AVRC_STS_NO_ERROR, if the message in p_data is parsed successfully. +** Otherwise, the error code defined by AVRCP 1.4 +** +*******************************************************************************/ +static tAVRC_STS avrc_pars_vendor_rsp(tAVRC_MSG_VENDOR *p_msg, tAVRC_RESPONSE *p_result) +{ + tAVRC_STS status = AVRC_STS_NO_ERROR; + UINT8 *p; + UINT16 len; + UINT8 eventid=0; + + /* Check the vendor data */ + if (p_msg->vendor_len == 0) + return AVRC_STS_NO_ERROR; + if (p_msg->p_vendor_data == NULL) + return AVRC_STS_INTERNAL_ERR; + + p = p_msg->p_vendor_data; + BE_STREAM_TO_UINT8 (p_result->pdu, p); + p++; /* skip the reserved/packe_type byte */ + BE_STREAM_TO_UINT16 (len, p); + AVRC_TRACE_DEBUG("avrc_pars_vendor_rsp() ctype:0x%x pdu:0x%x, len:%d/0x%x", p_msg->hdr.ctype, p_result->pdu, len, len); + if (p_msg->hdr.ctype == AVRC_RSP_REJ) + { + p_result->rsp.status = *p; + return p_result->rsp.status; + } + + switch (p_result->pdu) + { + /* case AVRC_PDU_REQUEST_CONTINUATION_RSP: 0x40 */ + /* case AVRC_PDU_ABORT_CONTINUATION_RSP: 0x41 */ + +#if (AVRC_ADV_CTRL_INCLUDED == TRUE) + case AVRC_PDU_SET_ABSOLUTE_VOLUME: /* 0x50 */ + if (len != 1) + status = AVRC_STS_INTERNAL_ERR; + else + { + BE_STREAM_TO_UINT8 (p_result->volume.volume, p); + } + break; +#endif /* (AVRC_ADV_CTRL_INCLUDED == TRUE) */ + + case AVRC_PDU_REGISTER_NOTIFICATION: /* 0x31 */ +#if (AVRC_ADV_CTRL_INCLUDED == TRUE) + BE_STREAM_TO_UINT8 (eventid, p); + if(AVRC_EVT_VOLUME_CHANGE==eventid + && (AVRC_RSP_CHANGED==p_msg->hdr.ctype || AVRC_RSP_INTERIM==p_msg->hdr.ctype + || AVRC_RSP_REJ==p_msg->hdr.ctype || AVRC_RSP_NOT_IMPL==p_msg->hdr.ctype)) + { + p_result->reg_notif.status=p_msg->hdr.ctype; + p_result->reg_notif.event_id=eventid; + BE_STREAM_TO_UINT8 (p_result->reg_notif.param.volume, p); + } + AVRC_TRACE_DEBUG("avrc_pars_vendor_rsp PDU reg notif response:event %x, volume %x",eventid, + p_result->reg_notif.param.volume); +#endif /* (AVRC_ADV_CTRL_INCLUDED == TRUE) */ + break; + default: + status = AVRC_STS_BAD_CMD; + break; + } + + return status; +} + +/******************************************************************************* +** +** Function AVRC_ParsResponse +** +** Description This function is a superset of AVRC_ParsMetadata to parse the response. +** +** Returns AVRC_STS_NO_ERROR, if the message in p_data is parsed successfully. +** Otherwise, the error code defined by AVRCP 1.4 +** +*******************************************************************************/ +tAVRC_STS AVRC_ParsResponse (tAVRC_MSG *p_msg, tAVRC_RESPONSE *p_result, UINT8 *p_buf, UINT16 buf_len) +{ + tAVRC_STS status = AVRC_STS_INTERNAL_ERR; + UINT16 id; + UNUSED(p_buf); + UNUSED(buf_len); + + if (p_msg && p_result) + { + switch (p_msg->hdr.opcode) + { + case AVRC_OP_VENDOR: /* 0x00 Vendor-dependent commands */ + status = avrc_pars_vendor_rsp(&p_msg->vendor, p_result); + break; + + case AVRC_OP_PASS_THRU: /* 0x7C panel subunit opcode */ + status = avrc_pars_pass_thru(&p_msg->pass, &id); + if (status == AVRC_STS_NO_ERROR) + { + p_result->pdu = (UINT8)id; + } + break; + + default: + AVRC_TRACE_ERROR("AVRC_ParsResponse() unknown opcode:0x%x", p_msg->hdr.opcode); + break; + } + p_result->rsp.opcode = p_msg->hdr.opcode; + p_result->rsp.status = status; + } + return status; +} + + +#endif /* (AVRC_METADATA_INCLUDED == TRUE) */ diff --git a/components/bt/bluedroid/stack/avrc/avrc_pars_tg.c b/components/bt/bluedroid/stack/avrc/avrc_pars_tg.c new file mode 100755 index 0000000000..b709c0f8f7 --- /dev/null +++ b/components/bt/bluedroid/stack/avrc/avrc_pars_tg.c @@ -0,0 +1,322 @@ +/****************************************************************************** + * + * Copyright (C) 2003-2013 Broadcom Corporation + * + * 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. + * + ******************************************************************************/ +#include + +#include "gki.h" +#include "avrc_api.h" +#include "avrc_defs.h" +#include "avrc_int.h" + +/***************************************************************************** +** Global data +*****************************************************************************/ +#if (AVRC_METADATA_INCLUDED == TRUE) + +/******************************************************************************* +** +** Function avrc_pars_vendor_cmd +** +** Description This function parses the vendor specific commands defined by +** Bluetooth SIG +** +** Returns AVRC_STS_NO_ERROR, if the message in p_data is parsed successfully. +** Otherwise, the error code defined by AVRCP 1.4 +** +*******************************************************************************/ +static tAVRC_STS avrc_pars_vendor_cmd(tAVRC_MSG_VENDOR *p_msg, tAVRC_COMMAND *p_result, + UINT8 *p_buf, UINT16 buf_len) +{ + tAVRC_STS status = AVRC_STS_NO_ERROR; + UINT8 *p; + UINT16 len; + UINT8 xx, yy; + UINT8 *p_u8; + UINT16 *p_u16; + UINT32 u32, u32_2, *p_u32; + tAVRC_APP_SETTING *p_app_set; + UINT16 size_needed; + + /* Check the vendor data */ + if (p_msg->vendor_len == 0) + return AVRC_STS_NO_ERROR; + if (p_msg->p_vendor_data == NULL) + return AVRC_STS_INTERNAL_ERR; + + p = p_msg->p_vendor_data; + p_result->pdu = *p++; + AVRC_TRACE_DEBUG("avrc_pars_vendor_cmd() pdu:0x%x", p_result->pdu); + if (!AVRC_IsValidAvcType (p_result->pdu, p_msg->hdr.ctype)) + { + AVRC_TRACE_DEBUG("avrc_pars_vendor_cmd() detects wrong AV/C type!"); + status = AVRC_STS_BAD_CMD; + } + + p++; /* skip the reserved byte */ + BE_STREAM_TO_UINT16 (len, p); + if ((len+4) != (p_msg->vendor_len)) + { + status = AVRC_STS_INTERNAL_ERR; + } + + if (status != AVRC_STS_NO_ERROR) + return status; + + switch (p_result->pdu) + { + case AVRC_PDU_GET_CAPABILITIES: /* 0x10 */ + p_result->get_caps.capability_id = *p++; + if (!AVRC_IS_VALID_CAP_ID(p_result->get_caps.capability_id)) + status = AVRC_STS_BAD_PARAM; + else if (len != 1) + status = AVRC_STS_INTERNAL_ERR; + break; + + case AVRC_PDU_LIST_PLAYER_APP_ATTR: /* 0x11 */ + /* no additional parameters */ + if (len != 0) + status = AVRC_STS_INTERNAL_ERR; + break; + + case AVRC_PDU_LIST_PLAYER_APP_VALUES: /* 0x12 */ + p_result->list_app_values.attr_id = *p++; + if (!AVRC_IS_VALID_ATTRIBUTE(p_result->list_app_values.attr_id)) + status = AVRC_STS_BAD_PARAM; + else if (len != 1) + status = AVRC_STS_INTERNAL_ERR; + break; + + case AVRC_PDU_GET_CUR_PLAYER_APP_VALUE: /* 0x13 */ + case AVRC_PDU_GET_PLAYER_APP_ATTR_TEXT: /* 0x15 */ + BE_STREAM_TO_UINT8 (p_result->get_cur_app_val.num_attr, p); + if (len != (p_result->get_cur_app_val.num_attr+1)) + { + status = AVRC_STS_INTERNAL_ERR; + break; + } + p_u8 = p_result->get_cur_app_val.attrs; + for (xx=0, yy=0; xx< p_result->get_cur_app_val.num_attr; xx++) + { + /* only report the valid player app attributes */ + if (AVRC_IsValidPlayerAttr(*p)) + p_u8[yy++] = *p; + p++; + } + p_result->get_cur_app_val.num_attr = yy; + if (yy == 0) + { + status = AVRC_STS_BAD_PARAM; + } + break; + + case AVRC_PDU_SET_PLAYER_APP_VALUE: /* 0x14 */ + BE_STREAM_TO_UINT8 (p_result->set_app_val.num_val, p); + size_needed = sizeof(tAVRC_APP_SETTING); + if (p_buf && (len == ((p_result->set_app_val.num_val<<1) + 1))) + { + p_result->set_app_val.p_vals = (tAVRC_APP_SETTING *)p_buf; + p_app_set = p_result->set_app_val.p_vals; + for (xx=0; ((xx< p_result->set_app_val.num_val) && (buf_len > size_needed)); xx++) + { + p_app_set[xx].attr_id = *p++; + p_app_set[xx].attr_val = *p++; + if (!avrc_is_valid_player_attrib_value(p_app_set[xx].attr_id, p_app_set[xx].attr_val)) + status = AVRC_STS_BAD_PARAM; + } + if (xx != p_result->set_app_val.num_val) + { + AVRC_TRACE_ERROR("AVRC_PDU_SET_PLAYER_APP_VALUE not enough room:%d orig num_val:%d", + xx, p_result->set_app_val.num_val); + p_result->set_app_val.num_val = xx; + } + } + else + { + AVRC_TRACE_ERROR("AVRC_PDU_SET_PLAYER_APP_VALUE NULL decode buffer or bad len"); + status = AVRC_STS_INTERNAL_ERR; + } + break; + + case AVRC_PDU_GET_PLAYER_APP_VALUE_TEXT:/* 0x16 */ + if (len < 3) + status = AVRC_STS_INTERNAL_ERR; + else + { + BE_STREAM_TO_UINT8 (p_result->get_app_val_txt.attr_id, p); + if (!AVRC_IS_VALID_ATTRIBUTE(p_result->get_app_val_txt.attr_id)) + status = AVRC_STS_BAD_PARAM; + else + { + BE_STREAM_TO_UINT8 (p_result->get_app_val_txt.num_val, p); + if ( (len - 2/* attr_id & num_val */) != p_result->get_app_val_txt.num_val) + status = AVRC_STS_INTERNAL_ERR; + else + { + p_u8 = p_result->get_app_val_txt.vals; + for (xx=0; xx< p_result->get_app_val_txt.num_val; xx++) + { + p_u8[xx] = *p++; + if (!avrc_is_valid_player_attrib_value(p_result->get_app_val_txt.attr_id, + p_u8[xx])) + { + status = AVRC_STS_BAD_PARAM; + break; + } + } + } + } + } + break; + + case AVRC_PDU_INFORM_DISPLAY_CHARSET: /* 0x17 */ + if (len < 3) + status = AVRC_STS_INTERNAL_ERR; + else + { + BE_STREAM_TO_UINT8 (p_result->inform_charset.num_id, p); + if ( (len - 1/* num_id */) != p_result->inform_charset.num_id * 2) + status = AVRC_STS_INTERNAL_ERR; + else + { + p_u16 = p_result->inform_charset.charsets; + if (p_result->inform_charset.num_id > AVRC_MAX_CHARSET_SIZE) + p_result->inform_charset.num_id = AVRC_MAX_CHARSET_SIZE; + for (xx=0; xx< p_result->inform_charset.num_id; xx++) + { + BE_STREAM_TO_UINT16 (p_u16[xx], p); + } + } + } + break; + + case AVRC_PDU_INFORM_BATTERY_STAT_OF_CT:/* 0x18 */ + if (len != 1) + status = AVRC_STS_INTERNAL_ERR; + else + { + p_result->inform_battery_status.battery_status = *p++; + if (!AVRC_IS_VALID_BATTERY_STATUS(p_result->inform_battery_status.battery_status)) + status = AVRC_STS_BAD_PARAM; + } + break; + + case AVRC_PDU_GET_ELEMENT_ATTR: /* 0x20 */ + if (len < 9) /* UID/8 and num_attr/1 */ + status = AVRC_STS_INTERNAL_ERR; + else + { + BE_STREAM_TO_UINT32 (u32, p); + BE_STREAM_TO_UINT32 (u32_2, p); + if (u32== 0 && u32_2 == 0) + { + BE_STREAM_TO_UINT8 (p_result->get_elem_attrs.num_attr, p); + if ( (len - 9/* UID/8 and num_attr/1 */) != (p_result->get_elem_attrs.num_attr * 4)) + status = AVRC_STS_INTERNAL_ERR; + else + { + p_u32 = p_result->get_elem_attrs.attrs; + if (p_result->get_elem_attrs.num_attr > AVRC_MAX_ELEM_ATTR_SIZE) + p_result->get_elem_attrs.num_attr = AVRC_MAX_ELEM_ATTR_SIZE; + for (xx=0; xx< p_result->get_elem_attrs.num_attr; xx++) + { + BE_STREAM_TO_UINT32 (p_u32[xx], p); + } + } + } + else + status = AVRC_STS_NOT_FOUND; + } + break; + + case AVRC_PDU_GET_PLAY_STATUS: /* 0x30 */ + /* no additional parameters */ + if (len != 0) + status = AVRC_STS_INTERNAL_ERR; + break; + + case AVRC_PDU_REGISTER_NOTIFICATION: /* 0x31 */ + if (len != 5) + status = AVRC_STS_INTERNAL_ERR; + else + { + BE_STREAM_TO_UINT8 (p_result->reg_notif.event_id, p); + BE_STREAM_TO_UINT32 (p_result->reg_notif.param, p); + } + break; + + case AVRC_PDU_SET_ABSOLUTE_VOLUME: + { + if(len!=1) + status = AVRC_STS_INTERNAL_ERR; + break; + } + + /* case AVRC_PDU_REQUEST_CONTINUATION_RSP: 0x40 */ + /* case AVRC_PDU_ABORT_CONTINUATION_RSP: 0x41 */ + + default: + status = AVRC_STS_BAD_CMD; + break; + } + + return status; +} + +/******************************************************************************* +** +** Function AVRC_ParsCommand +** +** Description This function is a superset of AVRC_ParsMetadata to parse the command. +** +** Returns AVRC_STS_NO_ERROR, if the message in p_data is parsed successfully. +** Otherwise, the error code defined by AVRCP 1.4 +** +*******************************************************************************/ +tAVRC_STS AVRC_ParsCommand (tAVRC_MSG *p_msg, tAVRC_COMMAND *p_result, UINT8 *p_buf, UINT16 buf_len) +{ + tAVRC_STS status = AVRC_STS_INTERNAL_ERR; + UINT16 id; + + if (p_msg && p_result) + { + switch (p_msg->hdr.opcode) + { + case AVRC_OP_VENDOR: /* 0x00 Vendor-dependent commands */ + status = avrc_pars_vendor_cmd(&p_msg->vendor, p_result, p_buf, buf_len); + break; + + case AVRC_OP_PASS_THRU: /* 0x7C panel subunit opcode */ + status = avrc_pars_pass_thru(&p_msg->pass, &id); + if (status == AVRC_STS_NO_ERROR) + { + p_result->pdu = (UINT8)id; + } + break; + + default: + AVRC_TRACE_ERROR("AVRC_ParsCommand() unknown opcode:0x%x", p_msg->hdr.opcode); + break; + } + p_result->cmd.opcode = p_msg->hdr.opcode; + p_result->cmd.status = status; + } + AVRC_TRACE_DEBUG("AVRC_ParsCommand() return status:0x%x", status); + return status; +} + +#endif /* (AVRC_METADATA_INCLUDED == TRUE) */ + diff --git a/components/bt/bluedroid/stack/avrc/avrc_sdp.c b/components/bt/bluedroid/stack/avrc/avrc_sdp.c new file mode 100755 index 0000000000..ba10c1c5a5 --- /dev/null +++ b/components/bt/bluedroid/stack/avrc/avrc_sdp.c @@ -0,0 +1,352 @@ +/****************************************************************************** + * + * Copyright (C) 2003-2013 Broadcom Corporation + * + * 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. + * + ******************************************************************************/ + +/****************************************************************************** + * + * AVRCP SDP related functions + * + ******************************************************************************/ +#include + +#include "gki.h" +#include "avrc_api.h" +#include "avrc_int.h" + +#ifndef SDP_AVRCP_1_4 +#define SDP_AVRCP_1_4 FALSE +#endif + +#ifndef SDP_AVCTP_1_4 +#define SDP_AVCTP_1_4 TRUE +#endif + +/***************************************************************************** +** Global data +*****************************************************************************/ +#if AVRC_DYNAMIC_MEMORY == FALSE +tAVRC_CB avrc_cb; +#endif + +/* update AVRC_NUM_PROTO_ELEMS if this constant is changed */ +const tSDP_PROTOCOL_ELEM avrc_proto_list [] = +{ + {UUID_PROTOCOL_L2CAP, 1, {AVCT_PSM, 0} }, +#if SDP_AVCTP_1_4 == TRUE + {UUID_PROTOCOL_AVCTP, 1, {AVCT_REV_1_4, 0} } +#else +#if SDP_AVRCP_1_4 == TRUE + {UUID_PROTOCOL_AVCTP, 1, {AVCT_REV_1_3, 0} } +#else +#if AVRC_METADATA_INCLUDED == TRUE + {UUID_PROTOCOL_AVCTP, 1, {AVCT_REV_1_2, 0} } +#else + {UUID_PROTOCOL_AVCTP, 1, {AVCT_REV_1_0, 0} } +#endif +#endif +#endif +}; + +#if SDP_AVRCP_1_4 == TRUE +const tSDP_PROTO_LIST_ELEM avrc_add_proto_list [] = +{ + {AVRC_NUM_PROTO_ELEMS, + { + {UUID_PROTOCOL_L2CAP, 1, {AVCT_BR_PSM, 0} }, + {UUID_PROTOCOL_AVCTP, 1, {AVCT_REV_1_3, 0} }}} +}; +#endif + + +/****************************************************************************** +** +** Function avrc_sdp_cback +** +** Description This is the SDP callback function used by A2D_FindService. +** This function will be executed by SDP when the service +** search is completed. If the search is successful, it +** finds the first record in the database that matches the +** UUID of the search. Then retrieves various parameters +** from the record. When it is finished it calls the +** application callback function. +** +** Returns Nothing. +** +******************************************************************************/ +static void avrc_sdp_cback(UINT16 status) +{ + AVRC_TRACE_API("avrc_sdp_cback status: %d", status); + + /* reset service_uuid, so can start another find service */ + avrc_cb.service_uuid = 0; + + /* return info from sdp record in app callback function */ + (*avrc_cb.p_cback) (status); + + return; +} + +/****************************************************************************** +** +** Function AVRC_FindService +** +** Description This function is called by the application to perform service +** discovery and retrieve AVRCP SDP record information from a +** peer device. Information is returned for the first service +** record found on the server that matches the service UUID. +** The callback function will be executed when service discovery +** is complete. There can only be one outstanding call to +** AVRC_FindService() at a time; the application must wait for +** the callback before it makes another call to the function. +** The application is responsible for allocating memory for the +** discovery database. It is recommended that the size of the +** discovery database be at least 300 bytes. The application +** can deallocate the memory after the callback function has +** executed. +** +** Input Parameters: +** service_uuid: Indicates TG(UUID_SERVCLASS_AV_REM_CTRL_TARGET) +** or CT(UUID_SERVCLASS_AV_REMOTE_CONTROL) +** +** bd_addr: BD address of the peer device. +** +** p_db: SDP discovery database parameters. +** +** p_cback: Pointer to the callback function. +** +** Output Parameters: +** None. +** +** Returns AVRC_SUCCESS if successful. +** AVRC_BAD_PARAMS if discovery database parameters are invalid. +** AVRC_NO_RESOURCES if there are not enough resources to +** perform the service search. +** +******************************************************************************/ +UINT16 AVRC_FindService(UINT16 service_uuid, BD_ADDR bd_addr, + tAVRC_SDP_DB_PARAMS *p_db, tAVRC_FIND_CBACK *p_cback) +{ + tSDP_UUID uuid_list; + BOOLEAN result = TRUE; + UINT16 a2d_attr_list[] = {ATTR_ID_SERVICE_CLASS_ID_LIST, /* update AVRC_NUM_ATTR, if changed */ + ATTR_ID_PROTOCOL_DESC_LIST, + ATTR_ID_BT_PROFILE_DESC_LIST, + ATTR_ID_SERVICE_NAME, + ATTR_ID_SUPPORTED_FEATURES, + ATTR_ID_PROVIDER_NAME}; + + AVRC_TRACE_API("AVRC_FindService uuid: %x", service_uuid); + if( (service_uuid != UUID_SERVCLASS_AV_REM_CTRL_TARGET && service_uuid != UUID_SERVCLASS_AV_REMOTE_CONTROL) || + p_db == NULL || p_db->p_db == NULL || p_cback == NULL) + return AVRC_BAD_PARAM; + + /* check if it is busy */ + if( avrc_cb.service_uuid == UUID_SERVCLASS_AV_REM_CTRL_TARGET || + avrc_cb.service_uuid == UUID_SERVCLASS_AV_REMOTE_CONTROL) + return AVRC_NO_RESOURCES; + + /* set up discovery database */ + uuid_list.len = LEN_UUID_16; + uuid_list.uu.uuid16 = service_uuid; + + if(p_db->p_attrs == NULL || p_db->num_attr == 0) + { + p_db->p_attrs = a2d_attr_list; + p_db->num_attr = AVRC_NUM_ATTR; + } + + result = SDP_InitDiscoveryDb(p_db->p_db, p_db->db_len, 1, &uuid_list, p_db->num_attr, + p_db->p_attrs); + + if (result == TRUE) + { + /* store service_uuid and discovery db pointer */ + avrc_cb.p_db = p_db->p_db; + avrc_cb.service_uuid = service_uuid; + avrc_cb.p_cback = p_cback; + + /* perform service search */ + result = SDP_ServiceSearchAttributeRequest(bd_addr, p_db->p_db, avrc_sdp_cback); + } + + return (result ? AVRC_SUCCESS : AVRC_FAIL); +} + +/****************************************************************************** +** +** Function AVRC_AddRecord +** +** Description This function is called to build an AVRCP SDP record. +** Prior to calling this function the application must +** call SDP_CreateRecord() to create an SDP record. +** +** Input Parameters: +** service_uuid: Indicates TG(UUID_SERVCLASS_AV_REM_CTRL_TARGET) +** or CT(UUID_SERVCLASS_AV_REMOTE_CONTROL) +** +** p_service_name: Pointer to a null-terminated character +** string containing the service name. +** If service name is not used set this to NULL. +** +** p_provider_name: Pointer to a null-terminated character +** string containing the provider name. +** If provider name is not used set this to NULL. +** +** categories: Supported categories. +** +** sdp_handle: SDP handle returned by SDP_CreateRecord(). +** +** Output Parameters: +** None. +** +** Returns AVRC_SUCCESS if successful. +** AVRC_NO_RESOURCES if not enough resources to build the SDP record. +** +******************************************************************************/ +UINT16 AVRC_AddRecord(UINT16 service_uuid, char *p_service_name, + char *p_provider_name, UINT16 categories, UINT32 sdp_handle) +{ + UINT16 browse_list[1]; + BOOLEAN result = TRUE; + UINT8 temp[8]; + UINT8 *p; + UINT16 count = 1; + UINT16 class_list[2]; + + + AVRC_TRACE_API("AVRC_AddRecord uuid: %x", service_uuid); + + if( service_uuid != UUID_SERVCLASS_AV_REM_CTRL_TARGET && service_uuid != UUID_SERVCLASS_AV_REMOTE_CONTROL ) + return AVRC_BAD_PARAM; + + /* add service class id list */ + class_list[0] = service_uuid; +#if SDP_AVCTP_1_4 == TRUE + if( service_uuid == UUID_SERVCLASS_AV_REMOTE_CONTROL ) + { + class_list[1] = UUID_SERVCLASS_AV_REM_CTRL_CONTROL; + count = 2; + } +#else +#if SDP_AVRCP_1_4 == TRUE + if( service_uuid == UUID_SERVCLASS_AV_REMOTE_CONTROL ) + { + class_list[1] = UUID_SERVCLASS_AV_REM_CTRL_CONTROL; + count = 2; + } +#endif +#endif + result &= SDP_AddServiceClassIdList(sdp_handle, count, class_list); + + /* add protocol descriptor list */ + result &= SDP_AddProtocolList(sdp_handle, AVRC_NUM_PROTO_ELEMS, (tSDP_PROTOCOL_ELEM *)avrc_proto_list); + + /* add profile descriptor list */ +#if SDP_AVRCP_1_4 == TRUE + /* additional protocol list to include browsing channel */ + result &= SDP_AddAdditionProtoLists( sdp_handle, 1, (tSDP_PROTO_LIST_ELEM *)avrc_add_proto_list); + + result &= SDP_AddProfileDescriptorList(sdp_handle, UUID_SERVCLASS_AV_REMOTE_CONTROL, AVRC_REV_1_4); +#else +#if AVRC_METADATA_INCLUDED == TRUE + result &= SDP_AddProfileDescriptorList(sdp_handle, UUID_SERVCLASS_AV_REMOTE_CONTROL, AVRC_REV_1_3); +#else + result &= SDP_AddProfileDescriptorList(sdp_handle, UUID_SERVCLASS_AV_REMOTE_CONTROL, AVRC_REV_1_0); +#endif +#endif + + /* add supported categories */ + p = temp; + UINT16_TO_BE_STREAM(p, categories); + result &= SDP_AddAttribute(sdp_handle, ATTR_ID_SUPPORTED_FEATURES, UINT_DESC_TYPE, + (UINT32)2, (UINT8*)temp); + + /* add provider name */ + if (p_provider_name != NULL) + { + result &= SDP_AddAttribute(sdp_handle, ATTR_ID_PROVIDER_NAME, TEXT_STR_DESC_TYPE, + (UINT32)(strlen(p_provider_name)+1), (UINT8 *) p_provider_name); + } + + /* add service name */ + if (p_service_name != NULL) + { + result &= SDP_AddAttribute(sdp_handle, ATTR_ID_SERVICE_NAME, TEXT_STR_DESC_TYPE, + (UINT32)(strlen(p_service_name)+1), (UINT8 *) p_service_name); + } + + /* add browse group list */ + browse_list[0] = UUID_SERVCLASS_PUBLIC_BROWSE_GROUP; + result &= SDP_AddUuidSequence(sdp_handle, ATTR_ID_BROWSE_GROUP_LIST, 1, browse_list); + + + return (result ? AVRC_SUCCESS : AVRC_FAIL); +} + + + +/****************************************************************************** +** +** Function AVRC_SetTraceLevel +** +** Description Sets the trace level for AVRC. If 0xff is passed, the +** current trace level is returned. +** +** Input Parameters: +** new_level: The level to set the AVRC tracing to: +** 0xff-returns the current setting. +** 0-turns off tracing. +** >= 1-Errors. +** >= 2-Warnings. +** >= 3-APIs. +** >= 4-Events. +** >= 5-Debug. +** +** Returns The new trace level or current trace level if +** the input parameter is 0xff. +** +******************************************************************************/ +UINT8 AVRC_SetTraceLevel (UINT8 new_level) +{ + if (new_level != 0xFF) + avrc_cb.trace_level = new_level; + + return (avrc_cb.trace_level); +} + +/******************************************************************************* +** +** Function AVRC_Init +** +** Description This function is called at stack startup to allocate the +** control block (if using dynamic memory), and initializes the +** control block and tracing level. +** +** Returns void +** +*******************************************************************************/ +void AVRC_Init(void) +{ + memset(&avrc_cb, 0, sizeof(tAVRC_CB)); + +#if defined(AVRC_INITIAL_TRACE_LEVEL) + avrc_cb.trace_level = AVRC_INITIAL_TRACE_LEVEL; +#else + avrc_cb.trace_level = BT_TRACE_LEVEL_NONE; +#endif +} + diff --git a/components/bt/bluedroid/stack/avrc/avrc_utils.c b/components/bt/bluedroid/stack/avrc/avrc_utils.c new file mode 100755 index 0000000000..432ecc0cd6 --- /dev/null +++ b/components/bt/bluedroid/stack/avrc/avrc_utils.c @@ -0,0 +1,239 @@ +/****************************************************************************** + * + * Copyright (C) 2003-2013 Broadcom Corporation + * + * 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. + * + ******************************************************************************/ +#include + +#include "gki.h" +#include "avrc_api.h" +#include "avrc_int.h" + + +#if (AVRC_METADATA_INCLUDED == TRUE) + +/************************************************************************** +** +** Function AVRC_IsValidAvcType +** +** Description Check if correct AVC type is specified +** +** Returns returns TRUE if it is valid +** +** +*******************************************************************************/ +BOOLEAN AVRC_IsValidAvcType(UINT8 pdu_id, UINT8 avc_type) +{ + BOOLEAN result=FALSE; + + if (avc_type < AVRC_RSP_NOT_IMPL) /* command msg */ + { + switch (pdu_id) + { + case AVRC_PDU_GET_CAPABILITIES: /* 0x10 */ + case AVRC_PDU_LIST_PLAYER_APP_ATTR: /* 0x11 */ + case AVRC_PDU_LIST_PLAYER_APP_VALUES: /* 0x12 */ + case AVRC_PDU_GET_CUR_PLAYER_APP_VALUE: /* 0x13 */ + case AVRC_PDU_GET_PLAYER_APP_ATTR_TEXT: /* 0x15 */ + case AVRC_PDU_GET_PLAYER_APP_VALUE_TEXT: /* 0x16 */ + case AVRC_PDU_GET_ELEMENT_ATTR: /* 0x20 */ + case AVRC_PDU_GET_PLAY_STATUS: /* 0x30 */ + if (avc_type == AVRC_CMD_STATUS) + result=TRUE; + break; + + case AVRC_PDU_SET_PLAYER_APP_VALUE: /* 0x14 */ + case AVRC_PDU_INFORM_DISPLAY_CHARSET: /* 0x17 */ + case AVRC_PDU_INFORM_BATTERY_STAT_OF_CT: /* 0x18 */ + case AVRC_PDU_REQUEST_CONTINUATION_RSP: /* 0x40 */ + case AVRC_PDU_ABORT_CONTINUATION_RSP: /* 0x41 */ + if (avc_type == AVRC_CMD_CTRL) + result=TRUE; + break; + + case AVRC_PDU_REGISTER_NOTIFICATION: /* 0x31 */ + if (avc_type == AVRC_CMD_NOTIF) + result=TRUE; + break; + } + } + else /* response msg */ + { + if (avc_type >= AVRC_RSP_NOT_IMPL && + avc_type <= AVRC_RSP_INTERIM ) + result=TRUE; + } + + return result; +} + +/******************************************************************************* +** +** Function avrc_is_valid_player_attrib_value +** +** Description Check if the given attrib value is valid for its attribute +** +** Returns returns TRUE if it is valid +** +*******************************************************************************/ +BOOLEAN avrc_is_valid_player_attrib_value(UINT8 attrib, UINT8 value) +{ + BOOLEAN result=FALSE; + + switch(attrib) + { + case AVRC_PLAYER_SETTING_EQUALIZER: + if ((value > 0) && + (value <= AVRC_PLAYER_VAL_ON)) + result=TRUE; + break; + + case AVRC_PLAYER_SETTING_REPEAT: + if ((value > 0) && + (value <= AVRC_PLAYER_VAL_GROUP_REPEAT)) + result=TRUE; + break; + + case AVRC_PLAYER_SETTING_SHUFFLE: + case AVRC_PLAYER_SETTING_SCAN: + if ((value > 0) && + (value <= AVRC_PLAYER_VAL_GROUP_SHUFFLE)) + result=TRUE; + break; + } + + if (attrib >= AVRC_PLAYER_SETTING_LOW_MENU_EXT) + result = TRUE; + + if (!result) + AVRC_TRACE_ERROR( + "avrc_is_valid_player_attrib_value() found not matching attrib(x%x)-value(x%x) pair!", + attrib, value); + + return result; +} + +/******************************************************************************* +** +** Function AVRC_IsValidPlayerAttr +** +** Description Check if the given attrib value is a valid one +** +** Returns returns TRUE if it is valid +** +*******************************************************************************/ +BOOLEAN AVRC_IsValidPlayerAttr(UINT8 attr) +{ + BOOLEAN result=FALSE; + + if ( (attr >= AVRC_PLAYER_SETTING_EQUALIZER && attr <= AVRC_PLAYER_SETTING_SCAN) || + (attr >= AVRC_PLAYER_SETTING_LOW_MENU_EXT) ) + { + result = TRUE; + } + + return result; +} + + + +/******************************************************************************* +** +** Function avrc_pars_pass_thru +** +** Description This function parses the pass thru commands defined by +** Bluetooth SIG +** +** Returns AVRC_STS_NO_ERROR, if the message in p_data is parsed successfully. +** Otherwise, the error code defined by AVRCP 1.4 +** +*******************************************************************************/ +tAVRC_STS avrc_pars_pass_thru(tAVRC_MSG_PASS *p_msg, UINT16 *p_vendor_unique_id) +{ + UINT8 *p_data; + UINT32 co_id; + UINT16 id; + tAVRC_STS status = AVRC_STS_BAD_CMD; + + if (p_msg->op_id == AVRC_ID_VENDOR && p_msg->pass_len == AVRC_PASS_THRU_GROUP_LEN) + { + p_data = p_msg->p_pass_data; + AVRC_BE_STREAM_TO_CO_ID (co_id, p_data); + if (co_id == AVRC_CO_METADATA) + { + BE_STREAM_TO_UINT16 (id, p_data); + if (AVRC_IS_VALID_GROUP(id)) + { + *p_vendor_unique_id = id; + status = AVRC_STS_NO_ERROR; + } + } + } + return status; +} + +/******************************************************************************* +** +** Function avrc_opcode_from_pdu +** +** Description This function returns the opcode of the given pdu +** +** Returns AVRC_OP_VENDOR, AVRC_OP_PASS_THRU or AVRC_OP_BROWSE +** +*******************************************************************************/ +UINT8 avrc_opcode_from_pdu(UINT8 pdu) +{ + UINT8 opcode = 0; + + switch (pdu) + { + case AVRC_PDU_NEXT_GROUP: + case AVRC_PDU_PREV_GROUP: /* pass thru */ + opcode = AVRC_OP_PASS_THRU; + break; + + default: /* vendor */ + opcode = AVRC_OP_VENDOR; + break; + } + + return opcode; +} + +/******************************************************************************* +** +** Function avrc_is_valid_opcode +** +** Description This function returns the opcode of the given pdu +** +** Returns AVRC_OP_VENDOR, AVRC_OP_PASS_THRU or AVRC_OP_BROWSE +** +*******************************************************************************/ +BOOLEAN avrc_is_valid_opcode(UINT8 opcode) +{ + BOOLEAN is_valid = FALSE; + switch (opcode) + { + case AVRC_OP_BROWSE: + case AVRC_OP_PASS_THRU: + case AVRC_OP_VENDOR: + is_valid = TRUE; + break; + } + return is_valid; +} + +#endif /* (AVRC_METADATA_INCLUDED == TRUE) */ + diff --git a/components/bt/bluedroid/stack/avrc/include/avrc_int.h b/components/bt/bluedroid/stack/avrc/include/avrc_int.h new file mode 100755 index 0000000000..6bb7014488 --- /dev/null +++ b/components/bt/bluedroid/stack/avrc/include/avrc_int.h @@ -0,0 +1,158 @@ +/****************************************************************************** + * + * Copyright (C) 2003-2012 Broadcom Corporation + * + * 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. + * + ******************************************************************************/ + +/****************************************************************************** + * + * VRCP internal header file. + * + ******************************************************************************/ + + +#ifndef AVRC_INT_H +#define AVRC_INT_H + +//#include "avct_defs.h" +#include "avrc_api.h" + +/* DEBUG FLAGS + * + * #define META_DEBUG_ENABLED + */ +/***************************************************************************** +** Constants +*****************************************************************************/ + +/* Number of attributes in AVRC SDP record. */ +#define AVRC_NUM_ATTR 6 + +/* Number of protocol elements in protocol element list. */ +#define AVRC_NUM_PROTO_ELEMS 2 + +#ifndef AVRC_MIN_CMD_LEN +#define AVRC_MIN_CMD_LEN 20 +#endif + +#define AVRC_UNIT_OPRND_BYTES 5 +#define AVRC_SUB_OPRND_BYTES 4 +#define AVRC_SUBRSP_OPRND_BYTES 3 +#define AVRC_SUB_PAGE_MASK 7 +#define AVRC_SUB_PAGE_SHIFT 4 +#define AVRC_SUB_EXT_CODE 7 +#define AVRC_PASS_OP_ID_MASK 0x7F +#define AVRC_PASS_STATE_MASK 0x80 +#define AVRC_CMD_OPRND_PAD 0xFF + +#define AVRC_CTYPE_MASK 0x0F +#define AVRC_SUBTYPE_MASK 0xF8 +#define AVRC_SUBTYPE_SHIFT 3 +#define AVRC_SUBID_MASK 0x07 +#define AVRC_SUBID_IGNORE 0x07 + +#define AVRC_SINGLE_PARAM_SIZE 1 +#define AVRC_METADATA_PKT_TYPE_MASK 0x03 +#define AVRC_PASS_THOUGH_MSG_MASK 0x80 /* MSB of msg_type indicates the PAS THROUGH msg */ +#define AVRC_VENDOR_UNIQUE_MASK 0x70 /* vendor unique id */ + + +/* Company ID is 24-bit integer We can not use the macros in bt_types.h */ +#define AVRC_CO_ID_TO_BE_STREAM(p, u32) {*(p)++ = (UINT8)((u32) >> 16); *(p)++ = (UINT8)((u32) >> 8); *(p)++ = (UINT8)(u32); } +#define AVRC_BE_STREAM_TO_CO_ID(u32, p) {u32 = (((UINT32)(*((p) + 2))) + (((UINT32)(*((p) + 1))) << 8) + (((UINT32)(*(p))) << 16)); (p) += 3;} + +#define AVRC_AVC_HDR_SIZE 3 /* ctype, subunit*, opcode */ + +#define AVRC_MIN_META_HDR_SIZE 4 /* pdu id(1), packet type(1), param len(2) */ +#define AVRC_MIN_BROWSE_HDR_SIZE 3 /* pdu id(1), param len(2) */ + +#define AVRC_VENDOR_HDR_SIZE 6 /* ctype, subunit*, opcode, CO_ID */ +#define AVRC_MSG_VENDOR_OFFSET 23 +#define AVRC_MIN_VENDOR_SIZE (AVRC_MSG_VENDOR_OFFSET + BT_HDR_SIZE + AVRC_MIN_META_HDR_SIZE) + +#define AVRC_PASS_THRU_SIZE 8 +#define AVRC_MSG_PASS_THRU_OFFSET 25 +#define AVRC_MIN_PASS_THRU_SIZE (AVRC_MSG_PASS_THRU_OFFSET + BT_HDR_SIZE + 4) + +#define AVRC_MIN_BROWSE_SIZE (AVCT_BROWSE_OFFSET + BT_HDR_SIZE + AVRC_MIN_BROWSE_HDR_SIZE) + +#define AVRC_CTRL_PKT_LEN(pf, pk) {pf = (UINT8 *)((pk) + 1) + (pk)->offset + 2;} + +#define AVRC_MAX_CTRL_DATA_LEN (AVRC_PACKET_LEN) + +/***************************************************************************** +** Type definitions +*****************************************************************************/ + +#if (AVRC_METADATA_INCLUDED == TRUE) +/* type for Metadata fragmentation control block */ +typedef struct +{ + BT_HDR *p_fmsg; /* the fragmented message */ + UINT8 frag_pdu; /* the PDU ID for fragmentation */ + BOOLEAN frag_enabled; /* fragmentation flag */ +} tAVRC_FRAG_CB; + +/* type for Metadata re-assembly control block */ +typedef struct +{ + BT_HDR *p_rmsg; /* the received message */ + UINT16 rasm_offset; /* re-assembly flag, the offset of the start fragment */ + UINT8 rasm_pdu; /* the PDU ID for re-assembly */ +} tAVRC_RASM_CB; +#endif + +typedef struct +{ + tAVRC_CONN_CB ccb[AVCT_NUM_CONN]; +#if (AVRC_METADATA_INCLUDED == TRUE) + tAVRC_FRAG_CB fcb[AVCT_NUM_CONN]; + tAVRC_RASM_CB rcb[AVCT_NUM_CONN]; +#endif + tAVRC_FIND_CBACK *p_cback; /* pointer to application callback */ + tSDP_DISCOVERY_DB *p_db; /* pointer to discovery database */ + UINT16 service_uuid; /* service UUID to search */ + UINT8 trace_level; +} tAVRC_CB; + + + +#ifdef __cplusplus +extern "C" +{ +#endif + +/****************************************************************************** +** Main Control Block +*******************************************************************************/ +#if AVRC_DYNAMIC_MEMORY == FALSE +extern tAVRC_CB avrc_cb; +#else +extern tAVRC_CB *avrc_cb_ptr; +#define avrc_cb (*avrc_cb_ptr) +#endif + +extern BOOLEAN avrc_is_valid_pdu_id(UINT8 pdu_id); +extern BOOLEAN avrc_is_valid_player_attrib_value(UINT8 attrib, UINT8 value); +extern BT_HDR * avrc_alloc_ctrl_pkt (UINT8 pdu); +extern tAVRC_STS avrc_pars_pass_thru(tAVRC_MSG_PASS *p_msg, UINT16 *p_vendor_unique_id); +extern UINT8 avrc_opcode_from_pdu(UINT8 pdu); +extern BOOLEAN avrc_is_valid_opcode(UINT8 opcode); + +#ifdef __cplusplus +} +#endif + +#endif /* AVRC_INT_H */ diff --git a/components/bt/bluedroid/stack/btm/btm_acl.c b/components/bt/bluedroid/stack/btm/btm_acl.c new file mode 100755 index 0000000000..0e1d475dd0 --- /dev/null +++ b/components/bt/bluedroid/stack/btm/btm_acl.c @@ -0,0 +1,2564 @@ +/****************************************************************************** + * + * Copyright (C) 2000-2012 Broadcom Corporation + * + * 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. + * + ******************************************************************************/ + +/***************************************************************************** +** +** Name: btm_acl.c +** +** Description: This file contains functions that handle ACL connections. +** This includes operations such as hold and sniff modes, +** supported packet types. +** +** This module contains both internal and external (API) +** functions. External (API) functions are distinguishable +** by their names beginning with uppercase BTM. +** +** +******************************************************************************/ + +#include +#include +//#include +#include + +#include "bt_types.h" +#include "bt_target.h" +#include "controller.h" +#include "gki.h" +#include "hcimsgs.h" +#include "btu.h" +#include "btm_api.h" +#include "btm_int.h" +#include "l2c_int.h" +#include "hcidefs.h" +//#include "bt_utils.h" + +static void btm_read_remote_features (UINT16 handle); +static void btm_read_remote_ext_features (UINT16 handle, UINT8 page_number); +static void btm_process_remote_ext_features (tACL_CONN *p_acl_cb, UINT8 num_read_pages); + +#define BTM_DEV_REPLY_TIMEOUT 3 /* 3 second timeout waiting for responses */ + +/******************************************************************************* +** +** Function btm_acl_init +** +** Description This function is called at BTM startup to initialize +** +** Returns void +** +*******************************************************************************/ +void btm_acl_init (void) +{ + BTM_TRACE_DEBUG ("btm_acl_init"); +#if 0 /* cleared in btm_init; put back in if called from anywhere else! */ + memset (&btm_cb.acl_db, 0, sizeof (btm_cb.acl_db)); + memset (btm_cb.btm_scn, 0, BTM_MAX_SCN); /* Initialize the SCN usage to FALSE */ + btm_cb.btm_def_link_policy = 0; + btm_cb.p_bl_changed_cb = NULL; +#endif + + /* Initialize nonzero defaults */ + btm_cb.btm_def_link_super_tout = HCI_DEFAULT_INACT_TOUT; + btm_cb.acl_disc_reason = 0xff ; +} + +/******************************************************************************* +** +** Function btm_bda_to_acl +** +** Description This function returns the FIRST acl_db entry for the passed BDA. +** +** Parameters bda : BD address of the remote device +** transport : Physical transport used for ACL connection (BR/EDR or LE) +** +** Returns Returns pointer to the ACL DB for the requested BDA if found. +** NULL if not found. +** +*******************************************************************************/ +tACL_CONN *btm_bda_to_acl (BD_ADDR bda, tBT_TRANSPORT transport) +{ + tACL_CONN *p = &btm_cb.acl_db[0]; + UINT16 xx; + if (bda) + { + for (xx = 0; xx < MAX_L2CAP_LINKS; xx++, p++) + { + if ((p->in_use) && (!memcmp (p->remote_addr, bda, BD_ADDR_LEN)) +#if BLE_INCLUDED == TRUE + && p->transport == transport +#endif + ) + { + BTM_TRACE_DEBUG ("btm_bda_to_acl found"); + return(p); + } + } + } + + /* If here, no BD Addr found */ + return((tACL_CONN *)NULL); +} + +/******************************************************************************* +** +** Function btm_handle_to_acl_index +** +** Description This function returns the FIRST acl_db entry for the passed hci_handle. +** +** Returns index to the acl_db or MAX_L2CAP_LINKS. +** +*******************************************************************************/ +UINT8 btm_handle_to_acl_index (UINT16 hci_handle) +{ + tACL_CONN *p = &btm_cb.acl_db[0]; + UINT8 xx; + BTM_TRACE_DEBUG ("btm_handle_to_acl_index"); + for (xx = 0; xx < MAX_L2CAP_LINKS; xx++, p++) + { + if ((p->in_use) && (p->hci_handle == hci_handle)) + { + break; + } + } + + /* If here, no BD Addr found */ + return(xx); +} + +#if BLE_PRIVACY_SPT == TRUE +/******************************************************************************* +** +** Function btm_ble_get_acl_remote_addr +** +** Description This function reads the active remote address used for the +** connection. +** +** Returns success return TRUE, otherwise FALSE. +** +*******************************************************************************/ +BOOLEAN btm_ble_get_acl_remote_addr(tBTM_SEC_DEV_REC *p_dev_rec, BD_ADDR conn_addr, + tBLE_ADDR_TYPE *p_addr_type) +{ +#if BLE_INCLUDED == TRUE + BOOLEAN st = TRUE; + + if (p_dev_rec == NULL) + { + BTM_TRACE_ERROR("btm_ble_get_acl_remote_addr can not find device with matching address"); + return FALSE; + } + + switch (p_dev_rec->ble.active_addr_type) + { + case BTM_BLE_ADDR_PSEUDO: + memcpy(conn_addr, p_dev_rec->bd_addr, BD_ADDR_LEN); + * p_addr_type = p_dev_rec->ble.ble_addr_type; + break; + + case BTM_BLE_ADDR_RRA: + memcpy(conn_addr, p_dev_rec->ble.cur_rand_addr, BD_ADDR_LEN); + * p_addr_type = BLE_ADDR_RANDOM; + break; + + case BTM_BLE_ADDR_STATIC: + memcpy(conn_addr, p_dev_rec->ble.static_addr, BD_ADDR_LEN); + * p_addr_type = p_dev_rec->ble.static_addr_type; + break; + + default: + BTM_TRACE_ERROR("Unknown active address: %d", p_dev_rec->ble.active_addr_type); + st = FALSE; + break; + } + + return st; +#else + UNUSED(p_dev_rec); + UNUSED(conn_addr); + UNUSED(p_addr_type); + return FALSE; +#endif +} +#endif +/******************************************************************************* +** +** Function btm_acl_created +** +** Description This function is called by L2CAP when an ACL connection +** is created. +** +** Returns void +** +*******************************************************************************/ +void btm_acl_created (BD_ADDR bda, DEV_CLASS dc, BD_NAME bdn, + UINT16 hci_handle, UINT8 link_role, tBT_TRANSPORT transport) +{ + tBTM_SEC_DEV_REC *p_dev_rec = NULL; + tACL_CONN *p; + UINT8 xx; + + BTM_TRACE_DEBUG ("btm_acl_created hci_handle=%d link_role=%d transport=%d", + hci_handle,link_role, transport); + /* Ensure we don't have duplicates */ + p = btm_bda_to_acl(bda, transport); + if (p != (tACL_CONN *)NULL) + { + p->hci_handle = hci_handle; + p->link_role = link_role; +#if BLE_INCLUDED == TRUE + p->transport = transport; +#endif + BTM_TRACE_DEBUG ("Duplicate btm_acl_created: RemBdAddr: %02x%02x%02x%02x%02x%02x", + bda[0], bda[1], bda[2], bda[3], bda[4], bda[5]); + BTM_SetLinkPolicy(p->remote_addr, &btm_cb.btm_def_link_policy); + return; + } + + /* Allocate acl_db entry */ + for (xx = 0, p = &btm_cb.acl_db[0]; xx < MAX_L2CAP_LINKS; xx++, p++) + { + if (!p->in_use) + { + p->in_use = TRUE; + p->hci_handle = hci_handle; + p->link_role = link_role; + p->link_up_issued = FALSE; + memcpy (p->remote_addr, bda, BD_ADDR_LEN); + +#if BLE_INCLUDED == TRUE + p->transport = transport; +#if BLE_PRIVACY_SPT == TRUE + if (transport == BT_TRANSPORT_LE) + btm_ble_refresh_local_resolvable_private_addr(bda, + btm_cb.ble_ctr_cb.addr_mgnt_cb.private_addr); +#else + p->conn_addr_type = BLE_ADDR_PUBLIC; + memcpy(p->conn_addr, &controller_get_interface()->get_address()->address, BD_ADDR_LEN); + +#endif +#endif + p->switch_role_state = BTM_ACL_SWKEY_STATE_IDLE; + + btm_pm_sm_alloc(xx); + + + if (dc) + memcpy (p->remote_dc, dc, DEV_CLASS_LEN); + + if (bdn) + memcpy (p->remote_name, bdn, BTM_MAX_REM_BD_NAME_LEN); + + /* if BR/EDR do something more */ + if (transport == BT_TRANSPORT_BR_EDR) + { + btsnd_hcic_read_rmt_clk_offset (p->hci_handle); + btsnd_hcic_rmt_ver_req (p->hci_handle); + } + p_dev_rec = btm_find_dev_by_handle (hci_handle); + +#if (BLE_INCLUDED == TRUE) + if (p_dev_rec ) + { + BTM_TRACE_DEBUG ("device_type=0x%x", p_dev_rec->device_type); + } +#endif + + if (p_dev_rec && !(transport == BT_TRANSPORT_LE)) + { + /* If remote features already known, copy them and continue connection setup */ + if ((p_dev_rec->num_read_pages) && + (p_dev_rec->num_read_pages <= (HCI_EXT_FEATURES_PAGE_MAX + 1))) + { + memcpy (p->peer_lmp_features, p_dev_rec->features, + (HCI_FEATURE_BYTES_PER_PAGE * p_dev_rec->num_read_pages)); + p->num_read_pages = p_dev_rec->num_read_pages; + + const UINT8 req_pend = (p_dev_rec->sm4 & BTM_SM4_REQ_PEND); + + /* Store the Peer Security Capabilites (in SM4 and rmt_sec_caps) */ + btm_sec_set_peer_sec_caps(p, p_dev_rec); + + BTM_TRACE_API("%s: pend:%d", __FUNCTION__, req_pend); + if (req_pend) + { + /* Request for remaining Security Features (if any) */ + l2cu_resubmit_pending_sec_req (p_dev_rec->bd_addr); + } + btm_establish_continue (p); + return; + } + } + +#if (BLE_INCLUDED == TRUE) + /* If here, features are not known yet */ + if (p_dev_rec && transport == BT_TRANSPORT_LE) + { +#if BLE_PRIVACY_SPT == TRUE + btm_ble_get_acl_remote_addr (p_dev_rec, p->active_remote_addr, + &p->active_remote_addr_type); +#endif + + if (HCI_LE_SLAVE_INIT_FEAT_EXC_SUPPORTED(controller_get_interface()->get_features_ble()->as_array) + || link_role == HCI_ROLE_MASTER) + { + btsnd_hcic_ble_read_remote_feat(p->hci_handle); + } + else + { + btm_establish_continue(p); + } + } + else +#endif + { + btm_read_remote_features (p->hci_handle); + } + + /* read page 1 - on rmt feature event for buffer reasons */ + return; + } + } +} + + +/******************************************************************************* +** +** Function btm_acl_report_role_change +** +** Description This function is called when the local device is deemed +** to be down. It notifies L2CAP of the failure. +** +** Returns void +** +*******************************************************************************/ +void btm_acl_report_role_change (UINT8 hci_status, BD_ADDR bda) +{ + tBTM_ROLE_SWITCH_CMPL ref_data; + BTM_TRACE_DEBUG ("btm_acl_report_role_change"); + if (btm_cb.devcb.p_switch_role_cb + && (bda && (0 == memcmp(btm_cb.devcb.switch_role_ref_data.remote_bd_addr, bda, BD_ADDR_LEN)))) + { + memcpy (&ref_data, &btm_cb.devcb.switch_role_ref_data, sizeof(tBTM_ROLE_SWITCH_CMPL)); + ref_data.hci_status = hci_status; + (*btm_cb.devcb.p_switch_role_cb)(&ref_data); + memset (&btm_cb.devcb.switch_role_ref_data, 0, sizeof(tBTM_ROLE_SWITCH_CMPL)); + btm_cb.devcb.p_switch_role_cb = NULL; + } +} + +/******************************************************************************* +** +** Function btm_acl_removed +** +** Description This function is called by L2CAP when an ACL connection +** is removed. Since only L2CAP creates ACL links, we use +** the L2CAP link index as our index into the control blocks. +** +** Returns void +** +*******************************************************************************/ +void btm_acl_removed (BD_ADDR bda, tBT_TRANSPORT transport) +{ + tACL_CONN *p; + tBTM_BL_EVENT_DATA evt_data; +#if (defined BLE_INCLUDED && BLE_INCLUDED == TRUE) + tBTM_SEC_DEV_REC *p_dev_rec=NULL; +#endif + BTM_TRACE_DEBUG ("btm_acl_removed"); + p = btm_bda_to_acl(bda, transport); + if (p != (tACL_CONN *)NULL) + { + p->in_use = FALSE; + + /* if the disconnected channel has a pending role switch, clear it now */ + btm_acl_report_role_change(HCI_ERR_NO_CONNECTION, bda); + + /* Only notify if link up has had a chance to be issued */ + if (p->link_up_issued) + { + p->link_up_issued = FALSE; + + /* If anyone cares, tell him database changed */ + if (btm_cb.p_bl_changed_cb) + { + evt_data.event = BTM_BL_DISCN_EVT; + evt_data.discn.p_bda = bda; +#if BLE_INCLUDED == TRUE + evt_data.discn.handle = p->hci_handle; + evt_data.discn.transport = p->transport; +#endif + (*btm_cb.p_bl_changed_cb)(&evt_data); + } + + btm_acl_update_busy_level (BTM_BLI_ACL_DOWN_EVT); + } + +#if (defined BLE_INCLUDED && BLE_INCLUDED == TRUE) + + BTM_TRACE_DEBUG ("acl hci_handle=%d transport=%d connectable_mode=0x%0x link_role=%d", + p->hci_handle, + p->transport, + btm_cb.ble_ctr_cb.inq_var.connectable_mode, + p->link_role); + + p_dev_rec = btm_find_dev(bda); + if ( p_dev_rec) + { + BTM_TRACE_DEBUG("before update p_dev_rec->sec_flags=0x%x", p_dev_rec->sec_flags); + if (p->transport == BT_TRANSPORT_LE) + { + BTM_TRACE_DEBUG("LE link down"); + p_dev_rec->sec_flags &= ~(BTM_SEC_LE_ENCRYPTED | BTM_SEC_ROLE_SWITCHED); + if ( (p_dev_rec->sec_flags & BTM_SEC_LE_LINK_KEY_KNOWN) == 0) + { + BTM_TRACE_DEBUG("Not Bonded"); + p_dev_rec->sec_flags &= ~(BTM_SEC_LE_LINK_KEY_AUTHED | BTM_SEC_LE_AUTHENTICATED); + } + else + { + BTM_TRACE_DEBUG("Bonded"); + } + } + else + { + BTM_TRACE_DEBUG("Bletooth link down"); + p_dev_rec->sec_flags &= ~(BTM_SEC_AUTHORIZED | BTM_SEC_AUTHENTICATED + | BTM_SEC_ENCRYPTED | BTM_SEC_ROLE_SWITCHED); + } + BTM_TRACE_DEBUG("after update p_dev_rec->sec_flags=0x%x", p_dev_rec->sec_flags); + } + else + { + BTM_TRACE_ERROR("Device not found"); + + } +#endif + + /* Clear the ACL connection data */ + memset(p, 0, sizeof(tACL_CONN)); + } +} + + +/******************************************************************************* +** +** Function btm_acl_device_down +** +** Description This function is called when the local device is deemed +** to be down. It notifies L2CAP of the failure. +** +** Returns void +** +*******************************************************************************/ +void btm_acl_device_down (void) +{ + tACL_CONN *p = &btm_cb.acl_db[0]; + UINT16 xx; + BTM_TRACE_DEBUG ("btm_acl_device_down"); + for (xx = 0; xx < MAX_L2CAP_LINKS; xx++, p++) + { + if (p->in_use) + { + BTM_TRACE_DEBUG ("hci_handle=%d HCI_ERR_HW_FAILURE ",p->hci_handle ); + l2c_link_hci_disc_comp (p->hci_handle, HCI_ERR_HW_FAILURE); + } + } +} + +/******************************************************************************* +** +** Function btm_acl_update_busy_level +** +** Description This function is called to update the busy level of the system +** . +** +** Returns void +** +*******************************************************************************/ +void btm_acl_update_busy_level (tBTM_BLI_EVENT event) +{ + tBTM_BL_UPDATE_DATA evt; + UINT8 busy_level; + BTM_TRACE_DEBUG ("btm_acl_update_busy_level\n"); + BOOLEAN old_inquiry_state = btm_cb.is_inquiry; + switch (event) + { + case BTM_BLI_ACL_UP_EVT: + BTM_TRACE_DEBUG ("BTM_BLI_ACL_UP_EVT\n"); + break; + case BTM_BLI_ACL_DOWN_EVT: + BTM_TRACE_DEBUG ("BTM_BLI_ACL_DOWN_EVT\n"); + break; + case BTM_BLI_PAGE_EVT: + BTM_TRACE_DEBUG ("BTM_BLI_PAGE_EVT\n"); + btm_cb.is_paging = TRUE; + evt.busy_level_flags= BTM_BL_PAGING_STARTED; + break; + case BTM_BLI_PAGE_DONE_EVT: + BTM_TRACE_DEBUG ("BTM_BLI_PAGE_DONE_EVT\n"); + btm_cb.is_paging = FALSE; + evt.busy_level_flags = BTM_BL_PAGING_COMPLETE; + break; + case BTM_BLI_INQ_EVT: + BTM_TRACE_DEBUG ("BTM_BLI_INQ_EVT\n"); + btm_cb.is_inquiry = TRUE; + evt.busy_level_flags = BTM_BL_INQUIRY_STARTED; + break; + case BTM_BLI_INQ_CANCEL_EVT: + BTM_TRACE_DEBUG ("BTM_BLI_INQ_CANCEL_EVT\n"); + btm_cb.is_inquiry = FALSE; + evt.busy_level_flags = BTM_BL_INQUIRY_CANCELLED; + break; + case BTM_BLI_INQ_DONE_EVT: + BTM_TRACE_DEBUG ("BTM_BLI_INQ_DONE_EVT\n"); + btm_cb.is_inquiry = FALSE; + evt.busy_level_flags = BTM_BL_INQUIRY_COMPLETE; + break; + } + + if (btm_cb.is_paging || btm_cb.is_inquiry) + busy_level = 10; + else + busy_level = BTM_GetNumAclLinks(); + + if ((busy_level != btm_cb.busy_level) ||(old_inquiry_state != btm_cb.is_inquiry)) + { + evt.event = BTM_BL_UPDATE_EVT; + evt.busy_level = busy_level; + btm_cb.busy_level = busy_level; + if (btm_cb.p_bl_changed_cb && (btm_cb.bl_evt_mask & BTM_BL_UPDATE_MASK)) + { + (*btm_cb.p_bl_changed_cb)((tBTM_BL_EVENT_DATA *)&evt); + } + } +} + +/******************************************************************************* +** +** Function BTM_GetRole +** +** Description This function is called to get the role of the local device +** for the ACL connection with the specified remote device +** +** Returns BTM_SUCCESS if connection exists. +** BTM_UNKNOWN_ADDR if no active link with bd addr specified +** +*******************************************************************************/ +tBTM_STATUS BTM_GetRole (BD_ADDR remote_bd_addr, UINT8 *p_role) +{ + tACL_CONN *p; + BTM_TRACE_DEBUG ("BTM_GetRole"); + if ((p = btm_bda_to_acl(remote_bd_addr, BT_TRANSPORT_BR_EDR)) == NULL) + { + *p_role = BTM_ROLE_UNDEFINED; + return(BTM_UNKNOWN_ADDR); + } + + /* Get the current role */ + *p_role = p->link_role; + return(BTM_SUCCESS); +} + + +/******************************************************************************* +** +** Function BTM_SwitchRole +** +** Description This function is called to switch role between master and +** slave. If role is already set it will do nothing. If the +** command was initiated, the callback function is called upon +** completion. +** +** Returns BTM_SUCCESS if already in specified role. +** BTM_CMD_STARTED if command issued to controller. +** BTM_NO_RESOURCES if couldn't allocate memory to issue command +** BTM_UNKNOWN_ADDR if no active link with bd addr specified +** BTM_MODE_UNSUPPORTED if local device does not support role switching +** BTM_BUSY if the previous command is not completed +** +*******************************************************************************/ +tBTM_STATUS BTM_SwitchRole (BD_ADDR remote_bd_addr, UINT8 new_role, tBTM_CMPL_CB *p_cb) +{ + tACL_CONN *p; + tBTM_SEC_DEV_REC *p_dev_rec = NULL; +#if BTM_SCO_INCLUDED == TRUE + BOOLEAN is_sco_active; +#endif + tBTM_STATUS status; + tBTM_PM_MODE pwr_mode; + tBTM_PM_PWR_MD settings; +#if (BT_USE_TRACES == TRUE) + BD_ADDR_PTR p_bda; +#endif + BTM_TRACE_API ("BTM_SwitchRole BDA: %02x-%02x-%02x-%02x-%02x-%02x", + remote_bd_addr[0], remote_bd_addr[1], remote_bd_addr[2], + remote_bd_addr[3], remote_bd_addr[4], remote_bd_addr[5]); + + /* Make sure the local device supports switching */ + if (!controller_get_interface()->supports_master_slave_role_switch()) + return(BTM_MODE_UNSUPPORTED); + + if (btm_cb.devcb.p_switch_role_cb && p_cb) + { +#if (BT_USE_TRACES == TRUE) + p_bda = btm_cb.devcb.switch_role_ref_data.remote_bd_addr; + BTM_TRACE_DEBUG ("Role switch on other device is in progress 0x%02x%02x%02x%02x%02x%02x", + p_bda[0], p_bda[1], p_bda[2], + p_bda[3], p_bda[4], p_bda[5]); +#endif + return(BTM_BUSY); + } + + if ((p = btm_bda_to_acl(remote_bd_addr, BT_TRANSPORT_BR_EDR)) == NULL) + return(BTM_UNKNOWN_ADDR); + + /* Finished if already in desired role */ + if (p->link_role == new_role) + return(BTM_SUCCESS); + +#if BTM_SCO_INCLUDED == TRUE + /* Check if there is any SCO Active on this BD Address */ + is_sco_active = btm_is_sco_active_by_bdaddr(remote_bd_addr); + + if (is_sco_active == TRUE) + return(BTM_NO_RESOURCES); +#endif + + /* Ignore role switch request if the previous request was not completed */ + if (p->switch_role_state != BTM_ACL_SWKEY_STATE_IDLE) + { + BTM_TRACE_DEBUG ("BTM_SwitchRole busy: %d", + p->switch_role_state); + return(BTM_BUSY); + } + + if ((status = BTM_ReadPowerMode(p->remote_addr, &pwr_mode)) != BTM_SUCCESS) + return(status); + + /* Wake up the link if in sniff or park before attempting switch */ + if (pwr_mode == BTM_PM_MD_PARK || pwr_mode == BTM_PM_MD_SNIFF) + { + memset( (void*)&settings, 0, sizeof(settings)); + settings.mode = BTM_PM_MD_ACTIVE; + status = BTM_SetPowerMode (BTM_PM_SET_ONLY_ID, p->remote_addr, &settings); + if (status != BTM_CMD_STARTED) + return(BTM_WRONG_MODE); + + p->switch_role_state = BTM_ACL_SWKEY_STATE_MODE_CHANGE; + } + /* some devices do not support switch while encryption is on */ + else + { + p_dev_rec = btm_find_dev (remote_bd_addr); + if ((p_dev_rec != NULL) + && ((p_dev_rec->sec_flags & BTM_SEC_ENCRYPTED) != 0) + && !BTM_EPR_AVAILABLE(p)) + { + /* bypass turning off encryption if change link key is already doing it */ + if (p->encrypt_state != BTM_ACL_ENCRYPT_STATE_ENCRYPT_OFF) + { + if (!btsnd_hcic_set_conn_encrypt (p->hci_handle, FALSE)) + return(BTM_NO_RESOURCES); + else + p->encrypt_state = BTM_ACL_ENCRYPT_STATE_ENCRYPT_OFF; + } + + p->switch_role_state = BTM_ACL_SWKEY_STATE_ENCRYPTION_OFF; + } + else + { + if (!btsnd_hcic_switch_role (remote_bd_addr, new_role)) + return(BTM_NO_RESOURCES); + + p->switch_role_state = BTM_ACL_SWKEY_STATE_IN_PROGRESS; + +#if BTM_DISC_DURING_RS == TRUE + if (p_dev_rec) + p_dev_rec->rs_disc_pending = BTM_SEC_RS_PENDING; +#endif + } + } + + /* Initialize return structure in case request fails */ + if (p_cb) + { + memcpy (btm_cb.devcb.switch_role_ref_data.remote_bd_addr, remote_bd_addr, + BD_ADDR_LEN); + btm_cb.devcb.switch_role_ref_data.role = new_role; + /* initialized to an error code */ + btm_cb.devcb.switch_role_ref_data.hci_status = HCI_ERR_UNSUPPORTED_VALUE; + btm_cb.devcb.p_switch_role_cb = p_cb; + } + return(BTM_CMD_STARTED); +} + +/******************************************************************************* +** +** Function btm_acl_encrypt_change +** +** Description This function is when encryption of the connection is +** completed by the LM. Checks to see if a role switch or +** change of link key was active and initiates or continues +** process if needed. +** +** Returns void +** +*******************************************************************************/ +void btm_acl_encrypt_change (UINT16 handle, UINT8 status, UINT8 encr_enable) +{ + tACL_CONN *p; + UINT8 xx; + tBTM_SEC_DEV_REC *p_dev_rec; + tBTM_BL_ROLE_CHG_DATA evt; + + BTM_TRACE_DEBUG ("btm_acl_encrypt_change handle=%d status=%d encr_enabl=%d", + handle, status, encr_enable); + xx = btm_handle_to_acl_index(handle); + /* don't assume that we can never get a bad hci_handle */ + if (xx < MAX_L2CAP_LINKS) + p = &btm_cb.acl_db[xx]; + else + return; + + /* Process Role Switch if active */ + if (p->switch_role_state == BTM_ACL_SWKEY_STATE_ENCRYPTION_OFF) + { + /* if encryption turn off failed we still will try to switch role */ + if (encr_enable) + { + p->switch_role_state = BTM_ACL_SWKEY_STATE_IDLE; + p->encrypt_state = BTM_ACL_ENCRYPT_STATE_IDLE; + } + else + { + p->switch_role_state = BTM_ACL_SWKEY_STATE_SWITCHING; + p->encrypt_state = BTM_ACL_ENCRYPT_STATE_TEMP_FUNC; + } + + if (!btsnd_hcic_switch_role (p->remote_addr, (UINT8)!p->link_role)) + { + p->switch_role_state = BTM_ACL_SWKEY_STATE_IDLE; + p->encrypt_state = BTM_ACL_ENCRYPT_STATE_IDLE; + btm_acl_report_role_change(btm_cb.devcb.switch_role_ref_data.hci_status, p->remote_addr); + } +#if BTM_DISC_DURING_RS == TRUE + else + { + if ((p_dev_rec = btm_find_dev (p->remote_addr)) != NULL) + p_dev_rec->rs_disc_pending = BTM_SEC_RS_PENDING; + } +#endif + + } + /* Finished enabling Encryption after role switch */ + else if (p->switch_role_state == BTM_ACL_SWKEY_STATE_ENCRYPTION_ON) + { + p->switch_role_state = BTM_ACL_SWKEY_STATE_IDLE; + p->encrypt_state = BTM_ACL_ENCRYPT_STATE_IDLE; + btm_acl_report_role_change(btm_cb.devcb.switch_role_ref_data.hci_status, p->remote_addr); + + /* if role change event is registered, report it now */ + if (btm_cb.p_bl_changed_cb && (btm_cb.bl_evt_mask & BTM_BL_ROLE_CHG_MASK)) + { + evt.event = BTM_BL_ROLE_CHG_EVT; + evt.new_role = btm_cb.devcb.switch_role_ref_data.role; + evt.p_bda = btm_cb.devcb.switch_role_ref_data.remote_bd_addr; + evt.hci_status = btm_cb.devcb.switch_role_ref_data.hci_status; + (*btm_cb.p_bl_changed_cb)((tBTM_BL_EVENT_DATA *)&evt); + + BTM_TRACE_DEBUG("Role Switch Event: new_role 0x%02x, HCI Status 0x%02x, rs_st:%d", + evt.new_role, evt.hci_status, p->switch_role_state); + } + +#if BTM_DISC_DURING_RS == TRUE + /* If a disconnect is pending, issue it now that role switch has completed */ + if ((p_dev_rec = btm_find_dev (p->remote_addr)) != NULL) + { + if (p_dev_rec->rs_disc_pending == BTM_SEC_DISC_PENDING) + { + BTM_TRACE_WARNING("btm_acl_encrypt_change -> Issuing delayed HCI_Disconnect!!!"); + btsnd_hcic_disconnect(p_dev_rec->hci_handle, HCI_ERR_PEER_USER); + } + BTM_TRACE_ERROR("btm_acl_encrypt_change: tBTM_SEC_DEV:0x%x rs_disc_pending=%d", + (UINT32)p_dev_rec, p_dev_rec->rs_disc_pending); + p_dev_rec->rs_disc_pending = BTM_SEC_RS_NOT_PENDING; /* reset flag */ + } +#endif + } +} +/******************************************************************************* +** +** Function BTM_SetLinkPolicy +** +** Description Create and send HCI "Write Policy Set" command +** +** Returns status of the operation +** +*******************************************************************************/ +tBTM_STATUS BTM_SetLinkPolicy (BD_ADDR remote_bda, UINT16 *settings) +{ + tACL_CONN *p; + UINT8 *localFeatures = BTM_ReadLocalFeatures(); + BTM_TRACE_DEBUG ("BTM_SetLinkPolicy"); +/* BTM_TRACE_API ("BTM_SetLinkPolicy: requested settings: 0x%04x", *settings ); */ + + /* First, check if hold mode is supported */ + if (*settings != HCI_DISABLE_ALL_LM_MODES) + { + if ( (*settings & HCI_ENABLE_MASTER_SLAVE_SWITCH) && (!HCI_SWITCH_SUPPORTED(localFeatures)) ) + { + *settings &= (~HCI_ENABLE_MASTER_SLAVE_SWITCH); + BTM_TRACE_API ("BTM_SetLinkPolicy switch not supported (settings: 0x%04x)", *settings ); + } + if ( (*settings & HCI_ENABLE_HOLD_MODE) && (!HCI_HOLD_MODE_SUPPORTED(localFeatures)) ) + { + *settings &= (~HCI_ENABLE_HOLD_MODE); + BTM_TRACE_API ("BTM_SetLinkPolicy hold not supported (settings: 0x%04x)", *settings ); + } + if ( (*settings & HCI_ENABLE_SNIFF_MODE) && (!HCI_SNIFF_MODE_SUPPORTED(localFeatures)) ) + { + *settings &= (~HCI_ENABLE_SNIFF_MODE); + BTM_TRACE_API ("BTM_SetLinkPolicy sniff not supported (settings: 0x%04x)", *settings ); + } + if ( (*settings & HCI_ENABLE_PARK_MODE) && (!HCI_PARK_MODE_SUPPORTED(localFeatures)) ) + { + *settings &= (~HCI_ENABLE_PARK_MODE); + BTM_TRACE_API ("BTM_SetLinkPolicy park not supported (settings: 0x%04x)", *settings ); + } + } + + if ((p = btm_bda_to_acl(remote_bda, BT_TRANSPORT_BR_EDR)) != NULL) + return(btsnd_hcic_write_policy_set (p->hci_handle, *settings) ? BTM_CMD_STARTED : BTM_NO_RESOURCES); + + /* If here, no BD Addr found */ + return(BTM_UNKNOWN_ADDR); +} + +/******************************************************************************* +** +** Function BTM_SetDefaultLinkPolicy +** +** Description Set the default value for HCI "Write Policy Set" command +** to use when an ACL link is created. +** +** Returns void +** +*******************************************************************************/ +void BTM_SetDefaultLinkPolicy (UINT16 settings) +{ + UINT8 *localFeatures = BTM_ReadLocalFeatures(); + + BTM_TRACE_DEBUG("BTM_SetDefaultLinkPolicy setting:0x%04x", settings); + + if((settings & HCI_ENABLE_MASTER_SLAVE_SWITCH) && (!HCI_SWITCH_SUPPORTED(localFeatures))) + { + settings &= ~HCI_ENABLE_MASTER_SLAVE_SWITCH; + BTM_TRACE_DEBUG("BTM_SetDefaultLinkPolicy switch not supported (settings: 0x%04x)", settings); + } + if ((settings & HCI_ENABLE_HOLD_MODE) && (!HCI_HOLD_MODE_SUPPORTED(localFeatures))) + { + settings &= ~HCI_ENABLE_HOLD_MODE; + BTM_TRACE_DEBUG("BTM_SetDefaultLinkPolicy hold not supported (settings: 0x%04x)", settings); + } + if ((settings & HCI_ENABLE_SNIFF_MODE) && (!HCI_SNIFF_MODE_SUPPORTED(localFeatures))) + { + settings &= ~HCI_ENABLE_SNIFF_MODE; + BTM_TRACE_DEBUG("BTM_SetDefaultLinkPolicy sniff not supported (settings: 0x%04x)", settings); + } + if ((settings & HCI_ENABLE_PARK_MODE) && (!HCI_PARK_MODE_SUPPORTED(localFeatures))) + { + settings &= ~HCI_ENABLE_PARK_MODE; + BTM_TRACE_DEBUG("BTM_SetDefaultLinkPolicy park not supported (settings: 0x%04x)", settings); + } + BTM_TRACE_DEBUG("Set DefaultLinkPolicy:0x%04x", settings); + + btm_cb.btm_def_link_policy = settings; + + /* Set the default Link Policy of the controller */ + btsnd_hcic_write_def_policy_set(settings); +} + +/******************************************************************************* +** +** Function btm_read_remote_version_complete +** +** Description This function is called when the command complete message +** is received from the HCI for the remote version info. +** +** Returns void +** +*******************************************************************************/ +void btm_read_remote_version_complete (UINT8 *p) +{ + tACL_CONN *p_acl_cb = &btm_cb.acl_db[0]; + UINT8 status; + UINT16 handle; + int xx; + BTM_TRACE_DEBUG ("btm_read_remote_version_complete"); + + STREAM_TO_UINT8 (status, p); + STREAM_TO_UINT16 (handle, p); + + /* Look up the connection by handle and copy features */ + for (xx = 0; xx < MAX_L2CAP_LINKS; xx++, p_acl_cb++) + { + if ((p_acl_cb->in_use) && (p_acl_cb->hci_handle == handle)) + { + if (status == HCI_SUCCESS) + { + STREAM_TO_UINT8 (p_acl_cb->lmp_version, p); + STREAM_TO_UINT16 (p_acl_cb->manufacturer, p); + STREAM_TO_UINT16 (p_acl_cb->lmp_subversion, p); + } +#if BLE_INCLUDED == TRUE + if (p_acl_cb->transport == BT_TRANSPORT_LE) + l2cble_notify_le_connection (p_acl_cb->remote_addr); +#endif + break; + } + } +} + + +/******************************************************************************* +** +** Function btm_process_remote_ext_features +** +** Description Local function called to process all extended features pages +** read from a remote device. +** +** Returns void +** +*******************************************************************************/ +void btm_process_remote_ext_features (tACL_CONN *p_acl_cb, UINT8 num_read_pages) +{ + UINT16 handle = p_acl_cb->hci_handle; + tBTM_SEC_DEV_REC *p_dev_rec = btm_find_dev_by_handle (handle); + UINT8 page_idx; + + BTM_TRACE_DEBUG ("btm_process_remote_ext_features"); + + /* Make sure we have the record to save remote features information */ + if (p_dev_rec == NULL) + { + /* Get a new device; might be doing dedicated bonding */ + p_dev_rec = btm_find_or_alloc_dev (p_acl_cb->remote_addr); + } + + p_acl_cb->num_read_pages = num_read_pages; + p_dev_rec->num_read_pages = num_read_pages; + + /* Move the pages to placeholder */ + for (page_idx = 0; page_idx < num_read_pages; page_idx++) + { + if (page_idx > HCI_EXT_FEATURES_PAGE_MAX) + { + BTM_TRACE_ERROR("%s: page=%d unexpected", __FUNCTION__, page_idx); + break; + } + memcpy (p_dev_rec->features[page_idx], p_acl_cb->peer_lmp_features[page_idx], + HCI_FEATURE_BYTES_PER_PAGE); + } + + const UINT8 req_pend = (p_dev_rec->sm4 & BTM_SM4_REQ_PEND); + + /* Store the Peer Security Capabilites (in SM4 and rmt_sec_caps) */ + btm_sec_set_peer_sec_caps(p_acl_cb, p_dev_rec); + + BTM_TRACE_API("%s: pend:%d", __FUNCTION__, req_pend); + if (req_pend) + { + /* Request for remaining Security Features (if any) */ + l2cu_resubmit_pending_sec_req (p_dev_rec->bd_addr); + } +} + + +/******************************************************************************* +** +** Function btm_read_remote_features +** +** Description Local function called to send a read remote supported features/ +** remote extended features page[0]. +** +** Returns void +** +*******************************************************************************/ +void btm_read_remote_features (UINT16 handle) +{ + UINT8 acl_idx; + tACL_CONN *p_acl_cb; + + BTM_TRACE_DEBUG("btm_read_remote_features() handle: %d", handle); + + if ((acl_idx = btm_handle_to_acl_index(handle)) >= MAX_L2CAP_LINKS) + { + BTM_TRACE_ERROR("btm_read_remote_features handle=%d invalid", handle); + return; + } + + p_acl_cb = &btm_cb.acl_db[acl_idx]; + p_acl_cb->num_read_pages = 0; + memset (p_acl_cb->peer_lmp_features, 0, sizeof(p_acl_cb->peer_lmp_features)); + + /* first send read remote supported features HCI command */ + /* because we don't know whether the remote support extended feature command */ + btsnd_hcic_rmt_features_req (handle); +} + + +/******************************************************************************* +** +** Function btm_read_remote_ext_features +** +** Description Local function called to send a read remote extended features +** +** Returns void +** +*******************************************************************************/ +void btm_read_remote_ext_features (UINT16 handle, UINT8 page_number) +{ + BTM_TRACE_DEBUG("btm_read_remote_ext_features() handle: %d page: %d", handle, page_number); + + btsnd_hcic_rmt_ext_features(handle, page_number); +} + + +/******************************************************************************* +** +** Function btm_read_remote_features_complete +** +** Description This function is called when the remote supported features +** complete event is received from the HCI. +** +** Returns void +** +*******************************************************************************/ +void btm_read_remote_features_complete (UINT8 *p) +{ + tACL_CONN *p_acl_cb; + UINT8 status; + UINT16 handle; + UINT8 acl_idx; + + BTM_TRACE_DEBUG ("btm_read_remote_features_complete"); + STREAM_TO_UINT8 (status, p); + + if (status != HCI_SUCCESS) + { + BTM_TRACE_ERROR ("btm_read_remote_features_complete failed (status 0x%02x)", status); + return; + } + + STREAM_TO_UINT16 (handle, p); + + if ((acl_idx = btm_handle_to_acl_index(handle)) >= MAX_L2CAP_LINKS) + { + BTM_TRACE_ERROR("btm_read_remote_features_complete handle=%d invalid", handle); + return; + } + + p_acl_cb = &btm_cb.acl_db[acl_idx]; + + /* Copy the received features page */ + STREAM_TO_ARRAY(p_acl_cb->peer_lmp_features[HCI_EXT_FEATURES_PAGE_0], p, + HCI_FEATURE_BYTES_PER_PAGE); + + if ((HCI_LMP_EXTENDED_SUPPORTED(p_acl_cb->peer_lmp_features[HCI_EXT_FEATURES_PAGE_0])) && + (controller_get_interface()->supports_reading_remote_extended_features())) + { + /* if the remote controller has extended features and local controller supports + ** HCI_Read_Remote_Extended_Features command then start reading these feature starting + ** with extended features page 1 */ + BTM_TRACE_DEBUG ("Start reading remote extended features"); + btm_read_remote_ext_features(handle, HCI_EXT_FEATURES_PAGE_1); + return; + } + + /* Remote controller has no extended features. Process remote controller supported features + (features page HCI_EXT_FEATURES_PAGE_0). */ + btm_process_remote_ext_features (p_acl_cb, 1); + + /* Continue with HCI connection establishment */ + btm_establish_continue (p_acl_cb); +} + +/******************************************************************************* +** +** Function btm_read_remote_ext_features_complete +** +** Description This function is called when the remote extended features +** complete event is received from the HCI. +** +** Returns void +** +*******************************************************************************/ +void btm_read_remote_ext_features_complete (UINT8 *p) +{ + tACL_CONN *p_acl_cb; + UINT8 page_num, max_page; + UINT16 handle; + UINT8 acl_idx; + + BTM_TRACE_DEBUG ("btm_read_remote_ext_features_complete"); + + ++p; + STREAM_TO_UINT16 (handle, p); + STREAM_TO_UINT8 (page_num, p); + STREAM_TO_UINT8 (max_page, p); + + /* Validate parameters */ + if ((acl_idx = btm_handle_to_acl_index(handle)) >= MAX_L2CAP_LINKS) + { + BTM_TRACE_ERROR("btm_read_remote_ext_features_complete handle=%d invalid", handle); + return; + } + + if (max_page > HCI_EXT_FEATURES_PAGE_MAX) + { + BTM_TRACE_ERROR("btm_read_remote_ext_features_complete page=%d unknown", max_page); + return; + } + + p_acl_cb = &btm_cb.acl_db[acl_idx]; + + /* Copy the received features page */ + STREAM_TO_ARRAY(p_acl_cb->peer_lmp_features[page_num], p, HCI_FEATURE_BYTES_PER_PAGE); + + /* If there is the next remote features page and + * we have space to keep this page data - read this page */ + if ((page_num < max_page) && (page_num < HCI_EXT_FEATURES_PAGE_MAX)) + { + page_num++; + BTM_TRACE_DEBUG("BTM reads next remote extended features page (%d)", page_num); + btm_read_remote_ext_features (handle, page_num); + return; + } + + /* Reading of remote feature pages is complete */ + BTM_TRACE_DEBUG("BTM reached last remote extended features page (%d)", page_num); + + /* Process the pages */ + btm_process_remote_ext_features (p_acl_cb, (UINT8) (page_num + 1)); + + /* Continue with HCI connection establishment */ + btm_establish_continue (p_acl_cb); +} + +/******************************************************************************* +** +** Function btm_read_remote_ext_features_failed +** +** Description This function is called when the remote extended features +** complete event returns a failed status. +** +** Returns void +** +*******************************************************************************/ +void btm_read_remote_ext_features_failed (UINT8 status, UINT16 handle) +{ + tACL_CONN *p_acl_cb; + UINT8 acl_idx; + + BTM_TRACE_WARNING ("btm_read_remote_ext_features_failed (status 0x%02x) for handle %d", + status, handle); + + if ((acl_idx = btm_handle_to_acl_index(handle)) >= MAX_L2CAP_LINKS) + { + BTM_TRACE_ERROR("btm_read_remote_ext_features_failed handle=%d invalid", handle); + return; + } + + p_acl_cb = &btm_cb.acl_db[acl_idx]; + + /* Process supported features only */ + btm_process_remote_ext_features (p_acl_cb, 1); + + /* Continue HCI connection establishment */ + btm_establish_continue (p_acl_cb); +} + +/******************************************************************************* +** +** Function btm_establish_continue +** +** Description This function is called when the command complete message +** is received from the HCI for the read local link policy request. +** +** Returns void +** +*******************************************************************************/ +void btm_establish_continue (tACL_CONN *p_acl_cb) +{ + tBTM_BL_EVENT_DATA evt_data; + BTM_TRACE_DEBUG ("btm_establish_continue"); +#if (!defined(BTM_BYPASS_EXTRA_ACL_SETUP) || BTM_BYPASS_EXTRA_ACL_SETUP == FALSE) +#if (defined BLE_INCLUDED && BLE_INCLUDED == TRUE) + if (p_acl_cb->transport == BT_TRANSPORT_BR_EDR) +#endif + { + /* For now there are a some devices that do not like sending */ + /* commands events and data at the same time. */ + /* Set the packet types to the default allowed by the device */ + btm_set_packet_types (p_acl_cb, btm_cb.btm_acl_pkt_types_supported); + + if (btm_cb.btm_def_link_policy) + BTM_SetLinkPolicy (p_acl_cb->remote_addr, &btm_cb.btm_def_link_policy); + } +#endif + p_acl_cb->link_up_issued = TRUE; + + /* If anyone cares, tell him database changed */ + if (btm_cb.p_bl_changed_cb) + { + evt_data.event = BTM_BL_CONN_EVT; + evt_data.conn.p_bda = p_acl_cb->remote_addr; + evt_data.conn.p_bdn = p_acl_cb->remote_name; + evt_data.conn.p_dc = p_acl_cb->remote_dc; + evt_data.conn.p_features = p_acl_cb->peer_lmp_features[HCI_EXT_FEATURES_PAGE_0]; +#if BLE_INCLUDED == TRUE + evt_data.conn.handle = p_acl_cb->hci_handle; + evt_data.conn.transport = p_acl_cb->transport; +#endif + + (*btm_cb.p_bl_changed_cb)(&evt_data); + } + btm_acl_update_busy_level (BTM_BLI_ACL_UP_EVT); +} + + +/******************************************************************************* +** +** Function BTM_SetDefaultLinkSuperTout +** +** Description Set the default value for HCI "Write Link Supervision Timeout" +** command to use when an ACL link is created. +** +** Returns void +** +*******************************************************************************/ +void BTM_SetDefaultLinkSuperTout (UINT16 timeout) +{ + BTM_TRACE_DEBUG ("BTM_SetDefaultLinkSuperTout"); + btm_cb.btm_def_link_super_tout = timeout; +} + +/******************************************************************************* +** +** Function BTM_GetLinkSuperTout +** +** Description Read the link supervision timeout value of the connection +** +** Returns status of the operation +** +*******************************************************************************/ +tBTM_STATUS BTM_GetLinkSuperTout (BD_ADDR remote_bda, UINT16 *p_timeout) +{ + tACL_CONN *p = btm_bda_to_acl(remote_bda, BT_TRANSPORT_BR_EDR); + + BTM_TRACE_DEBUG ("BTM_GetLinkSuperTout"); + if (p != (tACL_CONN *)NULL) + { + *p_timeout = p->link_super_tout; + return(BTM_SUCCESS); + } + /* If here, no BD Addr found */ + return(BTM_UNKNOWN_ADDR); +} + + +/******************************************************************************* +** +** Function BTM_SetLinkSuperTout +** +** Description Create and send HCI "Write Link Supervision Timeout" command +** +** Returns status of the operation +** +*******************************************************************************/ +tBTM_STATUS BTM_SetLinkSuperTout (BD_ADDR remote_bda, UINT16 timeout) +{ + tACL_CONN *p = btm_bda_to_acl(remote_bda, BT_TRANSPORT_BR_EDR); + + BTM_TRACE_DEBUG ("BTM_SetLinkSuperTout"); + if (p != (tACL_CONN *)NULL) + { + p->link_super_tout = timeout; + + /* Only send if current role is Master; 2.0 spec requires this */ + if (p->link_role == BTM_ROLE_MASTER) + { + if (!btsnd_hcic_write_link_super_tout (LOCAL_BR_EDR_CONTROLLER_ID, + p->hci_handle, timeout)) + return(BTM_NO_RESOURCES); + + return(BTM_CMD_STARTED); + } + else + return(BTM_SUCCESS); + } + + /* If here, no BD Addr found */ + return(BTM_UNKNOWN_ADDR); +} + +/******************************************************************************* +** +** Function BTM_IsAclConnectionUp +** +** Description This function is called to check if an ACL connection exists +** to a specific remote BD Address. +** +** Returns TRUE if connection is up, else FALSE. +** +*******************************************************************************/ +BOOLEAN BTM_IsAclConnectionUp (BD_ADDR remote_bda, tBT_TRANSPORT transport) +{ + tACL_CONN *p; + + BTM_TRACE_API ("BTM_IsAclConnectionUp: RemBdAddr: %02x%02x%02x%02x%02x%02x", + remote_bda[0], remote_bda[1], remote_bda[2], + remote_bda[3], remote_bda[4], remote_bda[5]); + + p = btm_bda_to_acl(remote_bda, transport); + if (p != (tACL_CONN *)NULL) + { + return(TRUE); + } + + /* If here, no BD Addr found */ + return(FALSE); +} + +/******************************************************************************* +** +** Function BTM_GetNumAclLinks +** +** Description This function is called to count the number of +** ACL links that are active. +** +** Returns UINT16 Number of active ACL links +** +*******************************************************************************/ +UINT16 BTM_GetNumAclLinks (void) +{ + uint16_t num_acl = 0; + + for (uint16_t i = 0; i < MAX_L2CAP_LINKS; ++i) + { + if (btm_cb.acl_db[i].in_use) + ++num_acl; + } + + return num_acl; +} + +/******************************************************************************* +** +** Function btm_get_acl_disc_reason_code +** +** Description This function is called to get the disconnection reason code +** returned by the HCI at disconnection complete event. +** +** Returns TRUE if connection is up, else FALSE. +** +*******************************************************************************/ +UINT16 btm_get_acl_disc_reason_code (void) +{ + UINT8 res = btm_cb.acl_disc_reason; + BTM_TRACE_DEBUG ("btm_get_acl_disc_reason_code"); + return(res); +} + + +/******************************************************************************* +** +** Function BTM_GetHCIConnHandle +** +** Description This function is called to get the handle for an ACL connection +** to a specific remote BD Address. +** +** Returns the handle of the connection, or 0xFFFF if none. +** +*******************************************************************************/ +UINT16 BTM_GetHCIConnHandle (BD_ADDR remote_bda, tBT_TRANSPORT transport) +{ + tACL_CONN *p; + BTM_TRACE_DEBUG ("BTM_GetHCIConnHandle"); + p = btm_bda_to_acl(remote_bda, transport); + if (p != (tACL_CONN *)NULL) + { + return(p->hci_handle); + } + + /* If here, no BD Addr found */ + return(0xFFFF); +} + +/******************************************************************************* +** +** Function btm_process_clk_off_comp_evt +** +** Description This function is called when clock offset command completes. +** +** Input Parms hci_handle - connection handle associated with the change +** clock offset +** +** Returns void +** +*******************************************************************************/ +void btm_process_clk_off_comp_evt (UINT16 hci_handle, UINT16 clock_offset) +{ + UINT8 xx; + BTM_TRACE_DEBUG ("btm_process_clk_off_comp_evt"); + /* Look up the connection by handle and set the current mode */ + if ((xx = btm_handle_to_acl_index(hci_handle)) < MAX_L2CAP_LINKS) + btm_cb.acl_db[xx].clock_offset = clock_offset; +} + +/******************************************************************************* +** +** Function btm_acl_role_changed +** +** Description This function is called whan a link's master/slave role change +** event or command status event (with error) is received. +** It updates the link control block, and calls +** the registered callback with status and role (if registered). +** +** Returns void +** +*******************************************************************************/ +void btm_acl_role_changed (UINT8 hci_status, BD_ADDR bd_addr, UINT8 new_role) +{ + UINT8 *p_bda = (bd_addr) ? bd_addr : + btm_cb.devcb.switch_role_ref_data.remote_bd_addr; + tACL_CONN *p = btm_bda_to_acl(p_bda, BT_TRANSPORT_BR_EDR); + tBTM_ROLE_SWITCH_CMPL *p_data = &btm_cb.devcb.switch_role_ref_data; + tBTM_SEC_DEV_REC *p_dev_rec; + tBTM_BL_ROLE_CHG_DATA evt; + + BTM_TRACE_DEBUG ("btm_acl_role_changed"); + /* Ignore any stray events */ + if (p == NULL) + { + /* it could be a failure */ + if (hci_status != HCI_SUCCESS) + btm_acl_report_role_change(hci_status, bd_addr); + return; + } + + p_data->hci_status = hci_status; + + if (hci_status == HCI_SUCCESS) + { + p_data->role = new_role; + memcpy(p_data->remote_bd_addr, p_bda, BD_ADDR_LEN); + + /* Update cached value */ + p->link_role = new_role; + + /* Reload LSTO: link supervision timeout is reset in the LM after a role switch */ + if (new_role == BTM_ROLE_MASTER) + { + BTM_SetLinkSuperTout (p->remote_addr, p->link_super_tout); + } + } + else + { + /* so the BTM_BL_ROLE_CHG_EVT uses the old role */ + new_role = p->link_role; + } + + /* Check if any SCO req is pending for role change */ + btm_sco_chk_pend_rolechange (p->hci_handle); + + /* if switching state is switching we need to turn encryption on */ + /* if idle, we did not change encryption */ + if (p->switch_role_state == BTM_ACL_SWKEY_STATE_SWITCHING) + { + if (btsnd_hcic_set_conn_encrypt (p->hci_handle, TRUE)) + { + p->encrypt_state = BTM_ACL_ENCRYPT_STATE_ENCRYPT_ON; + p->switch_role_state = BTM_ACL_SWKEY_STATE_ENCRYPTION_ON; + return; + } + } + + /* Set the switch_role_state to IDLE since the reply received from HCI */ + /* regardless of its result either success or failed. */ + if (p->switch_role_state == BTM_ACL_SWKEY_STATE_IN_PROGRESS) + { + p->switch_role_state = BTM_ACL_SWKEY_STATE_IDLE; + p->encrypt_state = BTM_ACL_ENCRYPT_STATE_IDLE; + } + + /* if role switch complete is needed, report it now */ + btm_acl_report_role_change(hci_status, bd_addr); + + /* if role change event is registered, report it now */ + if (btm_cb.p_bl_changed_cb && (btm_cb.bl_evt_mask & BTM_BL_ROLE_CHG_MASK)) + { + evt.event = BTM_BL_ROLE_CHG_EVT; + evt.new_role = new_role; + evt.p_bda = p_bda; + evt.hci_status = hci_status; + (*btm_cb.p_bl_changed_cb)((tBTM_BL_EVENT_DATA *)&evt); + } + + BTM_TRACE_DEBUG("Role Switch Event: new_role 0x%02x, HCI Status 0x%02x, rs_st:%d", + p_data->role, p_data->hci_status, p->switch_role_state); + +#if BTM_DISC_DURING_RS == TRUE + /* If a disconnect is pending, issue it now that role switch has completed */ + if ((p_dev_rec = btm_find_dev (p_bda)) != NULL) + { + if (p_dev_rec->rs_disc_pending == BTM_SEC_DISC_PENDING) + { + BTM_TRACE_WARNING("btm_acl_role_changed -> Issuing delayed HCI_Disconnect!!!"); + btsnd_hcic_disconnect(p_dev_rec->hci_handle, HCI_ERR_PEER_USER); + } + BTM_TRACE_ERROR("tBTM_SEC_DEV:0x%x rs_disc_pending=%d", + (UINT32)p_dev_rec, p_dev_rec->rs_disc_pending); + p_dev_rec->rs_disc_pending = BTM_SEC_RS_NOT_PENDING; /* reset flag */ + } + +#endif + +} + +/******************************************************************************* +** +** Function BTM_AllocateSCN +** +** Description Look through the Server Channel Numbers for a free one. +** +** Returns Allocated SCN number or 0 if none. +** +*******************************************************************************/ + +UINT8 BTM_AllocateSCN(void) +{ + UINT8 x; + BTM_TRACE_DEBUG ("BTM_AllocateSCN"); + + // stack reserves scn 1 for HFP, HSP we still do the correct way + for (x = 1; x < BTM_MAX_SCN; x++) + { + if (!btm_cb.btm_scn[x]) + { + btm_cb.btm_scn[x] = TRUE; + return(x+1); + } + } + + return(0); /* No free ports */ +} + +/******************************************************************************* +** +** Function BTM_TryAllocateSCN +** +** Description Try to allocate a fixed server channel +** +** Returns Returns TRUE if server channel was available +** +*******************************************************************************/ + +BOOLEAN BTM_TryAllocateSCN(UINT8 scn) +{ + /* Make sure we don't exceed max port range. + * Stack reserves scn 1 for HFP, HSP we still do the correct way. + */ + if ( (scn>=BTM_MAX_SCN) || (scn == 1) ) + return FALSE; + + /* check if this port is available */ + if (!btm_cb.btm_scn[scn-1]) + { + btm_cb.btm_scn[scn-1] = TRUE; + return TRUE; + } + + return (FALSE); /* Port was busy */ +} + +/******************************************************************************* +** +** Function BTM_FreeSCN +** +** Description Free the specified SCN. +** +** Returns TRUE or FALSE +** +*******************************************************************************/ +BOOLEAN BTM_FreeSCN(UINT8 scn) +{ + BTM_TRACE_DEBUG ("BTM_FreeSCN "); + if (scn <= BTM_MAX_SCN) + { + btm_cb.btm_scn[scn-1] = FALSE; + return(TRUE); + } + else + return(FALSE); /* Illegal SCN passed in */ +} + +/******************************************************************************* +** +** Function btm_set_packet_types +** +** Description This function sets the packet types used for a specific +** ACL connection. It is called internally by btm_acl_created +** or by an application/profile by BTM_SetPacketTypes. +** +** Returns status of the operation +** +*******************************************************************************/ +tBTM_STATUS btm_set_packet_types (tACL_CONN *p, UINT16 pkt_types) +{ + UINT16 temp_pkt_types; + BTM_TRACE_DEBUG ("btm_set_packet_types"); + /* Save in the ACL control blocks, types that we support */ + temp_pkt_types = (pkt_types & BTM_ACL_SUPPORTED_PKTS_MASK & + btm_cb.btm_acl_pkt_types_supported); + + /* OR in any exception packet types if at least 2.0 version of spec */ + temp_pkt_types |= ((pkt_types & BTM_ACL_EXCEPTION_PKTS_MASK) | + (btm_cb.btm_acl_pkt_types_supported & BTM_ACL_EXCEPTION_PKTS_MASK)); + + /* Exclude packet types not supported by the peer */ + btm_acl_chk_peer_pkt_type_support (p, &temp_pkt_types); + + BTM_TRACE_DEBUG ("SetPacketType Mask -> 0x%04x", temp_pkt_types); + + if (!btsnd_hcic_change_conn_type (p->hci_handle, temp_pkt_types)) + { + return(BTM_NO_RESOURCES); + } + + p->pkt_types_mask = temp_pkt_types; + + return(BTM_CMD_STARTED); +} + +/******************************************************************************* +** +** Function btm_get_max_packet_size +** +** Returns Returns maximum packet size that can be used for current +** connection, 0 if connection is not established +** +*******************************************************************************/ +UINT16 btm_get_max_packet_size (BD_ADDR addr) +{ + tACL_CONN *p = btm_bda_to_acl(addr, BT_TRANSPORT_BR_EDR); + UINT16 pkt_types = 0; + UINT16 pkt_size = 0; + BTM_TRACE_DEBUG ("btm_get_max_packet_size"); + if (p != NULL) + { + pkt_types = p->pkt_types_mask; + } + else + { + /* Special case for when info for the local device is requested */ + if (memcmp (controller_get_interface()->get_address(), addr, BD_ADDR_LEN) == 0) + { + pkt_types = btm_cb.btm_acl_pkt_types_supported; + } + } + + if (pkt_types) + { + if (!(pkt_types & BTM_ACL_PKT_TYPES_MASK_NO_3_DH5)) + pkt_size = HCI_EDR3_DH5_PACKET_SIZE; + else if (!(pkt_types & BTM_ACL_PKT_TYPES_MASK_NO_2_DH5)) + pkt_size = HCI_EDR2_DH5_PACKET_SIZE; + else if (!(pkt_types & BTM_ACL_PKT_TYPES_MASK_NO_3_DH3)) + pkt_size = HCI_EDR3_DH3_PACKET_SIZE; + else if (pkt_types & BTM_ACL_PKT_TYPES_MASK_DH5) + pkt_size = HCI_DH5_PACKET_SIZE; + else if (!(pkt_types & BTM_ACL_PKT_TYPES_MASK_NO_2_DH3)) + pkt_size = HCI_EDR2_DH3_PACKET_SIZE; + else if (pkt_types & BTM_ACL_PKT_TYPES_MASK_DM5) + pkt_size = HCI_DM5_PACKET_SIZE; + else if (pkt_types & BTM_ACL_PKT_TYPES_MASK_DH3) + pkt_size = HCI_DH3_PACKET_SIZE; + else if (pkt_types & BTM_ACL_PKT_TYPES_MASK_DM3) + pkt_size = HCI_DM3_PACKET_SIZE; + else if (!(pkt_types & BTM_ACL_PKT_TYPES_MASK_NO_3_DH1)) + pkt_size = HCI_EDR3_DH1_PACKET_SIZE; + else if (!(pkt_types & BTM_ACL_PKT_TYPES_MASK_NO_2_DH1)) + pkt_size = HCI_EDR2_DH1_PACKET_SIZE; + else if (pkt_types & BTM_ACL_PKT_TYPES_MASK_DH1) + pkt_size = HCI_DH1_PACKET_SIZE; + else if (pkt_types & BTM_ACL_PKT_TYPES_MASK_DM1) + pkt_size = HCI_DM1_PACKET_SIZE; + } + + return(pkt_size); +} + +/******************************************************************************* +** +** Function BTM_ReadRemoteVersion +** +** Returns If connected report peer device info +** +*******************************************************************************/ +tBTM_STATUS BTM_ReadRemoteVersion (BD_ADDR addr, UINT8 *lmp_version, + UINT16 *manufacturer, UINT16 *lmp_sub_version) +{ + tACL_CONN *p = btm_bda_to_acl(addr, BT_TRANSPORT_BR_EDR); + BTM_TRACE_DEBUG ("BTM_ReadRemoteVersion"); + if (p == NULL) + return(BTM_UNKNOWN_ADDR); + + if (lmp_version) + *lmp_version = p->lmp_version; + + if (manufacturer) + *manufacturer = p->manufacturer; + + if (lmp_sub_version) + *lmp_sub_version = p->lmp_subversion; + + return(BTM_SUCCESS); +} + +/******************************************************************************* +** +** Function BTM_ReadRemoteFeatures +** +** Returns pointer to the remote supported features mask (8 bytes) +** +*******************************************************************************/ +UINT8 *BTM_ReadRemoteFeatures (BD_ADDR addr) +{ + tACL_CONN *p = btm_bda_to_acl(addr, BT_TRANSPORT_BR_EDR); + BTM_TRACE_DEBUG ("BTM_ReadRemoteFeatures"); + if (p == NULL) + { + return(NULL); + } + + return(p->peer_lmp_features[HCI_EXT_FEATURES_PAGE_0]); +} + +/******************************************************************************* +** +** Function BTM_ReadRemoteExtendedFeatures +** +** Returns pointer to the remote extended features mask (8 bytes) +** or NULL if bad page +** +*******************************************************************************/ +UINT8 *BTM_ReadRemoteExtendedFeatures (BD_ADDR addr, UINT8 page_number) +{ + tACL_CONN *p = btm_bda_to_acl(addr, BT_TRANSPORT_BR_EDR); + BTM_TRACE_DEBUG ("BTM_ReadRemoteExtendedFeatures"); + if (p == NULL) + { + return(NULL); + } + + if (page_number > HCI_EXT_FEATURES_PAGE_MAX) + { + BTM_TRACE_ERROR("Warning: BTM_ReadRemoteExtendedFeatures page %d unknown", page_number); + return NULL; + } + + return(p->peer_lmp_features[page_number]); +} + +/******************************************************************************* +** +** Function BTM_ReadNumberRemoteFeaturesPages +** +** Returns number of features pages read from the remote device. +** +*******************************************************************************/ +UINT8 BTM_ReadNumberRemoteFeaturesPages (BD_ADDR addr) +{ + tACL_CONN *p = btm_bda_to_acl(addr, BT_TRANSPORT_BR_EDR); + BTM_TRACE_DEBUG ("BTM_ReadNumberRemoteFeaturesPages"); + if (p == NULL) + { + return(0); + } + + return(p->num_read_pages); +} + +/******************************************************************************* +** +** Function BTM_ReadAllRemoteFeatures +** +** Returns pointer to all features of the remote (24 bytes). +** +*******************************************************************************/ +UINT8 *BTM_ReadAllRemoteFeatures (BD_ADDR addr) +{ + tACL_CONN *p = btm_bda_to_acl(addr, BT_TRANSPORT_BR_EDR); + BTM_TRACE_DEBUG ("BTM_ReadAllRemoteFeatures"); + if (p == NULL) + { + return(NULL); + } + + return(p->peer_lmp_features[HCI_EXT_FEATURES_PAGE_0]); +} + +/******************************************************************************* +** +** Function BTM_RegBusyLevelNotif +** +** Description This function is called to register a callback to receive +** busy level change events. +** +** Returns BTM_SUCCESS if successfully registered, otherwise error +** +*******************************************************************************/ +tBTM_STATUS BTM_RegBusyLevelNotif (tBTM_BL_CHANGE_CB *p_cb, UINT8 *p_level, + tBTM_BL_EVENT_MASK evt_mask) +{ + BTM_TRACE_DEBUG ("BTM_RegBusyLevelNotif"); + if (p_level) + *p_level = btm_cb.busy_level; + + btm_cb.bl_evt_mask = evt_mask; + + if (!p_cb) + btm_cb.p_bl_changed_cb = NULL; + else if (btm_cb.p_bl_changed_cb) + return(BTM_BUSY); + else + btm_cb.p_bl_changed_cb = p_cb; + + return(BTM_SUCCESS); +} + +/******************************************************************************* +** +** Function BTM_SetQoS +** +** Description This function is called to setup QoS +** +** Returns status of the operation +** +*******************************************************************************/ +tBTM_STATUS BTM_SetQoS (BD_ADDR bd, FLOW_SPEC *p_flow, tBTM_CMPL_CB *p_cb) +{ + tACL_CONN *p = &btm_cb.acl_db[0]; + + BTM_TRACE_API ("BTM_SetQoS: BdAddr: %02x%02x%02x%02x%02x%02x", + bd[0], bd[1], bd[2], + bd[3], bd[4], bd[5]); + + /* If someone already waiting on the version, do not allow another */ + if (btm_cb.devcb.p_qossu_cmpl_cb) + return(BTM_BUSY); + + if ( (p = btm_bda_to_acl(bd, BT_TRANSPORT_BR_EDR)) != NULL) + { + btu_start_timer (&btm_cb.devcb.qossu_timer, BTU_TTYPE_BTM_ACL, BTM_DEV_REPLY_TIMEOUT); + btm_cb.devcb.p_qossu_cmpl_cb = p_cb; + + if (!btsnd_hcic_qos_setup (p->hci_handle, p_flow->qos_flags, p_flow->service_type, + p_flow->token_rate, p_flow->peak_bandwidth, + p_flow->latency,p_flow->delay_variation)) + { + btm_cb.devcb.p_qossu_cmpl_cb = NULL; + btu_stop_timer(&btm_cb.devcb.qossu_timer); + return(BTM_NO_RESOURCES); + } + else + return(BTM_CMD_STARTED); + } + + /* If here, no BD Addr found */ + return(BTM_UNKNOWN_ADDR); +} + +/******************************************************************************* +** +** Function btm_qos_setup_complete +** +** Description This function is called when the command complete message +** is received from the HCI for the qos setup request. +** +** Returns void +** +*******************************************************************************/ +void btm_qos_setup_complete (UINT8 status, UINT16 handle, FLOW_SPEC *p_flow) +{ + tBTM_CMPL_CB *p_cb = btm_cb.devcb.p_qossu_cmpl_cb; + tBTM_QOS_SETUP_CMPL qossu; + BTM_TRACE_DEBUG ("btm_qos_setup_complete"); + btu_stop_timer (&btm_cb.devcb.qossu_timer); + + btm_cb.devcb.p_qossu_cmpl_cb = NULL; + + if (p_cb) + { + memset(&qossu, 0, sizeof(tBTM_QOS_SETUP_CMPL)); + qossu.status = status; + qossu.handle = handle; + if (p_flow != NULL) + { + qossu.flow.qos_flags = p_flow->qos_flags; + qossu.flow.service_type = p_flow->service_type; + qossu.flow.token_rate = p_flow->token_rate; + qossu.flow.peak_bandwidth = p_flow->peak_bandwidth; + qossu.flow.latency = p_flow->latency; + qossu.flow.delay_variation = p_flow->delay_variation; + } + BTM_TRACE_DEBUG ("BTM: p_flow->delay_variation: 0x%02x", + qossu.flow.delay_variation); + (*p_cb)(&qossu); + } +} + + +/******************************************************************************* +** +** Function BTM_ReadRSSI +** +** Description This function is called to read the link policy settings. +** The address of link policy results are returned in the callback. +** (tBTM_RSSI_RESULTS) +** +** Returns BTM_CMD_STARTED if successfully initiated or error code +** +*******************************************************************************/ +tBTM_STATUS BTM_ReadRSSI (BD_ADDR remote_bda, tBTM_CMPL_CB *p_cb) +{ + tACL_CONN *p; + tBT_TRANSPORT transport = BT_TRANSPORT_BR_EDR; +#if BLE_INCLUDED == TRUE + tBT_DEVICE_TYPE dev_type; + tBLE_ADDR_TYPE addr_type; +#endif + BTM_TRACE_API ("BTM_ReadRSSI: RemBdAddr: %02x%02x%02x%02x%02x%02x", + remote_bda[0], remote_bda[1], remote_bda[2], + remote_bda[3], remote_bda[4], remote_bda[5]); + + /* If someone already waiting on the version, do not allow another */ + if (btm_cb.devcb.p_rssi_cmpl_cb) + return(BTM_BUSY); + +#if BLE_INCLUDED == TRUE + BTM_ReadDevInfo(remote_bda, &dev_type, &addr_type); + if (dev_type == BT_DEVICE_TYPE_BLE) + transport = BT_TRANSPORT_LE; +#endif + + p = btm_bda_to_acl(remote_bda, transport); + if (p != (tACL_CONN *)NULL) + { + btu_start_timer (&btm_cb.devcb.rssi_timer, BTU_TTYPE_BTM_ACL, + BTM_DEV_REPLY_TIMEOUT); + + btm_cb.devcb.p_rssi_cmpl_cb = p_cb; + + if (!btsnd_hcic_read_rssi (p->hci_handle)) + { + btm_cb.devcb.p_rssi_cmpl_cb = NULL; + btu_stop_timer (&btm_cb.devcb.rssi_timer); + return(BTM_NO_RESOURCES); + } + else + return(BTM_CMD_STARTED); + } + + /* If here, no BD Addr found */ + return(BTM_UNKNOWN_ADDR); +} + +/******************************************************************************* +** +** Function BTM_ReadLinkQuality +** +** Description This function is called to read the link qulaity. +** The value of the link quality is returned in the callback. +** (tBTM_LINK_QUALITY_RESULTS) +** +** Returns BTM_CMD_STARTED if successfully initiated or error code +** +*******************************************************************************/ +tBTM_STATUS BTM_ReadLinkQuality (BD_ADDR remote_bda, tBTM_CMPL_CB *p_cb) +{ + tACL_CONN *p; + + BTM_TRACE_API ("BTM_ReadLinkQuality: RemBdAddr: %02x%02x%02x%02x%02x%02x", + remote_bda[0], remote_bda[1], remote_bda[2], + remote_bda[3], remote_bda[4], remote_bda[5]); + + /* If someone already waiting on the version, do not allow another */ + if (btm_cb.devcb.p_lnk_qual_cmpl_cb) + return(BTM_BUSY); + + p = btm_bda_to_acl(remote_bda, BT_TRANSPORT_BR_EDR); + if (p != (tACL_CONN *)NULL) + { + btu_start_timer (&btm_cb.devcb.lnk_quality_timer, BTU_TTYPE_BTM_ACL, + BTM_DEV_REPLY_TIMEOUT); + btm_cb.devcb.p_lnk_qual_cmpl_cb = p_cb; + + if (!btsnd_hcic_get_link_quality (p->hci_handle)) + { + btu_stop_timer (&btm_cb.devcb.lnk_quality_timer); + btm_cb.devcb.p_lnk_qual_cmpl_cb = NULL; + return(BTM_NO_RESOURCES); + } + else + return(BTM_CMD_STARTED); + } + + /* If here, no BD Addr found */ + return(BTM_UNKNOWN_ADDR); +} + +/******************************************************************************* +** +** Function BTM_ReadTxPower +** +** Description This function is called to read the current +** TX power of the connection. The tx power level results +** are returned in the callback. +** (tBTM_RSSI_RESULTS) +** +** Returns BTM_CMD_STARTED if successfully initiated or error code +** +*******************************************************************************/ +tBTM_STATUS BTM_ReadTxPower (BD_ADDR remote_bda, tBT_TRANSPORT transport, tBTM_CMPL_CB *p_cb) +{ + tACL_CONN *p; + BOOLEAN ret; +#define BTM_READ_RSSI_TYPE_CUR 0x00 +#define BTM_READ_RSSI_TYPE_MAX 0X01 + + BTM_TRACE_API ("BTM_ReadTxPower: RemBdAddr: %02x%02x%02x%02x%02x%02x", + remote_bda[0], remote_bda[1], remote_bda[2], + remote_bda[3], remote_bda[4], remote_bda[5]); + + /* If someone already waiting on the version, do not allow another */ + if (btm_cb.devcb.p_tx_power_cmpl_cb) + return(BTM_BUSY); + + p = btm_bda_to_acl(remote_bda, transport); + if (p != (tACL_CONN *)NULL) + { + btu_start_timer (&btm_cb.devcb.tx_power_timer, BTU_TTYPE_BTM_ACL, + BTM_DEV_REPLY_TIMEOUT); + + btm_cb.devcb.p_tx_power_cmpl_cb = p_cb; + +#if BLE_INCLUDED == TRUE + if (p->transport == BT_TRANSPORT_LE) + { + memcpy(btm_cb.devcb.read_tx_pwr_addr, remote_bda, BD_ADDR_LEN); + ret = btsnd_hcic_ble_read_adv_chnl_tx_power(); + } + else +#endif + { + ret = btsnd_hcic_read_tx_power (p->hci_handle, BTM_READ_RSSI_TYPE_CUR); + } + if (!ret) + { + btm_cb.devcb.p_tx_power_cmpl_cb = NULL; + btu_stop_timer (&btm_cb.devcb.tx_power_timer); + return(BTM_NO_RESOURCES); + } + else + return(BTM_CMD_STARTED); + } + + /* If here, no BD Addr found */ + return (BTM_UNKNOWN_ADDR); +} +/******************************************************************************* +** +** Function btm_read_tx_power_complete +** +** Description This function is called when the command complete message +** is received from the HCI for the read tx power request. +** +** Returns void +** +*******************************************************************************/ +void btm_read_tx_power_complete (UINT8 *p, BOOLEAN is_ble) +{ + tBTM_CMPL_CB *p_cb = btm_cb.devcb.p_tx_power_cmpl_cb; + tBTM_TX_POWER_RESULTS results; + UINT16 handle; + tACL_CONN *p_acl_cb = &btm_cb.acl_db[0]; + UINT16 index; + BTM_TRACE_DEBUG ("btm_read_tx_power_complete"); + btu_stop_timer (&btm_cb.devcb.tx_power_timer); + + /* If there was a callback registered for read rssi, call it */ + btm_cb.devcb.p_tx_power_cmpl_cb = NULL; + + if (p_cb) + { + STREAM_TO_UINT8 (results.hci_status, p); + + if (results.hci_status == HCI_SUCCESS) + { + results.status = BTM_SUCCESS; + + if (!is_ble) + { + STREAM_TO_UINT16 (handle, p); + STREAM_TO_UINT8 (results.tx_power, p); + + /* Search through the list of active channels for the correct BD Addr */ + for (index = 0; index < MAX_L2CAP_LINKS; index++, p_acl_cb++) + { + if ((p_acl_cb->in_use) && (handle == p_acl_cb->hci_handle)) + { + memcpy (results.rem_bda, p_acl_cb->remote_addr, BD_ADDR_LEN); + break; + } + } + } +#if BLE_INCLUDED == TRUE + else + { + STREAM_TO_UINT8 (results.tx_power, p); + memcpy(results.rem_bda, btm_cb.devcb.read_tx_pwr_addr, BD_ADDR_LEN); + } +#endif + BTM_TRACE_DEBUG ("BTM TX power Complete: tx_power %d, hci status 0x%02x", + results.tx_power, results.hci_status); + } + else + results.status = BTM_ERR_PROCESSING; + + (*p_cb)(&results); + } +} + +/******************************************************************************* +** +** Function btm_read_rssi_complete +** +** Description This function is called when the command complete message +** is received from the HCI for the read rssi request. +** +** Returns void +** +*******************************************************************************/ +void btm_read_rssi_complete (UINT8 *p) +{ + tBTM_CMPL_CB *p_cb = btm_cb.devcb.p_rssi_cmpl_cb; + tBTM_RSSI_RESULTS results; + UINT16 handle; + tACL_CONN *p_acl_cb = &btm_cb.acl_db[0]; + UINT16 index; + BTM_TRACE_DEBUG ("btm_read_rssi_complete"); + btu_stop_timer (&btm_cb.devcb.rssi_timer); + + /* If there was a callback registered for read rssi, call it */ + btm_cb.devcb.p_rssi_cmpl_cb = NULL; + + if (p_cb) + { + STREAM_TO_UINT8 (results.hci_status, p); + + if (results.hci_status == HCI_SUCCESS) + { + results.status = BTM_SUCCESS; + + STREAM_TO_UINT16 (handle, p); + + STREAM_TO_UINT8 (results.rssi, p); + BTM_TRACE_DEBUG ("BTM RSSI Complete: rssi %d, hci status 0x%02x", + results.rssi, results.hci_status); + + /* Search through the list of active channels for the correct BD Addr */ + for (index = 0; index < MAX_L2CAP_LINKS; index++, p_acl_cb++) + { + if ((p_acl_cb->in_use) && (handle == p_acl_cb->hci_handle)) + { + memcpy (results.rem_bda, p_acl_cb->remote_addr, BD_ADDR_LEN); + break; + } + } + } + else + results.status = BTM_ERR_PROCESSING; + + (*p_cb)(&results); + } +} + +/******************************************************************************* +** +** Function btm_read_link_quality_complete +** +** Description This function is called when the command complete message +** is received from the HCI for the read link quality. +** +** Returns void +** +*******************************************************************************/ +void btm_read_link_quality_complete (UINT8 *p) +{ + tBTM_CMPL_CB *p_cb = btm_cb.devcb.p_lnk_qual_cmpl_cb; + tBTM_LINK_QUALITY_RESULTS results; + UINT16 handle; + tACL_CONN *p_acl_cb = &btm_cb.acl_db[0]; + UINT16 index; + BTM_TRACE_DEBUG ("btm_read_link_quality_complete"); + btu_stop_timer (&btm_cb.devcb.lnk_quality_timer); + + /* If there was a callback registered for read rssi, call it */ + btm_cb.devcb.p_lnk_qual_cmpl_cb = NULL; + + if (p_cb) + { + STREAM_TO_UINT8 (results.hci_status, p); + + if (results.hci_status == HCI_SUCCESS) + { + results.status = BTM_SUCCESS; + + STREAM_TO_UINT16 (handle, p); + + STREAM_TO_UINT8 (results.link_quality, p); + BTM_TRACE_DEBUG ("BTM Link Quality Complete: Link Quality %d, hci status 0x%02x", + results.link_quality, results.hci_status); + + /* Search through the list of active channels for the correct BD Addr */ + for (index = 0; index < MAX_L2CAP_LINKS; index++, p_acl_cb++) + { + if ((p_acl_cb->in_use) && (handle == p_acl_cb->hci_handle)) + { + memcpy (results.rem_bda, p_acl_cb->remote_addr, BD_ADDR_LEN); + break; + } + } + } + else + results.status = BTM_ERR_PROCESSING; + + (*p_cb)(&results); + } +} + +/******************************************************************************* +** +** Function btm_remove_acl +** +** Description This function is called to disconnect an ACL connection +** +** Returns BTM_SUCCESS if successfully initiated, otherwise BTM_NO_RESOURCES. +** +*******************************************************************************/ +tBTM_STATUS btm_remove_acl (BD_ADDR bd_addr, tBT_TRANSPORT transport) +{ + UINT16 hci_handle = BTM_GetHCIConnHandle(bd_addr, transport); + tBTM_STATUS status = BTM_SUCCESS; + + BTM_TRACE_DEBUG ("btm_remove_acl"); +#if BTM_DISC_DURING_RS == TRUE + tBTM_SEC_DEV_REC *p_dev_rec = btm_find_dev (bd_addr); + + /* Role Switch is pending, postpone until completed */ + if (p_dev_rec && (p_dev_rec->rs_disc_pending == BTM_SEC_RS_PENDING)) + { + p_dev_rec->rs_disc_pending = BTM_SEC_DISC_PENDING; + } + else /* otherwise can disconnect right away */ +#endif + { + if (hci_handle != 0xFFFF && p_dev_rec && + p_dev_rec->sec_state!= BTM_SEC_STATE_DISCONNECTING) + { + if (!btsnd_hcic_disconnect (hci_handle, HCI_ERR_PEER_USER)) + status = BTM_NO_RESOURCES; + } + else + status = BTM_UNKNOWN_ADDR; + } + + return status; +} + + +/******************************************************************************* +** +** Function BTM_SetTraceLevel +** +** Description This function sets the trace level for BTM. If called with +** a value of 0xFF, it simply returns the current trace level. +** +** Returns The new or current trace level +** +*******************************************************************************/ +UINT8 BTM_SetTraceLevel (UINT8 new_level) +{ + BTM_TRACE_DEBUG ("BTM_SetTraceLevel"); + if (new_level != 0xFF) + btm_cb.trace_level = new_level; + + return(btm_cb.trace_level); +} + +/******************************************************************************* +** +** Function btm_cont_rswitch +** +** Description This function is called to continue processing an active +** role switch. It first disables encryption if enabled and +** EPR is not supported +** +** Returns void +** +*******************************************************************************/ +void btm_cont_rswitch (tACL_CONN *p, tBTM_SEC_DEV_REC *p_dev_rec, + UINT8 hci_status) +{ + BOOLEAN sw_ok = TRUE; + BTM_TRACE_DEBUG ("btm_cont_rswitch"); + /* Check to see if encryption needs to be turned off if pending + change of link key or role switch */ + if (p->switch_role_state == BTM_ACL_SWKEY_STATE_MODE_CHANGE) + { + /* Must turn off Encryption first if necessary */ + /* Some devices do not support switch or change of link key while encryption is on */ + if (p_dev_rec != NULL && ((p_dev_rec->sec_flags & BTM_SEC_ENCRYPTED) != 0) + && !BTM_EPR_AVAILABLE(p)) + { + if (btsnd_hcic_set_conn_encrypt (p->hci_handle, FALSE)) + { + p->encrypt_state = BTM_ACL_ENCRYPT_STATE_ENCRYPT_OFF; + if (p->switch_role_state == BTM_ACL_SWKEY_STATE_MODE_CHANGE) + p->switch_role_state = BTM_ACL_SWKEY_STATE_ENCRYPTION_OFF; + } + else + { + /* Error occurred; set states back to Idle */ + if (p->switch_role_state == BTM_ACL_SWKEY_STATE_MODE_CHANGE) + sw_ok = FALSE; + } + } + else /* Encryption not used or EPR supported, continue with switch + and/or change of link key */ + { + if (p->switch_role_state == BTM_ACL_SWKEY_STATE_MODE_CHANGE) + { + p->switch_role_state = BTM_ACL_SWKEY_STATE_IN_PROGRESS; +#if BTM_DISC_DURING_RS == TRUE + if (p_dev_rec) + p_dev_rec->rs_disc_pending = BTM_SEC_RS_PENDING; +#endif + sw_ok = btsnd_hcic_switch_role (p->remote_addr, (UINT8)!p->link_role); + } + } + + if (!sw_ok) + { + p->switch_role_state = BTM_ACL_SWKEY_STATE_IDLE; + btm_acl_report_role_change(hci_status, p->remote_addr); + } + } +} + +/******************************************************************************* +** +** Function btm_acl_resubmit_page +** +** Description send pending page request +** +*******************************************************************************/ +void btm_acl_resubmit_page (void) +{ + tBTM_SEC_DEV_REC *p_dev_rec; + BT_HDR *p_buf; + UINT8 *pp; + BD_ADDR bda; + BTM_TRACE_DEBUG ("btm_acl_resubmit_page"); + /* If there were other page request schedule can start the next one */ + if ((p_buf = (BT_HDR *)GKI_dequeue (&btm_cb.page_queue)) != NULL) + { + /* skip 3 (2 bytes opcode and 1 byte len) to get to the bd_addr + * for both create_conn and rmt_name */ + pp = (UINT8 *)(p_buf + 1) + p_buf->offset + 3; + + STREAM_TO_BDADDR (bda, pp); + + p_dev_rec = btm_find_or_alloc_dev (bda); + + memcpy (btm_cb.connecting_bda, p_dev_rec->bd_addr, BD_ADDR_LEN); + memcpy (btm_cb.connecting_dc, p_dev_rec->dev_class, DEV_CLASS_LEN); + + btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p_buf); + } + else + btm_cb.paging = FALSE; +} + +/******************************************************************************* +** +** Function btm_acl_reset_paging +** +** Description set paging to FALSE and free the page queue - called at hci_reset +** +*******************************************************************************/ +void btm_acl_reset_paging (void) +{ + BT_HDR *p; + BTM_TRACE_DEBUG ("btm_acl_reset_paging"); + /* If we sent reset we are definitely not paging any more */ + while ((p = (BT_HDR *)GKI_dequeue(&btm_cb.page_queue)) != NULL) + GKI_freebuf (p); + + btm_cb.paging = FALSE; +} + +/******************************************************************************* +** +** Function btm_acl_paging +** +** Description send a paging command or queue it in btm_cb +** +*******************************************************************************/ +void btm_acl_paging (BT_HDR *p, BD_ADDR bda) +{ + tBTM_SEC_DEV_REC *p_dev_rec; + + BTM_TRACE_DEBUG ("btm_acl_paging discing:%d, paging:%d BDA: %06x%06x", + btm_cb.discing, btm_cb.paging, + (bda[0]<<16) + (bda[1]<<8) + bda[2], (bda[3]<<16) + (bda[4] << 8) + bda[5]); + if (btm_cb.discing) + { + btm_cb.paging = TRUE; + GKI_enqueue (&btm_cb.page_queue, p); + } + else + { + if (!BTM_ACL_IS_CONNECTED (bda)) + { + BTM_TRACE_DEBUG ("connecting_bda: %06x%06x", + (btm_cb.connecting_bda[0]<<16) + (btm_cb.connecting_bda[1]<<8) + + btm_cb.connecting_bda[2], + (btm_cb.connecting_bda[3]<<16) + (btm_cb.connecting_bda[4] << 8) + + btm_cb.connecting_bda[5]); + if (btm_cb.paging && + memcmp (bda, btm_cb.connecting_bda, BD_ADDR_LEN) != 0) + { + GKI_enqueue (&btm_cb.page_queue, p); + } + else + { + p_dev_rec = btm_find_or_alloc_dev (bda); + memcpy (btm_cb.connecting_bda, p_dev_rec->bd_addr, BD_ADDR_LEN); + memcpy (btm_cb.connecting_dc, p_dev_rec->dev_class, DEV_CLASS_LEN); + + btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p); + } + + btm_cb.paging = TRUE; + } + else /* ACL is already up */ + { + btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p); + } + } +} + +/******************************************************************************* +** +** Function btm_acl_notif_conn_collision +** +** Description Send connection collision event to upper layer if registered +** +** Returns TRUE if sent out to upper layer, +** FALSE if no one needs the notification. +** +*******************************************************************************/ +BOOLEAN btm_acl_notif_conn_collision (BD_ADDR bda) +{ + tBTM_BL_EVENT_DATA evt_data; + + /* Report possible collision to the upper layer. */ + if (btm_cb.p_bl_changed_cb) + { + BTM_TRACE_DEBUG ("btm_acl_notif_conn_collision: RemBdAddr: %02x%02x%02x%02x%02x%02x", + bda[0], bda[1], bda[2], bda[3], bda[4], bda[5]); + + evt_data.event = BTM_BL_COLLISION_EVT; + evt_data.conn.p_bda = bda; + +#if BLE_INCLUDED == TRUE + evt_data.conn.transport = BT_TRANSPORT_BR_EDR; + evt_data.conn.handle = BTM_INVALID_HCI_HANDLE; +#endif + (*btm_cb.p_bl_changed_cb)(&evt_data); + return TRUE; + } + else + return FALSE; +} + + +/******************************************************************************* +** +** Function btm_acl_chk_peer_pkt_type_support +** +** Description Check if peer supports requested packets +** +*******************************************************************************/ +void btm_acl_chk_peer_pkt_type_support (tACL_CONN *p, UINT16 *p_pkt_type) +{ + /* 3 and 5 slot packets? */ + if (!HCI_3_SLOT_PACKETS_SUPPORTED(p->peer_lmp_features[HCI_EXT_FEATURES_PAGE_0])) + *p_pkt_type &= ~(BTM_ACL_PKT_TYPES_MASK_DH3 +BTM_ACL_PKT_TYPES_MASK_DM3); + + if (!HCI_5_SLOT_PACKETS_SUPPORTED(p->peer_lmp_features[HCI_EXT_FEATURES_PAGE_0])) + *p_pkt_type &= ~(BTM_ACL_PKT_TYPES_MASK_DH5 + BTM_ACL_PKT_TYPES_MASK_DM5); + + /* 2 and 3 MPS support? */ + if (!HCI_EDR_ACL_2MPS_SUPPORTED(p->peer_lmp_features[HCI_EXT_FEATURES_PAGE_0])) + /* Not supported. Add 'not_supported' mask for all 2MPS packet types */ + *p_pkt_type |= (BTM_ACL_PKT_TYPES_MASK_NO_2_DH1 + BTM_ACL_PKT_TYPES_MASK_NO_2_DH3 + + BTM_ACL_PKT_TYPES_MASK_NO_2_DH5); + + if (!HCI_EDR_ACL_3MPS_SUPPORTED(p->peer_lmp_features[HCI_EXT_FEATURES_PAGE_0])) + /* Not supported. Add 'not_supported' mask for all 3MPS packet types */ + *p_pkt_type |= (BTM_ACL_PKT_TYPES_MASK_NO_3_DH1 + BTM_ACL_PKT_TYPES_MASK_NO_3_DH3 + + BTM_ACL_PKT_TYPES_MASK_NO_3_DH5); + + /* EDR 3 and 5 slot support? */ + if (HCI_EDR_ACL_2MPS_SUPPORTED(p->peer_lmp_features[HCI_EXT_FEATURES_PAGE_0]) + || HCI_EDR_ACL_3MPS_SUPPORTED(p->peer_lmp_features[HCI_EXT_FEATURES_PAGE_0])) + { + if (!HCI_3_SLOT_EDR_ACL_SUPPORTED(p->peer_lmp_features[HCI_EXT_FEATURES_PAGE_0])) + /* Not supported. Add 'not_supported' mask for all 3-slot EDR packet types */ + *p_pkt_type |= (BTM_ACL_PKT_TYPES_MASK_NO_2_DH3 + BTM_ACL_PKT_TYPES_MASK_NO_3_DH3); + + if (!HCI_5_SLOT_EDR_ACL_SUPPORTED(p->peer_lmp_features[HCI_EXT_FEATURES_PAGE_0])) + /* Not supported. Add 'not_supported' mask for all 5-slot EDR packet types */ + *p_pkt_type |= (BTM_ACL_PKT_TYPES_MASK_NO_2_DH5 + BTM_ACL_PKT_TYPES_MASK_NO_3_DH5); + } +} diff --git a/components/bt/bluedroid/stack/btm/btm_ble.c b/components/bt/bluedroid/stack/btm/btm_ble.c new file mode 100755 index 0000000000..974bbfbfaf --- /dev/null +++ b/components/bt/bluedroid/stack/btm/btm_ble.c @@ -0,0 +1,2675 @@ +/****************************************************************************** + * + * Copyright (C) 1999-2012 Broadcom Corporation + * + * 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 functions for BLE device control utilities, and LE + * security functions. + * + ******************************************************************************/ +#include "bt_target.h" + +#if BLE_INCLUDED == TRUE + +#include + +#include "bt_types.h" +#include "hcimsgs.h" +#include "btu.h" +#include "btm_int.h" +#include "btm_ble_api.h" +#include "smp_api.h" +#include "l2c_int.h" +#include "gap_api.h" +//#include "bt_utils.h" +#include "controller.h" + +//#define LOG_TAG "bt_btm_ble" +//#include "osi/include/log.h" + +#if SMP_INCLUDED == TRUE +extern BOOLEAN aes_cipher_msg_auth_code(BT_OCTET16 key, UINT8 *input, UINT16 length, + UINT16 tlen, UINT8 *p_signature); +extern void smp_link_encrypted(BD_ADDR bda, UINT8 encr_enable); +extern BOOLEAN smp_proc_ltk_request(BD_ADDR bda); +#endif +extern void gatt_notify_enc_cmpl(BD_ADDR bd_addr); +/*******************************************************************************/ +/* External Function to be called by other modules */ +/*******************************************************************************/ +/******************************************************** +** +** Function BTM_SecAddBleDevice +** +** Description Add/modify device. This function will be normally called +** during host startup to restore all required information +** for a LE device stored in the NVRAM. +** +** Parameters: bd_addr - BD address of the peer +** bd_name - Name of the peer device. NULL if unknown. +** dev_type - Remote device's device type. +** addr_type - LE device address type. +** +** Returns TRUE if added OK, else FALSE +** +*******************************************************************************/ +BOOLEAN BTM_SecAddBleDevice (BD_ADDR bd_addr, BD_NAME bd_name, tBT_DEVICE_TYPE dev_type, + tBLE_ADDR_TYPE addr_type) +{ + tBTM_SEC_DEV_REC *p_dev_rec; + UINT8 i = 0; + tBTM_INQ_INFO *p_info=NULL; + + BTM_TRACE_DEBUG ("BTM_SecAddBleDevice dev_type=0x%x", dev_type); + p_dev_rec = btm_find_dev (bd_addr); + + if (!p_dev_rec) + { + BTM_TRACE_DEBUG("Add a new device"); + + /* There is no device record, allocate one. + * If we can not find an empty spot for this one, let it fail. */ + for (i = 0; i < BTM_SEC_MAX_DEVICE_RECORDS; i++) + { + if (!(btm_cb.sec_dev_rec[i].sec_flags & BTM_SEC_IN_USE)) + { + BTM_TRACE_DEBUG ("allocate a new dev rec idx=0x%x ", i ); + p_dev_rec = &btm_cb.sec_dev_rec[i]; + + /* Mark this record as in use and initialize */ + memset (p_dev_rec, 0, sizeof (tBTM_SEC_DEV_REC)); + p_dev_rec->sec_flags = BTM_SEC_IN_USE; + memcpy (p_dev_rec->bd_addr, bd_addr, BD_ADDR_LEN); + p_dev_rec->hci_handle = BTM_GetHCIConnHandle (bd_addr, BT_TRANSPORT_BR_EDR); + p_dev_rec->ble_hci_handle = BTM_GetHCIConnHandle (bd_addr, BT_TRANSPORT_LE); + + /* update conn params, use default value for background connection params */ + p_dev_rec->conn_params.min_conn_int = + p_dev_rec->conn_params.max_conn_int = + p_dev_rec->conn_params.supervision_tout = + p_dev_rec->conn_params.slave_latency = BTM_BLE_CONN_PARAM_UNDEF; + + BTM_TRACE_DEBUG ("hci_handl=0x%x ", p_dev_rec->ble_hci_handle ); + break; + } + } + + if (!p_dev_rec) + return(FALSE); + } + else + { + BTM_TRACE_DEBUG("Device already exist"); + } + + memset(p_dev_rec->sec_bd_name, 0, sizeof(tBTM_BD_NAME)); + + if (bd_name && bd_name[0]) + { + p_dev_rec->sec_flags |= BTM_SEC_NAME_KNOWN; + BCM_STRNCPY_S ((char *)p_dev_rec->sec_bd_name, sizeof (p_dev_rec->sec_bd_name), + (char *)bd_name, BTM_MAX_REM_BD_NAME_LEN); + } + p_dev_rec->device_type |= dev_type; + p_dev_rec->ble.ble_addr_type = addr_type; + + memcpy (p_dev_rec->ble.pseudo_addr, bd_addr, BD_ADDR_LEN); + /* sync up with the Inq Data base*/ + p_info = BTM_InqDbRead(bd_addr); + if (p_info) + { + p_info->results.ble_addr_type = p_dev_rec->ble.ble_addr_type ; + p_info->results.device_type = p_dev_rec->device_type; + BTM_TRACE_DEBUG ("InqDb device_type =0x%x addr_type=0x%x", + p_info->results.device_type, p_info->results.ble_addr_type); + } + + return(TRUE); +} + +/******************************************************************************* +** +** Function BTM_SecAddBleKey +** +** Description Add/modify LE device information. This function will be +** normally called during host startup to restore all required +** information stored in the NVRAM. +** +** Parameters: bd_addr - BD address of the peer +** p_le_key - LE key values. +** key_type - LE SMP key type. +* +** Returns TRUE if added OK, else FALSE +** +*******************************************************************************/ +BOOLEAN BTM_SecAddBleKey (BD_ADDR bd_addr, tBTM_LE_KEY_VALUE *p_le_key, tBTM_LE_KEY_TYPE key_type) +{ +#if SMP_INCLUDED == TRUE + tBTM_SEC_DEV_REC *p_dev_rec; + BTM_TRACE_DEBUG ("BTM_SecAddBleKey"); + p_dev_rec = btm_find_dev (bd_addr); + if (!p_dev_rec || !p_le_key || + (key_type != BTM_LE_KEY_PENC && key_type != BTM_LE_KEY_PID && + key_type != BTM_LE_KEY_PCSRK && key_type != BTM_LE_KEY_LENC && + key_type != BTM_LE_KEY_LCSRK && key_type != BTM_LE_KEY_LID)) + { + BTM_TRACE_WARNING ("BTM_SecAddBleKey() Wrong Type, or No Device record \ + for bdaddr: %08x%04x, Type: %d", + (bd_addr[0]<<24)+(bd_addr[1]<<16)+(bd_addr[2]<<8)+bd_addr[3], + (bd_addr[4]<<8)+bd_addr[5], key_type); + return(FALSE); + } + + BTM_TRACE_DEBUG ("BTM_SecAddLeKey() BDA: %08x%04x, Type: 0x%02x", + (bd_addr[0]<<24)+(bd_addr[1]<<16)+(bd_addr[2]<<8)+bd_addr[3], + (bd_addr[4]<<8)+bd_addr[5], key_type); + + btm_sec_save_le_key (bd_addr, key_type, p_le_key, FALSE); + +#if (BLE_PRIVACY_SPT == TRUE) + if (key_type == BTM_LE_KEY_PID || key_type == BTM_LE_KEY_LID) + btm_ble_resolving_list_load_dev (p_dev_rec); +#endif + +#endif + + return(TRUE); +} + +/******************************************************************************* +** +** Function BTM_BleLoadLocalKeys +** +** Description Local local identity key, encryption root or sign counter. +** +** Parameters: key_type: type of key, can be BTM_BLE_KEY_TYPE_ID, BTM_BLE_KEY_TYPE_ER +** or BTM_BLE_KEY_TYPE_COUNTER. +** p_key: pointer to the key. +* +** Returns non2. +** +*******************************************************************************/ +void BTM_BleLoadLocalKeys(UINT8 key_type, tBTM_BLE_LOCAL_KEYS *p_key) +{ + tBTM_DEVCB *p_devcb = &btm_cb.devcb; + BTM_TRACE_DEBUG ("%s", __func__); + if (p_key != NULL) + { + switch (key_type) + { + case BTM_BLE_KEY_TYPE_ID: + memcpy(&p_devcb->id_keys, &p_key->id_keys, sizeof(tBTM_BLE_LOCAL_ID_KEYS)); + break; + + case BTM_BLE_KEY_TYPE_ER: + memcpy(p_devcb->ble_encryption_key_value, p_key->er, sizeof(BT_OCTET16)); + break; + + default: + BTM_TRACE_ERROR("unknow local key type: %d", key_type); + break; + } + } +} + +/******************************************************************************* +** +** Function BTM_GetDeviceEncRoot +** +** Description This function is called to read the local device encryption +** root. +** +** Returns void +** the local device ER is copied into ble_encr_key_value +** +*******************************************************************************/ +void BTM_GetDeviceEncRoot (BT_OCTET16 ble_encr_key_value) +{ + BTM_TRACE_DEBUG ("%s", __func__); + memcpy (ble_encr_key_value, btm_cb.devcb.ble_encryption_key_value, BT_OCTET16_LEN); +} + +/******************************************************************************* +** +** Function BTM_GetDeviceIDRoot +** +** Description This function is called to read the local device identity +** root. +** +** Returns void +** the local device IR is copied into irk +** +*******************************************************************************/ +void BTM_GetDeviceIDRoot (BT_OCTET16 irk) +{ + BTM_TRACE_DEBUG ("BTM_GetDeviceIDRoot "); + + memcpy (irk, btm_cb.devcb.id_keys.irk, BT_OCTET16_LEN); +} + +/******************************************************************************* +** +** Function BTM_GetDeviceDHK +** +** Description This function is called to read the local device DHK. +** +** Returns void +** the local device DHK is copied into dhk +** +*******************************************************************************/ +void BTM_GetDeviceDHK (BT_OCTET16 dhk) +{ + BTM_TRACE_DEBUG ("BTM_GetDeviceDHK"); + memcpy (dhk, btm_cb.devcb.id_keys.dhk, BT_OCTET16_LEN); +} + +/******************************************************************************* +** +** Function BTM_ReadConnectionAddr +** +** Description This function is called to get the local device address information +** . +** +** Returns void +** +*******************************************************************************/ +void BTM_ReadConnectionAddr (BD_ADDR remote_bda, BD_ADDR local_conn_addr, tBLE_ADDR_TYPE *p_addr_type) +{ + tACL_CONN *p_acl = btm_bda_to_acl(remote_bda, BT_TRANSPORT_LE); + + if (p_acl == NULL) + { + BTM_TRACE_ERROR("No connection exist!"); + return; + } + memcpy(local_conn_addr, p_acl->conn_addr, BD_ADDR_LEN); + * p_addr_type = p_acl->conn_addr_type; + + BTM_TRACE_DEBUG ("BTM_ReadConnectionAddr address type: %d addr: 0x%02x", + p_acl->conn_addr_type, p_acl->conn_addr[0]); +} + +/******************************************************************************* +** +** Function BTM_IsBleConnection +** +** Description This function is called to check if the connection handle +** for an LE link +** +** Returns TRUE if connection is LE link, otherwise FALSE. +** +*******************************************************************************/ +BOOLEAN BTM_IsBleConnection (UINT16 conn_handle) +{ +#if (BLE_INCLUDED == TRUE) + UINT8 xx; + tACL_CONN *p; + + BTM_TRACE_API ("BTM_IsBleConnection: conn_handle: %d", conn_handle); + + xx = btm_handle_to_acl_index (conn_handle); + if (xx >= MAX_L2CAP_LINKS) + return FALSE; + + p = &btm_cb.acl_db[xx]; + + return (p->transport == BT_TRANSPORT_LE); +#else + return FALSE; +#endif +} + +/******************************************************************************* +** +** Function BTM_ReadRemoteConnectionAddr +** +** Description This function is read the remote device address currently used +** +** Parameters pseudo_addr: pseudo random address available +** conn_addr:connection address used +** p_addr_type : BD Address type, Public or Random of the address used +** +** Returns BOOLEAN , TRUE if connection to remote device exists, else FALSE +** +*******************************************************************************/ +BOOLEAN BTM_ReadRemoteConnectionAddr(BD_ADDR pseudo_addr, BD_ADDR conn_addr, + tBLE_ADDR_TYPE *p_addr_type) +{ + BOOLEAN st = TRUE; +#if (BLE_PRIVACY_SPT == TRUE) + tACL_CONN *p = btm_bda_to_acl (pseudo_addr, BT_TRANSPORT_LE); + + if (p == NULL) + { + BTM_TRACE_ERROR("BTM_ReadRemoteConnectionAddr can not find connection" + " with matching address"); + return FALSE; + } + + memcpy(conn_addr, p->active_remote_addr, BD_ADDR_LEN); + *p_addr_type = p->active_remote_addr_type; +#else + tBTM_SEC_DEV_REC *p_dev_rec = btm_find_dev(pseudo_addr); + + memcpy(conn_addr, pseudo_addr, BD_ADDR_LEN); + if (p_dev_rec != NULL) + { + *p_addr_type = p_dev_rec->ble.ble_addr_type; + } +#endif + return st; + +} +/******************************************************************************* +** +** Function BTM_SecurityGrant +** +** Description This function is called to grant security process. +** +** Parameters bd_addr - peer device bd address. +** res - result of the operation BTM_SUCCESS if success. +** Otherwise, BTM_REPEATED_ATTEMPTS is too many attempts. +** +** Returns None +** +*******************************************************************************/ +void BTM_SecurityGrant(BD_ADDR bd_addr, UINT8 res) +{ +#if SMP_INCLUDED == TRUE + tSMP_STATUS res_smp = (res == BTM_SUCCESS) ? SMP_SUCCESS : SMP_REPEATED_ATTEMPTS; + BTM_TRACE_DEBUG ("BTM_SecurityGrant"); + SMP_SecurityGrant(bd_addr, res_smp); +#endif +} + +/******************************************************************************* +** +** Function BTM_BlePasskeyReply +** +** Description This function is called after Security Manager submitted +** passkey request to the application. +** +** Parameters: bd_addr - Address of the device for which passkey was requested +** res - result of the operation BTM_SUCCESS if success +** key_len - length in bytes of the Passkey +** p_passkey - pointer to array with the passkey +** trusted_mask - bitwise OR of trusted services (array of UINT32) +** +*******************************************************************************/ +void BTM_BlePasskeyReply (BD_ADDR bd_addr, UINT8 res, UINT32 passkey) +{ +#if SMP_INCLUDED == TRUE + tBTM_SEC_DEV_REC *p_dev_rec = btm_find_dev (bd_addr); + tSMP_STATUS res_smp = (res == BTM_SUCCESS) ? SMP_SUCCESS : SMP_PASSKEY_ENTRY_FAIL; + + if (p_dev_rec == NULL) + { + BTM_TRACE_ERROR("Passkey reply to Unknown device"); + return; + } + + p_dev_rec->sec_flags |= BTM_SEC_LE_AUTHENTICATED; + BTM_TRACE_DEBUG ("BTM_BlePasskeyReply"); + SMP_PasskeyReply(bd_addr, res_smp, passkey); +#endif +} + +/******************************************************************************* +** +** Function BTM_BleConfirmReply +** +** Description This function is called after Security Manager submitted +** numeric comparison request to the application. +** +** Parameters: bd_addr - Address of the device with which numeric +** comparison was requested +** res - comparison result BTM_SUCCESS if success +** +*******************************************************************************/ +void BTM_BleConfirmReply (BD_ADDR bd_addr, UINT8 res) +{ + tBTM_SEC_DEV_REC *p_dev_rec = btm_find_dev (bd_addr); + tSMP_STATUS res_smp = (res == BTM_SUCCESS) ? SMP_SUCCESS : SMP_PASSKEY_ENTRY_FAIL; + + if (p_dev_rec == NULL) + { + BTM_TRACE_ERROR("Passkey reply to Unknown device"); + return; + } + + p_dev_rec->sec_flags |= BTM_SEC_LE_AUTHENTICATED; + BTM_TRACE_DEBUG ("%s", __func__); + SMP_ConfirmReply(bd_addr, res_smp); +} + +/******************************************************************************* +** +** Function BTM_BleOobDataReply +** +** Description This function is called to provide the OOB data for +** SMP in response to BTM_LE_OOB_REQ_EVT +** +** Parameters: bd_addr - Address of the peer device +** res - result of the operation SMP_SUCCESS if success +** p_data - simple pairing Randomizer C. +** +*******************************************************************************/ +void BTM_BleOobDataReply(BD_ADDR bd_addr, UINT8 res, UINT8 len, UINT8 *p_data) +{ +#if SMP_INCLUDED == TRUE + tSMP_STATUS res_smp = (res == BTM_SUCCESS) ? SMP_SUCCESS : SMP_OOB_FAIL; + tBTM_SEC_DEV_REC *p_dev_rec = btm_find_dev (bd_addr); + + BTM_TRACE_DEBUG ("BTM_BleOobDataReply"); + + if (p_dev_rec == NULL) + { + BTM_TRACE_ERROR("BTM_BleOobDataReply() to Unknown device"); + return; + } + + p_dev_rec->sec_flags |= BTM_SEC_LE_AUTHENTICATED; + SMP_OobDataReply(bd_addr, res_smp, len, p_data); +#endif +} + +/****************************************************************************** +** +** Function BTM_BleSetConnScanParams +** +** Description Set scan parameter used in BLE connection request +** +** Parameters: scan_interval: scan interval +** scan_window: scan window +** +** Returns void +** +*******************************************************************************/ +void BTM_BleSetConnScanParams (UINT32 scan_interval, UINT32 scan_window) +{ +#if SMP_INCLUDED == TRUE + tBTM_BLE_CB *p_ble_cb = &btm_cb.ble_ctr_cb; + BOOLEAN new_param = FALSE; + + if (BTM_BLE_ISVALID_PARAM(scan_interval, BTM_BLE_SCAN_INT_MIN, BTM_BLE_SCAN_INT_MAX) && + BTM_BLE_ISVALID_PARAM(scan_window, BTM_BLE_SCAN_WIN_MIN, BTM_BLE_SCAN_WIN_MAX)) + { + if (p_ble_cb->scan_int != scan_interval) + { + p_ble_cb->scan_int = scan_interval; + new_param = TRUE; + } + + if (p_ble_cb->scan_win != scan_window) + { + p_ble_cb->scan_win = scan_window; + new_param = TRUE; + } + + if (new_param && p_ble_cb->conn_state == BLE_BG_CONN) + { + btm_ble_suspend_bg_conn(); + } + } + else + { + BTM_TRACE_ERROR("Illegal Connection Scan Parameters"); + } +#endif +} + +/******************************************************** +** +** Function BTM_BleSetPrefConnParams +** +** Description Set a peripheral's preferred connection parameters +** +** Parameters: bd_addr - BD address of the peripheral +** scan_interval: scan interval +** scan_window: scan window +** min_conn_int - minimum preferred connection interval +** max_conn_int - maximum preferred connection interval +** slave_latency - preferred slave latency +** supervision_tout - preferred supervision timeout +** +** Returns void +** +*******************************************************************************/ +void BTM_BleSetPrefConnParams (BD_ADDR bd_addr, + UINT16 min_conn_int, UINT16 max_conn_int, + UINT16 slave_latency, UINT16 supervision_tout) +{ + tBTM_SEC_DEV_REC *p_dev_rec = btm_find_dev (bd_addr); + + BTM_TRACE_API ("BTM_BleSetPrefConnParams min: %u max: %u latency: %u \ + tout: %u", + min_conn_int, max_conn_int, slave_latency, supervision_tout); + + if (BTM_BLE_ISVALID_PARAM(min_conn_int, BTM_BLE_CONN_INT_MIN, BTM_BLE_CONN_INT_MAX) && + BTM_BLE_ISVALID_PARAM(max_conn_int, BTM_BLE_CONN_INT_MIN, BTM_BLE_CONN_INT_MAX) && + BTM_BLE_ISVALID_PARAM(supervision_tout, BTM_BLE_CONN_SUP_TOUT_MIN, BTM_BLE_CONN_SUP_TOUT_MAX) && + (slave_latency <= BTM_BLE_CONN_LATENCY_MAX || slave_latency == BTM_BLE_CONN_PARAM_UNDEF)) + { + if (p_dev_rec) + { + /* expect conn int and stout and slave latency to be updated all together */ + if (min_conn_int != BTM_BLE_CONN_PARAM_UNDEF || max_conn_int != BTM_BLE_CONN_PARAM_UNDEF) + { + if (min_conn_int != BTM_BLE_CONN_PARAM_UNDEF) + p_dev_rec->conn_params.min_conn_int = min_conn_int; + else + p_dev_rec->conn_params.min_conn_int = max_conn_int; + + if (max_conn_int != BTM_BLE_CONN_PARAM_UNDEF) + p_dev_rec->conn_params.max_conn_int = max_conn_int; + else + p_dev_rec->conn_params.max_conn_int = min_conn_int; + + if (slave_latency != BTM_BLE_CONN_PARAM_UNDEF) + p_dev_rec->conn_params.slave_latency = slave_latency; + else + p_dev_rec->conn_params.slave_latency = BTM_BLE_CONN_SLAVE_LATENCY_DEF; + + if (supervision_tout != BTM_BLE_CONN_PARAM_UNDEF) + p_dev_rec->conn_params.supervision_tout = supervision_tout; + else + p_dev_rec->conn_params.supervision_tout = BTM_BLE_CONN_TIMEOUT_DEF; + + } + + } + else + { + BTM_TRACE_ERROR("Unknown Device, setting rejected"); + } + } + else + { + BTM_TRACE_ERROR("Illegal Connection Parameters"); + } +} + +/******************************************************************************* +** +** Function BTM_ReadDevInfo +** +** Description This function is called to read the device/address type +** of BD address. +** +** Parameter remote_bda: remote device address +** p_dev_type: output parameter to read the device type. +** p_addr_type: output parameter to read the address type. +** +*******************************************************************************/ +void BTM_ReadDevInfo (BD_ADDR remote_bda, tBT_DEVICE_TYPE *p_dev_type, tBLE_ADDR_TYPE *p_addr_type) +{ + tBTM_SEC_DEV_REC *p_dev_rec = btm_find_dev (remote_bda); + tBTM_INQ_INFO *p_inq_info = BTM_InqDbRead(remote_bda); + + *p_addr_type = BLE_ADDR_PUBLIC; + + if (!p_dev_rec) + { + *p_dev_type = BT_DEVICE_TYPE_BREDR; + /* Check with the BT manager if details about remote device are known */ + if (p_inq_info != NULL) + { + *p_dev_type = p_inq_info->results.device_type ; + *p_addr_type = p_inq_info->results.ble_addr_type; + } else { + /* unknown device, assume BR/EDR */ + BTM_TRACE_DEBUG ("btm_find_dev_type - unknown device, BR/EDR assumed"); + } + } + else /* there is a security device record exisitng */ + { + /* new inquiry result, overwrite device type in security device record */ + if (p_inq_info) + { + p_dev_rec->device_type = p_inq_info->results.device_type; + p_dev_rec->ble.ble_addr_type = p_inq_info->results.ble_addr_type; + } + if (memcmp(p_dev_rec->bd_addr, remote_bda, BD_ADDR_LEN) == 0 && + memcmp(p_dev_rec->ble.pseudo_addr, remote_bda, BD_ADDR_LEN) == 0) + { + *p_dev_type = p_dev_rec->device_type; + *p_addr_type = p_dev_rec->ble.ble_addr_type; + } + else if (memcmp(p_dev_rec->ble.pseudo_addr, remote_bda, BD_ADDR_LEN) == 0) + { + *p_dev_type = BT_DEVICE_TYPE_BLE; + *p_addr_type = p_dev_rec->ble.ble_addr_type; + } + else /* matching static adddress only */ + { + *p_dev_type = BT_DEVICE_TYPE_BREDR; + *p_addr_type = BLE_ADDR_PUBLIC; + } + + } + + BTM_TRACE_DEBUG ("btm_find_dev_type - device_type = %d addr_type = %d", *p_dev_type , *p_addr_type); +} + + +/******************************************************************************* +** +** Function BTM_ReadConnectedTransportAddress +** +** Description This function is called to read the paired device/address type of other device paired +** corresponding to the BD_address +** +** Parameter remote_bda: remote device address, carry out the transport address +** transport: active transport +** +** Return TRUE if an active link is identified; FALSE otherwise +** +*******************************************************************************/ +BOOLEAN BTM_ReadConnectedTransportAddress(BD_ADDR remote_bda, tBT_TRANSPORT transport) +{ + tBTM_SEC_DEV_REC *p_dev_rec = btm_find_dev(remote_bda); + tACL_CONN *p = btm_bda_to_acl(remote_bda, transport); + + /* if no device can be located, return */ + if (p_dev_rec == NULL) + return FALSE; + + if (transport == BT_TRANSPORT_BR_EDR) + { + if (btm_bda_to_acl(p_dev_rec->bd_addr, transport) != NULL) + { + memcpy(remote_bda, p_dev_rec->bd_addr, BD_ADDR_LEN); + return TRUE; + } + else if (p_dev_rec->device_type & BT_DEVICE_TYPE_BREDR) + { + memcpy(remote_bda, p_dev_rec->bd_addr, BD_ADDR_LEN); + } + else + memset(remote_bda, 0, BD_ADDR_LEN); + return FALSE; + } + + if (transport == BT_TRANSPORT_LE) + { + memcpy(remote_bda, p_dev_rec->ble.pseudo_addr, BD_ADDR_LEN); + if (btm_bda_to_acl(p_dev_rec->ble.pseudo_addr, transport) != NULL) + return TRUE; + else + return FALSE; + } + + return FALSE; +} + +/******************************************************************************* +** +** Function BTM_BleReceiverTest +** +** Description This function is called to start the LE Receiver test +** +** Parameter rx_freq - Frequency Range +** p_cmd_cmpl_cback - Command Complete callback +** +*******************************************************************************/ +void BTM_BleReceiverTest(UINT8 rx_freq, tBTM_CMPL_CB *p_cmd_cmpl_cback) +{ + btm_cb.devcb.p_le_test_cmd_cmpl_cb = p_cmd_cmpl_cback; + + if (btsnd_hcic_ble_receiver_test(rx_freq) == FALSE) + { + BTM_TRACE_ERROR("%s: Unable to Trigger LE receiver test", __FUNCTION__); + } +} + +/******************************************************************************* +** +** Function BTM_BleTransmitterTest +** +** Description This function is called to start the LE Transmitter test +** +** Parameter tx_freq - Frequency Range +** test_data_len - Length in bytes of payload data in each packet +** packet_payload - Pattern to use in the payload +** p_cmd_cmpl_cback - Command Complete callback +** +*******************************************************************************/ +void BTM_BleTransmitterTest(UINT8 tx_freq, UINT8 test_data_len, + UINT8 packet_payload, tBTM_CMPL_CB *p_cmd_cmpl_cback) +{ + btm_cb.devcb.p_le_test_cmd_cmpl_cb = p_cmd_cmpl_cback; + if (btsnd_hcic_ble_transmitter_test(tx_freq, test_data_len, packet_payload) == FALSE) + { + BTM_TRACE_ERROR("%s: Unable to Trigger LE transmitter test", __FUNCTION__); + } +} + +/******************************************************************************* +** +** Function BTM_BleTestEnd +** +** Description This function is called to stop the in-progress TX or RX test +** +** Parameter p_cmd_cmpl_cback - Command complete callback +** +*******************************************************************************/ +void BTM_BleTestEnd(tBTM_CMPL_CB *p_cmd_cmpl_cback) +{ + btm_cb.devcb.p_le_test_cmd_cmpl_cb = p_cmd_cmpl_cback; + + if (btsnd_hcic_ble_test_end() == FALSE) + { + BTM_TRACE_ERROR("%s: Unable to End the LE TX/RX test", __FUNCTION__); + } +} + +/******************************************************************************* +** Internal Functions +*******************************************************************************/ +void btm_ble_test_command_complete(UINT8 *p) +{ + tBTM_CMPL_CB *p_cb = btm_cb.devcb.p_le_test_cmd_cmpl_cb; + + btm_cb.devcb.p_le_test_cmd_cmpl_cb = NULL; + + if (p_cb) + { + (*p_cb)(p); + } +} + +/******************************************************************************* +** +** Function BTM_UseLeLink +** +** Description This function is to select the underneath physical link to use. +** +** Returns TRUE to use LE, FALSE use BR/EDR. +** +*******************************************************************************/ +BOOLEAN BTM_UseLeLink (BD_ADDR bd_addr) +{ + tACL_CONN *p; + tBT_DEVICE_TYPE dev_type; + tBLE_ADDR_TYPE addr_type; + BOOLEAN use_le = FALSE; + + if ((p = btm_bda_to_acl(bd_addr, BT_TRANSPORT_BR_EDR)) != NULL) + { + return use_le; + } + else if ((p = btm_bda_to_acl(bd_addr, BT_TRANSPORT_LE)) != NULL) + { + use_le = TRUE; + } + else + { + BTM_ReadDevInfo(bd_addr, &dev_type, &addr_type); + use_le = (dev_type == BT_DEVICE_TYPE_BLE); + } + return use_le; +} + + +/******************************************************************************* +** +** Function BTM_SetBleDataLength +** +** Description This function is to set maximum BLE transmission packet size +** +** Returns BTM_SUCCESS if success; otherwise failed. +** +*******************************************************************************/ +tBTM_STATUS BTM_SetBleDataLength(BD_ADDR bd_addr, UINT16 tx_pdu_length) +{ + tACL_CONN *p_acl = btm_bda_to_acl(bd_addr, BT_TRANSPORT_LE); + BTM_TRACE_DEBUG("%s: tx_pdu_length =%d", __FUNCTION__, tx_pdu_length); + + if (!controller_get_interface()->supports_ble_packet_extension()) + { + BTM_TRACE_ERROR("%s failed, request not supported", __FUNCTION__); + return BTM_ILLEGAL_VALUE; + } + + if (!HCI_LE_DATA_LEN_EXT_SUPPORTED(p_acl->peer_le_features)) + { + BTM_TRACE_ERROR("%s failed, peer does not support request", __FUNCTION__); + return BTM_ILLEGAL_VALUE; + } + + if (p_acl != NULL) + { + if (tx_pdu_length > BTM_BLE_DATA_SIZE_MAX) + tx_pdu_length = BTM_BLE_DATA_SIZE_MAX; + else if (tx_pdu_length < BTM_BLE_DATA_SIZE_MIN) + tx_pdu_length = BTM_BLE_DATA_SIZE_MIN; + + /* always set the TxTime to be max, as controller does not care for now */ + btsnd_hcic_ble_set_data_length(p_acl->hci_handle, tx_pdu_length, + BTM_BLE_DATA_TX_TIME_MAX); + + return BTM_SUCCESS; + } + else + { + BTM_TRACE_ERROR("%s: Wrong mode: no LE link exist or LE not supported",__FUNCTION__); + return BTM_WRONG_MODE; + } +} + +/******************************************************************************* +** +** Function btm_ble_rand_enc_complete +** +** Description This function is the callback functions for HCI_Rand command +** and HCI_Encrypt command is completed. +** This message is received from the HCI. +** +** Returns void +** +*******************************************************************************/ +void btm_ble_rand_enc_complete (UINT8 *p, UINT16 op_code, tBTM_RAND_ENC_CB *p_enc_cplt_cback) +{ + tBTM_RAND_ENC params; + UINT8 *p_dest = params.param_buf; + + BTM_TRACE_DEBUG ("btm_ble_rand_enc_complete"); + + memset(¶ms, 0, sizeof(tBTM_RAND_ENC)); + + /* If there was a callback address for vcs complete, call it */ + if (p_enc_cplt_cback && p) + { + /* Pass paramters to the callback function */ + STREAM_TO_UINT8(params.status, p); /* command status */ + + if (params.status == HCI_SUCCESS) + { + params.opcode = op_code; + + if (op_code == HCI_BLE_RAND) + params.param_len = BT_OCTET8_LEN; + else + params.param_len = BT_OCTET16_LEN; + + memcpy(p_dest, p, params.param_len); /* Fetch return info from HCI event message */ + } + if (p_enc_cplt_cback) + (*p_enc_cplt_cback)(¶ms); /* Call the Encryption complete callback function */ + } +} + + + #if (SMP_INCLUDED == TRUE) + +/******************************************************************************* +** +** Function btm_ble_get_enc_key_type +** +** Description This function is to increment local sign counter +** Returns None +** +*******************************************************************************/ +void btm_ble_increment_sign_ctr(BD_ADDR bd_addr, BOOLEAN is_local ) +{ + tBTM_SEC_DEV_REC *p_dev_rec; + + BTM_TRACE_DEBUG ("btm_ble_increment_sign_ctr is_local=%d", is_local); + + if ((p_dev_rec = btm_find_dev (bd_addr)) != NULL) + { + if (is_local) + p_dev_rec->ble.keys.local_counter++; + else + p_dev_rec->ble.keys.counter++; + BTM_TRACE_DEBUG ("is_local=%d local sign counter=%d peer sign counter=%d", + is_local, + p_dev_rec->ble.keys.local_counter, + p_dev_rec->ble.keys.counter); + } +} + +/******************************************************************************* +** +** Function btm_ble_get_enc_key_type +** +** Description This function is to get the BLE key type that has been exchanged +** in betweem local device and peer device. +** +** Returns p_key_type: output parameter to carry the key type value. +** +*******************************************************************************/ +BOOLEAN btm_ble_get_enc_key_type(BD_ADDR bd_addr, UINT8 *p_key_types) +{ + tBTM_SEC_DEV_REC *p_dev_rec; + + BTM_TRACE_DEBUG ("btm_ble_get_enc_key_type"); + + if ((p_dev_rec = btm_find_dev (bd_addr)) != NULL) + { + *p_key_types = p_dev_rec->ble.key_type; + return TRUE; + } + return FALSE; +} + +/******************************************************************************* +** +** Function btm_get_local_div +** +** Description This function is called to read the local DIV +** +** Returns TURE - if a valid DIV is availavle +*******************************************************************************/ +BOOLEAN btm_get_local_div (BD_ADDR bd_addr, UINT16 *p_div) +{ + tBTM_SEC_DEV_REC *p_dev_rec; + BOOLEAN status = FALSE; + BTM_TRACE_DEBUG ("btm_get_local_div"); + + BTM_TRACE_DEBUG("bd_addr:%02x-%02x-%02x-%02x-%02x-%02x", + bd_addr[0],bd_addr[1], + bd_addr[2],bd_addr[3], + bd_addr[4],bd_addr[5]); + + *p_div = 0; + p_dev_rec = btm_find_dev (bd_addr); + + if (p_dev_rec && p_dev_rec->ble.keys.div) + { + status = TRUE; + *p_div = p_dev_rec->ble.keys.div; + } + BTM_TRACE_DEBUG ("btm_get_local_div status=%d (1-OK) DIV=0x%x", status, *p_div); + return status; +} + +/******************************************************************************* +** +** Function btm_sec_save_le_key +** +** Description This function is called by the SMP to update +** an BLE key. SMP is internal, whereas all the keys shall +** be sent to the application. The function is also called +** when application passes ble key stored in NVRAM to the btm_sec. +** pass_to_application parameter is false in this case. +** +** Returns void +** +*******************************************************************************/ +void btm_sec_save_le_key(BD_ADDR bd_addr, tBTM_LE_KEY_TYPE key_type, tBTM_LE_KEY_VALUE *p_keys, + BOOLEAN pass_to_application) +{ + tBTM_SEC_DEV_REC *p_rec; + tBTM_LE_EVT_DATA cb_data; + UINT8 i; + + BTM_TRACE_DEBUG ("btm_sec_save_le_key key_type=0x%x pass_to_application=%d",key_type, pass_to_application); + /* Store the updated key in the device database */ + + BTM_TRACE_DEBUG("bd_addr:%02x-%02x-%02x-%02x-%02x-%02x", + bd_addr[0],bd_addr[1], + bd_addr[2],bd_addr[3], + bd_addr[4],bd_addr[5]); + + if ((p_rec = btm_find_dev (bd_addr)) != NULL && (p_keys || key_type== BTM_LE_KEY_LID)) + { + btm_ble_init_pseudo_addr (p_rec, bd_addr); + + switch (key_type) + { + case BTM_LE_KEY_PENC: + memcpy(p_rec->ble.keys.pltk, p_keys->penc_key.ltk, BT_OCTET16_LEN); + memcpy(p_rec->ble.keys.rand, p_keys->penc_key.rand, BT_OCTET8_LEN); + p_rec->ble.keys.sec_level = p_keys->penc_key.sec_level; + p_rec->ble.keys.ediv = p_keys->penc_key.ediv; + p_rec->ble.keys.key_size = p_keys->penc_key.key_size; + p_rec->ble.key_type |= BTM_LE_KEY_PENC; + p_rec->sec_flags |= BTM_SEC_LE_LINK_KEY_KNOWN; + if (p_keys->penc_key.sec_level == SMP_SEC_AUTHENTICATED) + p_rec->sec_flags |= BTM_SEC_LE_LINK_KEY_AUTHED; + else + p_rec->sec_flags &= ~BTM_SEC_LE_LINK_KEY_AUTHED; + BTM_TRACE_DEBUG("BTM_LE_KEY_PENC key_type=0x%x sec_flags=0x%x sec_leve=0x%x", + p_rec->ble.key_type, + p_rec->sec_flags, + p_rec->ble.keys.sec_level); + break; + + case BTM_LE_KEY_PID: + for (i=0; ible.keys.irk[i] = p_keys->pid_key.irk[i]; + } + + //memcpy( p_rec->ble.keys.irk, p_keys->pid_key, BT_OCTET16_LEN); todo will crash the system + memcpy(p_rec->ble.static_addr, p_keys->pid_key.static_addr, BD_ADDR_LEN); + p_rec->ble.static_addr_type = p_keys->pid_key.addr_type; + p_rec->ble.key_type |= BTM_LE_KEY_PID; + BTM_TRACE_DEBUG("BTM_LE_KEY_PID key_type=0x%x save peer IRK", p_rec->ble.key_type); + /* update device record address as static address */ + memcpy(p_rec->bd_addr, p_keys->pid_key.static_addr, BD_ADDR_LEN); + /* combine DUMO device security record if needed */ + btm_consolidate_dev(p_rec); + break; + + case BTM_LE_KEY_PCSRK: + memcpy(p_rec->ble.keys.pcsrk, p_keys->pcsrk_key.csrk, BT_OCTET16_LEN); + p_rec->ble.keys.srk_sec_level = p_keys->pcsrk_key.sec_level; + p_rec->ble.keys.counter = p_keys->pcsrk_key.counter; + p_rec->ble.key_type |= BTM_LE_KEY_PCSRK; + p_rec->sec_flags |= BTM_SEC_LE_LINK_KEY_KNOWN; + if ( p_keys->pcsrk_key.sec_level== SMP_SEC_AUTHENTICATED) + p_rec->sec_flags |= BTM_SEC_LE_LINK_KEY_AUTHED; + else + p_rec->sec_flags &= ~BTM_SEC_LE_LINK_KEY_AUTHED; + + BTM_TRACE_DEBUG("BTM_LE_KEY_PCSRK key_type=0x%x sec_flags=0x%x sec_level=0x%x peer_counter=%d", + p_rec->ble.key_type, + p_rec->sec_flags, + p_rec->ble.keys.srk_sec_level, + p_rec->ble.keys.counter ); + break; + + case BTM_LE_KEY_LENC: + memcpy(p_rec->ble.keys.lltk, p_keys->lenc_key.ltk, BT_OCTET16_LEN); + p_rec->ble.keys.div = p_keys->lenc_key.div; /* update DIV */ + p_rec->ble.keys.sec_level = p_keys->lenc_key.sec_level; + p_rec->ble.keys.key_size = p_keys->lenc_key.key_size; + p_rec->ble.key_type |= BTM_LE_KEY_LENC; + + BTM_TRACE_DEBUG("BTM_LE_KEY_LENC key_type=0x%x DIV=0x%x key_size=0x%x sec_level=0x%x", + p_rec->ble.key_type, + p_rec->ble.keys.div, + p_rec->ble.keys.key_size, + p_rec->ble.keys.sec_level ); + break; + + case BTM_LE_KEY_LCSRK:/* local CSRK has been delivered */ + memcpy (p_rec->ble.keys.lcsrk, p_keys->lcsrk_key.csrk, BT_OCTET16_LEN); + p_rec->ble.keys.div = p_keys->lcsrk_key.div; /* update DIV */ + p_rec->ble.keys.local_csrk_sec_level = p_keys->lcsrk_key.sec_level; + p_rec->ble.keys.local_counter = p_keys->lcsrk_key.counter; + p_rec->ble.key_type |= BTM_LE_KEY_LCSRK; + BTM_TRACE_DEBUG("BTM_LE_KEY_LCSRK key_type=0x%x DIV=0x%x scrk_sec_level=0x%x local_counter=%d", + p_rec->ble.key_type, + p_rec->ble.keys.div, + p_rec->ble.keys.local_csrk_sec_level, + p_rec->ble.keys.local_counter ); + break; + + case BTM_LE_KEY_LID: + p_rec->ble.key_type |= BTM_LE_KEY_LID; + break; + default: + BTM_TRACE_WARNING("btm_sec_save_le_key (Bad key_type 0x%02x)", key_type); + return; + } + + BTM_TRACE_DEBUG ("BLE key type 0x%02x updated for BDA: %08x%04x (btm_sec_save_le_key)", key_type, + (bd_addr[0]<<24)+(bd_addr[1]<<16)+(bd_addr[2]<<8)+bd_addr[3], + (bd_addr[4]<<8)+bd_addr[5]); + + /* Notify the application that one of the BLE keys has been updated + If link key is in progress, it will get sent later.*/ + if (pass_to_application && btm_cb.api.p_le_callback) + { + cb_data.key.p_key_value = p_keys; + cb_data.key.key_type = key_type; + + (*btm_cb.api.p_le_callback) (BTM_LE_KEY_EVT, bd_addr, &cb_data); + } + return; + } + + BTM_TRACE_WARNING ("BLE key type 0x%02x called for Unknown BDA or type: %08x%04x !! (btm_sec_save_le_key)", key_type, + (bd_addr[0]<<24)+(bd_addr[1]<<16)+(bd_addr[2]<<8)+bd_addr[3], + (bd_addr[4]<<8)+bd_addr[5]); + + if (p_rec) + { + BTM_TRACE_DEBUG ("sec_flags=0x%x", p_rec->sec_flags); + } +} + +/******************************************************************************* +** +** Function btm_ble_update_sec_key_size +** +** Description update the current lin kencryption key size +** +** Returns void +** +*******************************************************************************/ +void btm_ble_update_sec_key_size(BD_ADDR bd_addr, UINT8 enc_key_size) +{ + tBTM_SEC_DEV_REC *p_rec; + + BTM_TRACE_DEBUG("btm_ble_update_sec_key_size enc_key_size = %d", enc_key_size); + + if ((p_rec = btm_find_dev (bd_addr)) != NULL ) + { + p_rec->enc_key_size = enc_key_size; + } +} + +/******************************************************************************* +** +** Function btm_ble_read_sec_key_size +** +** Description update the current lin kencryption key size +** +** Returns void +** +*******************************************************************************/ +UINT8 btm_ble_read_sec_key_size(BD_ADDR bd_addr) +{ + tBTM_SEC_DEV_REC *p_rec; + + if ((p_rec = btm_find_dev (bd_addr)) != NULL ) + { + return p_rec->enc_key_size; + } + else + return 0; +} + +/******************************************************************************* +** +** Function btm_ble_link_sec_check +** +** Description Check BLE link security level match. +** +** Returns TRUE: check is OK and the *p_sec_req_act contain the action +** +*******************************************************************************/ +void btm_ble_link_sec_check(BD_ADDR bd_addr, tBTM_LE_AUTH_REQ auth_req, tBTM_BLE_SEC_REQ_ACT *p_sec_req_act) +{ + tBTM_SEC_DEV_REC *p_dev_rec = btm_find_dev (bd_addr); + UINT8 req_sec_level = BTM_LE_SEC_NONE, cur_sec_level = BTM_LE_SEC_NONE; + + BTM_TRACE_DEBUG ("btm_ble_link_sec_check auth_req =0x%x", auth_req); + + if (p_dev_rec == NULL) + { + BTM_TRACE_ERROR ("btm_ble_link_sec_check received for unknown device"); + return; + } + + if (p_dev_rec->sec_state == BTM_SEC_STATE_ENCRYPTING || + p_dev_rec->sec_state == BTM_SEC_STATE_AUTHENTICATING) + { + /* race condition: discard the security request while master is encrypting the link */ + *p_sec_req_act = BTM_BLE_SEC_REQ_ACT_DISCARD; + } + else + { + req_sec_level = BTM_LE_SEC_UNAUTHENTICATE; + if (auth_req & BTM_LE_AUTH_REQ_MITM) + { + req_sec_level = BTM_LE_SEC_AUTHENTICATED; + } + + BTM_TRACE_DEBUG ("dev_rec sec_flags=0x%x", p_dev_rec->sec_flags); + + /* currently encrpted */ + if (p_dev_rec->sec_flags & BTM_SEC_LE_ENCRYPTED) + { + if (p_dev_rec->sec_flags & BTM_SEC_LE_AUTHENTICATED) + cur_sec_level = BTM_LE_SEC_AUTHENTICATED; + else + cur_sec_level = BTM_LE_SEC_UNAUTHENTICATE; + } + else /* unencrypted link */ + { + /* if bonded, get the key security level */ + if (p_dev_rec->ble.key_type & BTM_LE_KEY_PENC) + cur_sec_level = p_dev_rec->ble.keys.sec_level; + else + cur_sec_level = BTM_LE_SEC_NONE; + } + + if (cur_sec_level >= req_sec_level) + { + /* To avoid re-encryption on an encrypted link for an equal condition encryption */ + *p_sec_req_act = BTM_BLE_SEC_REQ_ACT_ENCRYPT; + } + else + { + *p_sec_req_act = BTM_BLE_SEC_REQ_ACT_PAIR; /* start the pariring process to upgrade the keys*/ + } + } + + BTM_TRACE_DEBUG("cur_sec_level=%d req_sec_level=%d sec_req_act=%d", + cur_sec_level, + req_sec_level, + *p_sec_req_act); + +} + +/******************************************************************************* +** +** Function btm_ble_set_encryption +** +** Description This function is called to ensure that LE connection is +** encrypted. Should be called only on an open connection. +** Typically only needed for connections that first want to +** bring up unencrypted links, then later encrypt them. +** +** Returns void +** the local device ER is copied into er +** +*******************************************************************************/ +tBTM_STATUS btm_ble_set_encryption (BD_ADDR bd_addr, void *p_ref_data, UINT8 link_role) +{ + tBTM_STATUS cmd = BTM_NO_RESOURCES; + tBTM_BLE_SEC_ACT sec_act = *(tBTM_BLE_SEC_ACT *)p_ref_data ; + tBTM_SEC_DEV_REC *p_rec = btm_find_dev (bd_addr); + tBTM_BLE_SEC_REQ_ACT sec_req_act; + tBTM_LE_AUTH_REQ auth_req; + + if (p_rec == NULL) + { + BTM_TRACE_WARNING ("btm_ble_set_encryption (NULL device record!! sec_act=0x%x", sec_act); + return(BTM_WRONG_MODE); + } + + BTM_TRACE_DEBUG ("btm_ble_set_encryption sec_act=0x%x role_master=%d", sec_act, p_rec->role_master); + + if (sec_act == BTM_BLE_SEC_ENCRYPT_MITM) + { + p_rec->security_required |= BTM_SEC_IN_MITM; + } + + switch (sec_act) + { + case BTM_BLE_SEC_ENCRYPT: + if (link_role == BTM_ROLE_MASTER) + { + /* start link layer encryption using the security info stored */ + cmd = btm_ble_start_encrypt(bd_addr, FALSE, NULL); + break; + } + /* if salve role then fall through to call SMP_Pair below which will send a + sec_request to request the master to encrypt the link */ + case BTM_BLE_SEC_ENCRYPT_NO_MITM: + case BTM_BLE_SEC_ENCRYPT_MITM: + if (link_role == BTM_ROLE_MASTER) + { + auth_req = (sec_act == BTM_BLE_SEC_ENCRYPT_NO_MITM) + ? SMP_AUTH_GEN_BOND : (SMP_AUTH_GEN_BOND | SMP_AUTH_YN_BIT); + btm_ble_link_sec_check (bd_addr, auth_req, &sec_req_act); + + if (sec_req_act == BTM_BLE_SEC_REQ_ACT_ENCRYPT) + { + cmd = btm_ble_start_encrypt(bd_addr, FALSE, NULL); + break; + } + } + + if (SMP_Pair(bd_addr) == SMP_STARTED) + { + cmd = BTM_CMD_STARTED; + p_rec->sec_state = BTM_SEC_STATE_AUTHENTICATING; + } + break; + + default: + cmd = BTM_WRONG_MODE; + break; + } + return cmd; +} + +/******************************************************************************* +** +** Function btm_ble_ltk_request +** +** Description This function is called when encryption request is received +** on a slave device. +** +** +** Returns void +** +*******************************************************************************/ +void btm_ble_ltk_request(UINT16 handle, UINT8 rand[8], UINT16 ediv) +{ + tBTM_CB *p_cb = &btm_cb; + tBTM_SEC_DEV_REC *p_dev_rec = btm_find_dev_by_handle (handle); + BT_OCTET8 dummy_stk = {0}; + + BTM_TRACE_DEBUG ("btm_ble_ltk_request"); + + p_cb->ediv = ediv; + + memcpy(p_cb->enc_rand, rand, BT_OCTET8_LEN); + + if (p_dev_rec != NULL) + { + if (!smp_proc_ltk_request(p_dev_rec->bd_addr)) + btm_ble_ltk_request_reply(p_dev_rec->bd_addr, FALSE, dummy_stk); + } + +} + +/******************************************************************************* +** +** Function btm_ble_start_encrypt +** +** Description This function is called to start LE encryption. +** +** +** Returns BTM_SUCCESS if encryption was started successfully +** +*******************************************************************************/ +tBTM_STATUS btm_ble_start_encrypt(BD_ADDR bda, BOOLEAN use_stk, BT_OCTET16 stk) +{ + tBTM_CB *p_cb = &btm_cb; + tBTM_SEC_DEV_REC *p_rec = btm_find_dev (bda); + BT_OCTET8 dummy_rand = {0}; + tBTM_STATUS rt = BTM_NO_RESOURCES; + + BTM_TRACE_DEBUG ("btm_ble_start_encrypt"); + + if (!p_rec ) + { + BTM_TRACE_ERROR("Link is not active, can not encrypt!"); + return BTM_WRONG_MODE; + } + + if (p_rec->sec_state == BTM_SEC_STATE_ENCRYPTING) + { + BTM_TRACE_WARNING("Link Encryption is active, Busy!"); + return BTM_BUSY; + } + + p_cb->enc_handle = p_rec->ble_hci_handle; + + if (use_stk) + { + if (btsnd_hcic_ble_start_enc(p_rec->ble_hci_handle, dummy_rand, 0, stk)) + rt = BTM_CMD_STARTED; + } + else if (p_rec->ble.key_type & BTM_LE_KEY_PENC) + { + if (btsnd_hcic_ble_start_enc(p_rec->ble_hci_handle, p_rec->ble.keys.rand, + p_rec->ble.keys.ediv, p_rec->ble.keys.pltk)) + rt = BTM_CMD_STARTED; + } + else + { + BTM_TRACE_ERROR("No key available to encrypt the link"); + } + if (rt == BTM_CMD_STARTED) + { + if (p_rec->sec_state == BTM_SEC_STATE_IDLE) + p_rec->sec_state = BTM_SEC_STATE_ENCRYPTING; + } + + return rt; +} + +/******************************************************************************* +** +** Function btm_ble_link_encrypted +** +** Description This function is called when LE link encrption status is changed. +** +** Returns void +** +*******************************************************************************/ +void btm_ble_link_encrypted(BD_ADDR bd_addr, UINT8 encr_enable) +{ + tBTM_SEC_DEV_REC *p_dev_rec = btm_find_dev (bd_addr); + BOOLEAN enc_cback; + + if (!p_dev_rec) + { + BTM_TRACE_WARNING ("btm_ble_link_encrypted (No Device Found!) encr_enable=%d", encr_enable); + return; + } + + BTM_TRACE_DEBUG ("btm_ble_link_encrypted encr_enable=%d", encr_enable); + + enc_cback = (p_dev_rec->sec_state == BTM_SEC_STATE_ENCRYPTING); + + smp_link_encrypted(bd_addr, encr_enable); + + BTM_TRACE_DEBUG(" p_dev_rec->sec_flags=0x%x", p_dev_rec->sec_flags); + + if (encr_enable && p_dev_rec->enc_key_size == 0) + p_dev_rec->enc_key_size = p_dev_rec->ble.keys.key_size; + + p_dev_rec->sec_state = BTM_SEC_STATE_IDLE; + if (p_dev_rec->p_callback && enc_cback) + { + if (encr_enable) + btm_sec_dev_rec_cback_event(p_dev_rec, BTM_SUCCESS, TRUE); + else if (p_dev_rec->role_master) + btm_sec_dev_rec_cback_event(p_dev_rec, BTM_ERR_PROCESSING, TRUE); + + } + /* to notify GATT to send data if any request is pending */ + gatt_notify_enc_cmpl(p_dev_rec->ble.pseudo_addr); +} + +/******************************************************************************* +** Function btm_enc_proc_ltk +** Description send LTK reply when it's ready. +*******************************************************************************/ +static void btm_enc_proc_ltk(tSMP_ENC *p) +{ + UINT8 i; + BTM_TRACE_DEBUG ("btm_enc_proc_ltk"); + if (p && p->param_len == BT_OCTET16_LEN) + { + for (i = 0; i < (BT_OCTET16_LEN - btm_cb.key_size); i ++) + p->param_buf[BT_OCTET16_LEN - i - 1] = 0; + btsnd_hcic_ble_ltk_req_reply(btm_cb.enc_handle, p->param_buf); + } +} + +/******************************************************************************* +** Function btm_enc_proc_slave_y +** Description calculate LTK when Y is ready +*******************************************************************************/ +static void btm_enc_proc_slave_y(tSMP_ENC *p) +{ + UINT16 div, y; + UINT8 *pp = p->param_buf; + tBTM_CB *p_cb = &btm_cb; + tSMP_ENC output; + tBTM_SEC_DEV_REC *p_dev_rec; + + BTM_TRACE_DEBUG ("btm_enc_proc_slave_y"); + if (p != NULL) + { + STREAM_TO_UINT16(y, pp); + + div = p_cb->ediv ^ y; + p_dev_rec = btm_find_dev_by_handle (p_cb->enc_handle); + + if ( p_dev_rec && + p_dev_rec->ble.keys.div == div ) + { + BTM_TRACE_DEBUG ("LTK request OK"); + /* calculating LTK , LTK = E er(div) */ + SMP_Encrypt(p_cb->devcb.ble_encryption_key_value, BT_OCTET16_LEN, (UINT8 *)&div, 2, &output); + btm_enc_proc_ltk(&output); + } + else + { + BTM_TRACE_DEBUG ("LTK request failed - send negative reply"); + btsnd_hcic_ble_ltk_req_neg_reply(p_cb->enc_handle); + if (p_dev_rec) + btm_ble_link_encrypted(p_dev_rec->bd_addr, 0); + + } + } +} + +/******************************************************************************* +** +** Function btm_ble_ltk_request_reply +** +** Description This function is called to send a LTK request reply on a slave +** device. +** +** Returns void +** +*******************************************************************************/ +void btm_ble_ltk_request_reply(BD_ADDR bda, BOOLEAN use_stk, BT_OCTET16 stk) +{ + tBTM_SEC_DEV_REC *p_rec = btm_find_dev (bda); + tBTM_CB *p_cb = &btm_cb; + tSMP_ENC output; + + if (p_rec == NULL) + { + BTM_TRACE_ERROR("btm_ble_ltk_request_reply received for unknown device"); + return; + } + + BTM_TRACE_DEBUG ("btm_ble_ltk_request_reply"); + p_cb->enc_handle = p_rec->ble_hci_handle; + p_cb->key_size = p_rec->ble.keys.key_size; + + BTM_TRACE_ERROR("key size = %d", p_rec->ble.keys.key_size); + if (use_stk) + { + btsnd_hcic_ble_ltk_req_reply(btm_cb.enc_handle, stk); + } + else /* calculate LTK using peer device */ + { + if (p_rec->ble.key_type & BTM_LE_KEY_LENC) + btsnd_hcic_ble_ltk_req_reply(btm_cb.enc_handle, p_rec->ble.keys.lltk); + else + btsnd_hcic_ble_ltk_req_neg_reply(btm_cb.enc_handle); + } +} + +/******************************************************************************* +** +** Function btm_ble_io_capabilities_req +** +** Description This function is called to handle SMP get IO capability request. +** +** Returns void +** +*******************************************************************************/ +UINT8 btm_ble_io_capabilities_req(tBTM_SEC_DEV_REC *p_dev_rec, tBTM_LE_IO_REQ *p_data) +{ + UINT8 callback_rc = BTM_SUCCESS; + BTM_TRACE_DEBUG ("btm_ble_io_capabilities_req"); + if (btm_cb.api.p_le_callback) + { + /* the callback function implementation may change the IO capability... */ + callback_rc = (*btm_cb.api.p_le_callback) (BTM_LE_IO_REQ_EVT, p_dev_rec->bd_addr, (tBTM_LE_EVT_DATA *)p_data); + } +#if BTM_OOB_INCLUDED == TRUE + if ((callback_rc == BTM_SUCCESS) || (BTM_OOB_UNKNOWN != p_data->oob_data)) +#else + if (callback_rc == BTM_SUCCESS) +#endif + { +#if BTM_BLE_CONFORMANCE_TESTING == TRUE + if (btm_cb.devcb.keep_rfu_in_auth_req) + { + BTM_TRACE_DEBUG ("btm_ble_io_capabilities_req keep_rfu_in_auth_req = %u", + btm_cb.devcb.keep_rfu_in_auth_req); + p_data->auth_req &= BTM_LE_AUTH_REQ_MASK_KEEP_RFU; + btm_cb.devcb.keep_rfu_in_auth_req = FALSE; + } + else + { /* default */ + p_data->auth_req &= BTM_LE_AUTH_REQ_MASK; + } +#else + p_data->auth_req &= BTM_LE_AUTH_REQ_MASK; +#endif + + BTM_TRACE_DEBUG ("btm_ble_io_capabilities_req 1: p_dev_rec->security_required = %d auth_req:%d", + p_dev_rec->security_required, p_data->auth_req); + BTM_TRACE_DEBUG ("btm_ble_io_capabilities_req 2: i_keys=0x%x r_keys=0x%x (bit 0-LTK 1-IRK 2-CSRK)", + p_data->init_keys, + p_data->resp_keys); + + /* if authentication requires MITM protection, put on the mask */ + if (p_dev_rec->security_required & BTM_SEC_IN_MITM) + p_data->auth_req |= BTM_LE_AUTH_REQ_MITM; + + if (!(p_data->auth_req & SMP_AUTH_BOND)) + { + BTM_TRACE_DEBUG("Non bonding: No keys should be exchanged"); + p_data->init_keys = 0; + p_data->resp_keys = 0; + } + + BTM_TRACE_DEBUG ("btm_ble_io_capabilities_req 3: auth_req:%d", p_data->auth_req); + BTM_TRACE_DEBUG ("btm_ble_io_capabilities_req 4: i_keys=0x%x r_keys=0x%x", + p_data->init_keys, + p_data->resp_keys); + + BTM_TRACE_DEBUG ("btm_ble_io_capabilities_req 5: p_data->io_cap = %d auth_req:%d", + p_data->io_cap, p_data->auth_req); + + /* remove MITM protection requirement if IO cap does not allow it */ + if ((p_data->io_cap == BTM_IO_CAP_NONE) && p_data->oob_data == SMP_OOB_NONE) + p_data->auth_req &= ~BTM_LE_AUTH_REQ_MITM; + + if (!(p_data->auth_req & SMP_SC_SUPPORT_BIT)) + { + /* if Secure Connections are not supported then remove LK derivation, + ** and keypress notifications. + */ + BTM_TRACE_DEBUG("%s-SC not supported -> No LK derivation, no keypress notifications", + __func__); + p_data->auth_req &= ~SMP_KP_SUPPORT_BIT; + p_data->init_keys &= ~SMP_SEC_KEY_TYPE_LK; + p_data->resp_keys &= ~SMP_SEC_KEY_TYPE_LK; + } + + BTM_TRACE_DEBUG ("btm_ble_io_capabilities_req 6: IO_CAP:%d oob_data:%d auth_req:0x%02x", + p_data->io_cap, p_data->oob_data, p_data->auth_req); + } + return callback_rc; +} + +/******************************************************************************* +** +** Function btm_ble_br_keys_req +** +** Description This function is called to handle SMP request for keys sent +** over BR/EDR. +** +** Returns void +** +*******************************************************************************/ +UINT8 btm_ble_br_keys_req(tBTM_SEC_DEV_REC *p_dev_rec, tBTM_LE_IO_REQ *p_data) +{ + UINT8 callback_rc = BTM_SUCCESS; + BTM_TRACE_DEBUG ("%s", __func__); + if (btm_cb.api.p_le_callback) + { + /* the callback function implementation may change the IO capability... */ + callback_rc = (*btm_cb.api.p_le_callback) (BTM_LE_IO_REQ_EVT, p_dev_rec->bd_addr, + (tBTM_LE_EVT_DATA *)p_data); + } + + return callback_rc; +} + +#if (BLE_PRIVACY_SPT == TRUE ) +/******************************************************************************* +** +** Function btm_ble_resolve_random_addr_on_conn_cmpl +** +** Description resolve random address complete on connection complete event. +** +** Returns void +** +*******************************************************************************/ +static void btm_ble_resolve_random_addr_on_conn_cmpl(void * p_rec, void *p_data) +{ + UINT8 *p = (UINT8 *)p_data; + tBTM_SEC_DEV_REC *match_rec = (tBTM_SEC_DEV_REC *) p_rec; + UINT8 role, bda_type; + UINT16 handle; + BD_ADDR bda; + UINT16 conn_interval, conn_latency, conn_timeout; + BOOLEAN match = FALSE; + + ++p; + STREAM_TO_UINT16 (handle, p); + STREAM_TO_UINT8 (role, p); + STREAM_TO_UINT8 (bda_type, p); + STREAM_TO_BDADDR (bda, p); + STREAM_TO_UINT16 (conn_interval, p); + STREAM_TO_UINT16 (conn_latency, p); + STREAM_TO_UINT16 (conn_timeout, p); + + handle = HCID_GET_HANDLE (handle); + + BTM_TRACE_EVENT ("%s", __func__); + + if (match_rec) + { + LOG_INFO("%s matched and resolved random address", __func__); + match = TRUE; + match_rec->ble.active_addr_type = BTM_BLE_ADDR_RRA; + memcpy(match_rec->ble.cur_rand_addr, bda, BD_ADDR_LEN); + if (!btm_ble_init_pseudo_addr (match_rec, bda)) + { + /* assign the original address to be the current report address */ + memcpy(bda, match_rec->ble.pseudo_addr, BD_ADDR_LEN); + } + else + { + memcpy(bda, match_rec->bd_addr, BD_ADDR_LEN); + } + } + else + { + LOG_INFO("%s unable to match and resolve random address", __func__); + } + + btm_ble_connected(bda, handle, HCI_ENCRYPT_MODE_DISABLED, role, bda_type, match); + + l2cble_conn_comp (handle, role, bda, bda_type, conn_interval, + conn_latency, conn_timeout); + + return; +} +#endif + +/******************************************************************************* +** +** Function btm_ble_connected +** +** Description This function is when a LE connection to the peer device is +** establsihed +** +** Returns void +** +*******************************************************************************/ +void btm_ble_connected (UINT8 *bda, UINT16 handle, UINT8 enc_mode, UINT8 role, + tBLE_ADDR_TYPE addr_type, BOOLEAN addr_matched) +{ + tBTM_SEC_DEV_REC *p_dev_rec = btm_find_dev (bda); + tBTM_BLE_CB *p_cb = &btm_cb.ble_ctr_cb; + UNUSED(addr_matched); + + BTM_TRACE_EVENT ("btm_ble_connected"); + + /* Commenting out trace due to obf/compilation problems. + */ +#if (BT_USE_TRACES == TRUE) + if (p_dev_rec) + { + BTM_TRACE_EVENT ("Security Manager: btm_ble_connected : handle:%d enc_mode:%d bda:%x RName:%s", + handle, enc_mode, + (bda[2]<<24)+(bda[3]<<16)+(bda[4]<<8)+bda[5], + p_dev_rec->sec_bd_name); + + BTM_TRACE_DEBUG ("btm_ble_connected sec_flags=0x%x",p_dev_rec->sec_flags); + } + else + { + BTM_TRACE_EVENT ("Security Manager: btm_ble_connected: handle:%d enc_mode:%d bda:%x ", + handle, enc_mode, + (bda[2]<<24)+(bda[3]<<16)+(bda[4]<<8)+bda[5]); + } +#endif + + if (!p_dev_rec) + { + /* There is no device record for new connection. Allocate one */ + if ((p_dev_rec = btm_sec_alloc_dev (bda)) == NULL) + return; + } + else /* Update the timestamp for this device */ + { + p_dev_rec->timestamp = btm_cb.dev_rec_count++; + } + + /* update device information */ + p_dev_rec->device_type |= BT_DEVICE_TYPE_BLE; + p_dev_rec->ble_hci_handle = handle; + p_dev_rec->ble.ble_addr_type = addr_type; + /* update pseudo address */ + memcpy(p_dev_rec->ble.pseudo_addr, bda, BD_ADDR_LEN); + + p_dev_rec->role_master = FALSE; + if (role == HCI_ROLE_MASTER) + p_dev_rec->role_master = TRUE; + +#if (defined BLE_PRIVACY_SPT && BLE_PRIVACY_SPT == TRUE) + if (!addr_matched) + p_dev_rec->ble.active_addr_type = BTM_BLE_ADDR_PSEUDO; + + if (p_dev_rec->ble.ble_addr_type == BLE_ADDR_RANDOM && !addr_matched) + memcpy(p_dev_rec->ble.cur_rand_addr, bda, BD_ADDR_LEN); +#endif + + p_cb->inq_var.directed_conn = BTM_BLE_CONNECT_EVT; + + return; +} + +/***************************************************************************** +** Function btm_ble_conn_complete +** +** Description LE connection complete. +** +******************************************************************************/ +void btm_ble_conn_complete(UINT8 *p, UINT16 evt_len, BOOLEAN enhanced) +{ +#if (BLE_PRIVACY_SPT == TRUE ) + UINT8 *p_data = p, peer_addr_type; +#endif + UINT8 role, status, bda_type; + UINT16 handle; + BD_ADDR bda, local_rpa, peer_rpa; + UINT16 conn_interval, conn_latency, conn_timeout; + BOOLEAN match = FALSE; + UNUSED(evt_len); + + STREAM_TO_UINT8 (status, p); + STREAM_TO_UINT16 (handle, p); + STREAM_TO_UINT8 (role, p); + STREAM_TO_UINT8 (bda_type, p); + STREAM_TO_BDADDR (bda, p); + + if (status == 0) + { +#if (BLE_PRIVACY_SPT == TRUE ) + peer_addr_type = bda_type; + match = btm_identity_addr_to_random_pseudo (bda, &bda_type, TRUE); + + if (enhanced) + { + STREAM_TO_BDADDR (local_rpa, p); + STREAM_TO_BDADDR (peer_rpa, p); + } + + /* possiblly receive connection complete with resolvable random on + slave role while the device has been paired */ + if (!match && role == HCI_ROLE_SLAVE && BTM_BLE_IS_RESOLVE_BDA(bda)) + { + btm_ble_resolve_random_addr(bda, btm_ble_resolve_random_addr_on_conn_cmpl, p_data); + } + else +#endif + { + STREAM_TO_UINT16 (conn_interval, p); + STREAM_TO_UINT16 (conn_latency, p); + STREAM_TO_UINT16 (conn_timeout, p); + handle = HCID_GET_HANDLE (handle); + + btm_ble_connected(bda, handle, HCI_ENCRYPT_MODE_DISABLED, role, bda_type, match); + + l2cble_conn_comp (handle, role, bda, bda_type, conn_interval, + conn_latency, conn_timeout); + +#if (BLE_PRIVACY_SPT == TRUE) + if (enhanced) + { + btm_ble_refresh_local_resolvable_private_addr(bda, local_rpa); + + if (peer_addr_type & BLE_ADDR_TYPE_ID_BIT) + btm_ble_refresh_peer_resolvable_private_addr(bda, peer_rpa, BLE_ADDR_RANDOM); + } +#endif + } + } + else + { + role = HCI_ROLE_UNKNOWN; + if (status != HCI_ERR_DIRECTED_ADVERTISING_TIMEOUT) + { + btm_ble_set_conn_st(BLE_CONN_IDLE); +#if (defined BLE_PRIVACY_SPT && BLE_PRIVACY_SPT == TRUE) + btm_ble_disable_resolving_list(BTM_BLE_RL_INIT, TRUE); +#endif + } + else + { +#if (defined BLE_PRIVACY_SPT && BLE_PRIVACY_SPT == TRUE) + btm_cb.ble_ctr_cb.inq_var.adv_mode = BTM_BLE_ADV_DISABLE; + btm_ble_disable_resolving_list(BTM_BLE_RL_ADV, TRUE); +#endif + } + } + + btm_ble_update_mode_operation(role, bda, status); +} + + + +/***************************************************************************** +** Function btm_ble_create_ll_conn_complete +** +** Description LE connection complete. +** +******************************************************************************/ +void btm_ble_create_ll_conn_complete (UINT8 status) +{ + if (status != HCI_SUCCESS) + { + btm_ble_set_conn_st(BLE_CONN_IDLE); + btm_ble_update_mode_operation(HCI_ROLE_UNKNOWN, NULL, status); + } +} +/***************************************************************************** +** Function btm_proc_smp_cback +** +** Description This function is the SMP callback handler. +** +******************************************************************************/ +UINT8 btm_proc_smp_cback(tSMP_EVT event, BD_ADDR bd_addr, tSMP_EVT_DATA *p_data) +{ + tBTM_SEC_DEV_REC *p_dev_rec = btm_find_dev (bd_addr); + UINT8 res = 0; + + BTM_TRACE_DEBUG ("btm_proc_smp_cback event = %d", event); + + if (p_dev_rec != NULL) + { + switch (event) + { + case SMP_IO_CAP_REQ_EVT: + btm_ble_io_capabilities_req(p_dev_rec, (tBTM_LE_IO_REQ *)&p_data->io_req); + break; + + case SMP_BR_KEYS_REQ_EVT: + btm_ble_br_keys_req(p_dev_rec, (tBTM_LE_IO_REQ *)&p_data->io_req); + break; + + case SMP_PASSKEY_REQ_EVT: + case SMP_PASSKEY_NOTIF_EVT: + case SMP_OOB_REQ_EVT: + case SMP_NC_REQ_EVT: + case SMP_SC_OOB_REQ_EVT: + /* fall through */ + p_dev_rec->sec_flags |= BTM_SEC_LE_AUTHENTICATED; + + case SMP_SEC_REQUEST_EVT: + if (event == SMP_SEC_REQUEST_EVT && btm_cb.pairing_state != BTM_PAIR_STATE_IDLE) + { + BTM_TRACE_DEBUG("%s: Ignoring SMP Security request", __func__); + break; + } + memcpy (btm_cb.pairing_bda, bd_addr, BD_ADDR_LEN); + p_dev_rec->sec_state = BTM_SEC_STATE_AUTHENTICATING; + btm_cb.pairing_flags |= BTM_PAIR_FLAGS_LE_ACTIVE; + /* fall through */ + + case SMP_COMPLT_EVT: + if (btm_cb.api.p_le_callback) + { + /* the callback function implementation may change the IO capability... */ + BTM_TRACE_DEBUG ("btm_cb.api.p_le_callback=0x%x", btm_cb.api.p_le_callback ); + (*btm_cb.api.p_le_callback) (event, bd_addr, (tBTM_LE_EVT_DATA *)p_data); + } + + if (event == SMP_COMPLT_EVT) + { + BTM_TRACE_DEBUG ("evt=SMP_COMPLT_EVT before update sec_level=0x%x sec_flags=0x%x", p_data->cmplt.sec_level , p_dev_rec->sec_flags ); + + res = (p_data->cmplt.reason == SMP_SUCCESS) ? BTM_SUCCESS : BTM_ERR_PROCESSING; + + BTM_TRACE_DEBUG ("after update result=%d sec_level=0x%x sec_flags=0x%x", + res, p_data->cmplt.sec_level , p_dev_rec->sec_flags ); + + if (p_data->cmplt.is_pair_cancel && btm_cb.api.p_bond_cancel_cmpl_callback ) + { + BTM_TRACE_DEBUG ("Pairing Cancel completed"); + (*btm_cb.api.p_bond_cancel_cmpl_callback)(BTM_SUCCESS); + } +#if BTM_BLE_CONFORMANCE_TESTING == TRUE + if (res != BTM_SUCCESS) + { + if (!btm_cb.devcb.no_disc_if_pair_fail && p_data->cmplt.reason != SMP_CONN_TOUT) + { + BTM_TRACE_DEBUG ("Pairing failed - prepare to remove ACL"); + l2cu_start_post_bond_timer(p_dev_rec->ble_hci_handle); + } + else + { + BTM_TRACE_DEBUG ("Pairing failed - Not Removing ACL"); + p_dev_rec->sec_state = BTM_SEC_STATE_IDLE; + } + } +#else + if (res != BTM_SUCCESS && p_data->cmplt.reason != SMP_CONN_TOUT) + { + BTM_TRACE_DEBUG ("Pairing failed - prepare to remove ACL"); + l2cu_start_post_bond_timer(p_dev_rec->ble_hci_handle); + } +#endif + + BTM_TRACE_DEBUG ("btm_cb pairing_state=%x pairing_flags=%x pin_code_len=%x", + btm_cb.pairing_state, + btm_cb.pairing_flags, + btm_cb.pin_code_len ); + BTM_TRACE_DEBUG ("btm_cb.pairing_bda %02x:%02x:%02x:%02x:%02x:%02x", + btm_cb.pairing_bda[0], btm_cb.pairing_bda[1], btm_cb.pairing_bda[2], + btm_cb.pairing_bda[3], btm_cb.pairing_bda[4], btm_cb.pairing_bda[5]); + + /* Reset btm state only if the callback address matches pairing address*/ + if(memcmp(bd_addr, btm_cb.pairing_bda, BD_ADDR_LEN) == 0) + { + memset (btm_cb.pairing_bda, 0xff, BD_ADDR_LEN); + btm_cb.pairing_state = BTM_PAIR_STATE_IDLE; + btm_cb.pairing_flags = 0; + } + + if (res == BTM_SUCCESS) + { + p_dev_rec->sec_state = BTM_SEC_STATE_IDLE; +#if (defined BLE_PRIVACY_SPT && BLE_PRIVACY_SPT == TRUE) + /* add all bonded device into resolving list if IRK is available*/ + btm_ble_resolving_list_load_dev(p_dev_rec); +#endif + } + + btm_sec_dev_rec_cback_event(p_dev_rec, res, TRUE); + } + break; + + default: + BTM_TRACE_DEBUG ("unknown event = %d", event); + break; + + + } + } + else + { + BTM_TRACE_ERROR("btm_proc_smp_cback received for unknown device"); + } + + return 0; +} + + #endif /* SMP_INCLUDED */ + +/******************************************************************************* +** +** Function BTM_BleDataSignature +** +** Description This function is called to sign the data using AES128 CMAC +** algorith. +** +** Parameter bd_addr: target device the data to be signed for. +** p_text: singing data +** len: length of the data to be signed. +** signature: output parameter where data signature is going to +** be stored. +** +** Returns TRUE if signing sucessul, otherwise FALSE. +** +*******************************************************************************/ +BOOLEAN BTM_BleDataSignature (BD_ADDR bd_addr, UINT8 *p_text, UINT16 len, + BLE_SIGNATURE signature) +{ + tBTM_SEC_DEV_REC *p_rec = btm_find_dev (bd_addr); + + BTM_TRACE_DEBUG ("%s", __func__); + BOOLEAN ret = FALSE; + if (p_rec == NULL) + { + BTM_TRACE_ERROR("%s-data signing can not be done from unknown device", __func__); + } + else + { + UINT8 *p_mac = (UINT8 *)signature; + UINT8 *p_buf, *pp; + if ((p_buf = (UINT8 *)GKI_getbuf((UINT16)(len + 4))) != NULL) + { + BTM_TRACE_DEBUG("%s-Start to generate Local CSRK", __func__); + pp = p_buf; + /* prepare plain text */ + if (p_text) + { + memcpy(p_buf, p_text, len); + pp = (p_buf + len); + } + + UINT32_TO_STREAM(pp, p_rec->ble.keys.local_counter); + UINT32_TO_STREAM(p_mac, p_rec->ble.keys.local_counter); + + if ((ret = aes_cipher_msg_auth_code(p_rec->ble.keys.lcsrk, p_buf, (UINT16)(len + 4), + BTM_CMAC_TLEN_SIZE, p_mac)) == TRUE) + { + btm_ble_increment_sign_ctr(bd_addr, TRUE); + } + + BTM_TRACE_DEBUG("%s p_mac = %d", __func__, p_mac); + BTM_TRACE_DEBUG("p_mac[0] = 0x%02x p_mac[1] = 0x%02x p_mac[2] = 0x%02x p_mac[3] = 0x%02x", + *p_mac, *(p_mac + 1), *(p_mac + 2), *(p_mac + 3)); + BTM_TRACE_DEBUG("p_mac[4] = 0x%02x p_mac[5] = 0x%02x p_mac[6] = 0x%02x p_mac[7] = 0x%02x", + *(p_mac + 4), *(p_mac + 5), *(p_mac + 6), *(p_mac + 7)); + GKI_freebuf(p_buf); + } + } + return ret; +} + +/******************************************************************************* +** +** Function BTM_BleVerifySignature +** +** Description This function is called to verify the data signature +** +** Parameter bd_addr: target device the data to be signed for. +** p_orig: original data before signature. +** len: length of the signing data +** counter: counter used when doing data signing +** p_comp: signature to be compared against. + +** Returns TRUE if signature verified correctly; otherwise FALSE. +** +*******************************************************************************/ +BOOLEAN BTM_BleVerifySignature (BD_ADDR bd_addr, UINT8 *p_orig, UINT16 len, UINT32 counter, + UINT8 *p_comp) +{ + BOOLEAN verified = FALSE; +#if SMP_INCLUDED == TRUE + tBTM_SEC_DEV_REC *p_rec = btm_find_dev (bd_addr); + UINT8 p_mac[BTM_CMAC_TLEN_SIZE]; + + if (p_rec == NULL || (p_rec && !(p_rec->ble.key_type & BTM_LE_KEY_PCSRK))) + { + BTM_TRACE_ERROR("can not verify signature for unknown device"); + } + else if (counter < p_rec->ble.keys.counter) + { + BTM_TRACE_ERROR("signature received with out dated sign counter"); + } + else if (p_orig == NULL) + { + BTM_TRACE_ERROR("No signature to verify"); + } + else + { + BTM_TRACE_DEBUG ("%s rcv_cnt=%d >= expected_cnt=%d", __func__, counter, + p_rec->ble.keys.counter); + + if (aes_cipher_msg_auth_code(p_rec->ble.keys.pcsrk, p_orig, len, BTM_CMAC_TLEN_SIZE, p_mac)) + { + if (memcmp(p_mac, p_comp, BTM_CMAC_TLEN_SIZE) == 0) + { + btm_ble_increment_sign_ctr(bd_addr, FALSE); + verified = TRUE; + } + } + } +#endif /* SMP_INCLUDED */ + return verified; +} + +/******************************************************************************* +** +** Function BTM_GetLeSecurityState +** +** Description This function is called to get security mode 1 flags and +** encryption key size for LE peer. +** +** Returns BOOLEAN TRUE if LE device is found, FALSE otherwise. +** +*******************************************************************************/ +BOOLEAN BTM_GetLeSecurityState (BD_ADDR bd_addr, UINT8 *p_le_dev_sec_flags, UINT8 *p_le_key_size) +{ +#if (BLE_INCLUDED == TRUE) + tBTM_SEC_DEV_REC *p_dev_rec; + UINT16 dev_rec_sec_flags; +#endif + + *p_le_dev_sec_flags = 0; + *p_le_key_size = 0; + +#if (BLE_INCLUDED == TRUE && SMP_INCLUDED == TRUE) + if ((p_dev_rec = btm_find_dev (bd_addr)) == NULL) + { + BTM_TRACE_ERROR ("%s fails", __func__); + return (FALSE); + } + + if (p_dev_rec->ble_hci_handle == BTM_SEC_INVALID_HANDLE) + { + BTM_TRACE_ERROR ("%s-this is not LE device", __func__); + return (FALSE); + } + + dev_rec_sec_flags = p_dev_rec->sec_flags; + + if (dev_rec_sec_flags & BTM_SEC_LE_ENCRYPTED) + { + /* link is encrypted with LTK or STK */ + *p_le_key_size = p_dev_rec->enc_key_size; + *p_le_dev_sec_flags |= BTM_SEC_LE_LINK_ENCRYPTED; + + *p_le_dev_sec_flags |= (dev_rec_sec_flags & BTM_SEC_LE_AUTHENTICATED) + ? BTM_SEC_LE_LINK_PAIRED_WITH_MITM /* set auth LTK flag */ + : BTM_SEC_LE_LINK_PAIRED_WITHOUT_MITM; /* set unauth LTK flag */ + } + else if (p_dev_rec->ble.key_type & BTM_LE_KEY_PENC) + { + /* link is unencrypted, still LTK is available */ + *p_le_key_size = p_dev_rec->ble.keys.key_size; + + *p_le_dev_sec_flags |= (dev_rec_sec_flags & BTM_SEC_LE_LINK_KEY_AUTHED) + ? BTM_SEC_LE_LINK_PAIRED_WITH_MITM /* set auth LTK flag */ + : BTM_SEC_LE_LINK_PAIRED_WITHOUT_MITM; /* set unauth LTK flag */ + } + + BTM_TRACE_DEBUG ("%s - le_dev_sec_flags: 0x%02x, le_key_size: %d", + __func__, *p_le_dev_sec_flags, *p_le_key_size); + + return TRUE; +#else + return FALSE; +#endif +} + +/******************************************************************************* +** +** Function BTM_BleSecurityProcedureIsRunning +** +** Description This function indicates if LE security procedure is +** currently running with the peer. +** +** Returns BOOLEAN TRUE if security procedure is running, FALSE otherwise. +** +*******************************************************************************/ +BOOLEAN BTM_BleSecurityProcedureIsRunning(BD_ADDR bd_addr) +{ +#if (BLE_INCLUDED == TRUE) + tBTM_SEC_DEV_REC *p_dev_rec = btm_find_dev (bd_addr); + + if (p_dev_rec == NULL) + { + BTM_TRACE_ERROR ("%s device with BDA: %08x%04x is not found", + __func__, (bd_addr[0]<<24)+(bd_addr[1]<<16)+(bd_addr[2]<<8)+bd_addr[3], + (bd_addr[4]<<8)+bd_addr[5]); + return FALSE; + } + + return (p_dev_rec->sec_state == BTM_SEC_STATE_ENCRYPTING || + p_dev_rec->sec_state == BTM_SEC_STATE_AUTHENTICATING); +#else + return FALSE; +#endif +} + +/******************************************************************************* +** +** Function BTM_BleGetSupportedKeySize +** +** Description This function gets the maximum encryption key size in bytes +** the local device can suport. +** record. +** +** Returns the key size or 0 if the size can't be retrieved. +** +*******************************************************************************/ +extern UINT8 BTM_BleGetSupportedKeySize (BD_ADDR bd_addr) +{ +#ifndef L2CAP_LE_COC_INCLUDED +#define L2CAP_LE_COC_INCLUDED FALSE +#endif +#if ((BLE_INCLUDED == TRUE) && (L2CAP_LE_COC_INCLUDED == TRUE)) + tBTM_SEC_DEV_REC *p_dev_rec = btm_find_dev (bd_addr); + tBTM_LE_IO_REQ dev_io_cfg; + UINT8 callback_rc; + + if (!p_dev_rec) + { + BTM_TRACE_ERROR ("%s device with BDA: %08x%04x is not found", + __func__,(bd_addr[0]<<24)+(bd_addr[1]<<16)+(bd_addr[2]<<8)+bd_addr[3], + (bd_addr[4]<<8)+bd_addr[5]); + return 0; + } + + if (btm_cb.api.p_le_callback == NULL) + { + BTM_TRACE_ERROR ("%s can't access supported key size",__func__); + return 0; + } + + callback_rc = (*btm_cb.api.p_le_callback) (BTM_LE_IO_REQ_EVT, p_dev_rec->bd_addr, + (tBTM_LE_EVT_DATA *) &dev_io_cfg); + + if (callback_rc != BTM_SUCCESS) + { + BTM_TRACE_ERROR ("%s can't access supported key size",__func__); + return 0; + } + + BTM_TRACE_DEBUG ("%s device supports key size = %d", __func__, dev_io_cfg.max_key_size); + return (dev_io_cfg.max_key_size); +#else + return 0; +#endif +} + +/******************************************************************************* +** Utility functions for LE device IR/ER generation +*******************************************************************************/ +/******************************************************************************* +** +** Function btm_notify_new_key +** +** Description This function is to notify application new keys have been +** generated. +** +** Returns void +** +*******************************************************************************/ +static void btm_notify_new_key(UINT8 key_type) +{ + tBTM_BLE_LOCAL_KEYS *p_locak_keys = NULL; + + BTM_TRACE_DEBUG ("btm_notify_new_key key_type=%d", key_type); + + if (btm_cb.api.p_le_key_callback) + { + switch (key_type) + { + case BTM_BLE_KEY_TYPE_ID: + BTM_TRACE_DEBUG ("BTM_BLE_KEY_TYPE_ID"); + p_locak_keys = (tBTM_BLE_LOCAL_KEYS *)&btm_cb.devcb.id_keys; + break; + + case BTM_BLE_KEY_TYPE_ER: + BTM_TRACE_DEBUG ("BTM_BLE_KEY_TYPE_ER"); + p_locak_keys = (tBTM_BLE_LOCAL_KEYS *)&btm_cb.devcb.ble_encryption_key_value; + break; + + default: + BTM_TRACE_ERROR("unknown key type: %d", key_type); + break; + } + if (p_locak_keys != NULL) + (*btm_cb.api.p_le_key_callback) (key_type, p_locak_keys); + } +} + +/******************************************************************************* +** +** Function btm_ble_process_er2 +** +** Description This function is called when ER is generated, store it in +** local control block. +** +** Returns void +** +*******************************************************************************/ +static void btm_ble_process_er2(tBTM_RAND_ENC *p) +{ + BTM_TRACE_DEBUG ("btm_ble_process_er2"); + + if (p &&p->opcode == HCI_BLE_RAND) + { + memcpy(&btm_cb.devcb.ble_encryption_key_value[8], p->param_buf, BT_OCTET8_LEN); + btm_notify_new_key(BTM_BLE_KEY_TYPE_ER); + } + else + { + BTM_TRACE_ERROR("Generating ER2 exception."); + memset(&btm_cb.devcb.ble_encryption_key_value, 0, sizeof(BT_OCTET16)); + } +} + +/******************************************************************************* +** +** Function btm_ble_process_er +** +** Description This function is called when ER is generated, store it in +** local control block. +** +** Returns void +** +*******************************************************************************/ +static void btm_ble_process_er(tBTM_RAND_ENC *p) +{ + BTM_TRACE_DEBUG ("btm_ble_process_er"); + + if (p &&p->opcode == HCI_BLE_RAND) + { + memcpy(&btm_cb.devcb.ble_encryption_key_value[0], p->param_buf, BT_OCTET8_LEN); + + if (!btsnd_hcic_ble_rand((void *)btm_ble_process_er2)) + { + memset(&btm_cb.devcb.ble_encryption_key_value, 0, sizeof(BT_OCTET16)); + BTM_TRACE_ERROR("Generating ER2 failed."); + } + } + else + { + BTM_TRACE_ERROR("Generating ER1 exception."); + } +} + +/******************************************************************************* +** +** Function btm_ble_process_irk +** +** Description This function is called when IRK is generated, store it in +** local control block. +** +** Returns void +** +*******************************************************************************/ +static void btm_ble_process_irk(tSMP_ENC *p) +{ + BTM_TRACE_DEBUG ("btm_ble_process_irk"); + if (p &&p->opcode == HCI_BLE_ENCRYPT) + { + memcpy(btm_cb.devcb.id_keys.irk, p->param_buf, BT_OCTET16_LEN); + btm_notify_new_key(BTM_BLE_KEY_TYPE_ID); + +#if BLE_PRIVACY_SPT == TRUE + /* if privacy is enabled, new RPA should be calculated */ + if (btm_cb.ble_ctr_cb.privacy_mode != BTM_PRIVACY_NONE) + { + btm_gen_resolvable_private_addr((void *)btm_gen_resolve_paddr_low); + } +#endif + } + else + { + BTM_TRACE_ERROR("Generating IRK exception."); + } + + /* proceed generate ER */ + if (!btsnd_hcic_ble_rand((void *)btm_ble_process_er)) + { + BTM_TRACE_ERROR("Generating ER failed."); + } +} + +/******************************************************************************* +** +** Function btm_ble_process_dhk +** +** Description This function is called when DHK is calculated, store it in +** local control block, and proceed to generate ER, a 128-bits +** random number. +** +** Returns void +** +*******************************************************************************/ +static void btm_ble_process_dhk(tSMP_ENC *p) +{ +#if SMP_INCLUDED == TRUE + UINT8 btm_ble_irk_pt = 0x01; + tSMP_ENC output; + + BTM_TRACE_DEBUG ("btm_ble_process_dhk"); + + if (p && p->opcode == HCI_BLE_ENCRYPT) + { + memcpy(btm_cb.devcb.id_keys.dhk, p->param_buf, BT_OCTET16_LEN); + BTM_TRACE_DEBUG("BLE DHK generated."); + + /* IRK = D1(IR, 1) */ + if (!SMP_Encrypt(btm_cb.devcb.id_keys.ir, BT_OCTET16_LEN, &btm_ble_irk_pt, + 1, &output)) + { + /* reset all identity root related key */ + memset(&btm_cb.devcb.id_keys, 0, sizeof(tBTM_BLE_LOCAL_ID_KEYS)); + } + else + { + btm_ble_process_irk(&output); + } + } + else + { + /* reset all identity root related key */ + memset(&btm_cb.devcb.id_keys, 0, sizeof(tBTM_BLE_LOCAL_ID_KEYS)); + } +#endif +} + +/******************************************************************************* +** +** Function btm_ble_process_ir2 +** +** Description This function is called when IR is generated, proceed to calculate +** DHK = Eir({0x03, 0, 0 ...}) +** +** +** Returns void +** +*******************************************************************************/ +static void btm_ble_process_ir2(tBTM_RAND_ENC *p) +{ +#if SMP_INCLUDED == TRUE + UINT8 btm_ble_dhk_pt = 0x03; + tSMP_ENC output; + + BTM_TRACE_DEBUG ("btm_ble_process_ir2"); + + if (p && p->opcode == HCI_BLE_RAND) + { + /* remembering in control block */ + memcpy(&btm_cb.devcb.id_keys.ir[8], p->param_buf, BT_OCTET8_LEN); + /* generate DHK= Eir({0x03, 0x00, 0x00 ...}) */ + + + SMP_Encrypt(btm_cb.devcb.id_keys.ir, BT_OCTET16_LEN, &btm_ble_dhk_pt, + 1, &output); + btm_ble_process_dhk(&output); + + BTM_TRACE_DEBUG("BLE IR generated."); + } + else + { + memset(&btm_cb.devcb.id_keys, 0, sizeof(tBTM_BLE_LOCAL_ID_KEYS)); + } +#endif +} + +/******************************************************************************* +** +** Function btm_ble_process_ir +** +** Description This function is called when IR is generated, proceed to calculate +** DHK = Eir({0x02, 0, 0 ...}) +** +** +** Returns void +** +*******************************************************************************/ +static void btm_ble_process_ir(tBTM_RAND_ENC *p) +{ + BTM_TRACE_DEBUG ("btm_ble_process_ir"); + + if (p && p->opcode == HCI_BLE_RAND) + { + /* remembering in control block */ + memcpy(btm_cb.devcb.id_keys.ir, p->param_buf, BT_OCTET8_LEN); + + if (!btsnd_hcic_ble_rand((void *)btm_ble_process_ir2)) + { + BTM_TRACE_ERROR("Generating IR2 failed."); + memset(&btm_cb.devcb.id_keys, 0, sizeof(tBTM_BLE_LOCAL_ID_KEYS)); + } + } +} + +/******************************************************************************* +** +** Function btm_ble_reset_id +** +** Description This function is called to reset LE device identity. +** +** Returns void +** +*******************************************************************************/ +void btm_ble_reset_id( void ) +{ + BTM_TRACE_DEBUG ("btm_ble_reset_id"); + + /* regenrate Identity Root*/ + if (!btsnd_hcic_ble_rand((void *)btm_ble_process_ir)) + { + BTM_TRACE_DEBUG("Generating IR failed."); + } +} + + #if BTM_BLE_CONFORMANCE_TESTING == TRUE +/******************************************************************************* +** +** Function btm_ble_set_no_disc_if_pair_fail +** +** Description This function indicates that whether no disconnect of the ACL +** should be used if pairing failed +** +** Returns void +** +*******************************************************************************/ +void btm_ble_set_no_disc_if_pair_fail(BOOLEAN disable_disc ) +{ + BTM_TRACE_DEBUG ("btm_ble_set_disc_enable_if_pair_fail disable_disc=%d", disable_disc); + btm_cb.devcb.no_disc_if_pair_fail = disable_disc; +} + +/******************************************************************************* +** +** Function btm_ble_set_test_mac_value +** +** Description This function set test MAC value +** +** Returns void +** +*******************************************************************************/ +void btm_ble_set_test_mac_value(BOOLEAN enable, UINT8 *p_test_mac_val ) +{ + BTM_TRACE_DEBUG ("btm_ble_set_test_mac_value enable=%d", enable); + btm_cb.devcb.enable_test_mac_val = enable; + memcpy(btm_cb.devcb.test_mac, p_test_mac_val, BT_OCTET8_LEN); +} + +/******************************************************************************* +** +** Function btm_ble_set_test_local_sign_cntr_value +** +** Description This function set test local sign counter value +** +** Returns void +** +*******************************************************************************/ +void btm_ble_set_test_local_sign_cntr_value(BOOLEAN enable, UINT32 test_local_sign_cntr ) +{ + BTM_TRACE_DEBUG ("btm_ble_set_test_local_sign_cntr_value enable=%d local_sign_cntr=%d", + enable, test_local_sign_cntr); + btm_cb.devcb.enable_test_local_sign_cntr = enable; + btm_cb.devcb.test_local_sign_cntr = test_local_sign_cntr; +} + +/******************************************************************************* +** +** Function btm_set_random_address +** +** Description This function set a random address to local controller. +** +** Returns void +** +*******************************************************************************/ +void btm_set_random_address(BD_ADDR random_bda) +{ + tBTM_LE_RANDOM_CB *p_cb = &btm_cb.ble_ctr_cb.addr_mgnt_cb; + BOOLEAN adv_mode = btm_cb.ble_ctr_cb.inq_var.adv_mode ; + + BTM_TRACE_DEBUG ("btm_set_random_address"); + + if (adv_mode == BTM_BLE_ADV_ENABLE) + btsnd_hcic_ble_set_adv_enable (BTM_BLE_ADV_DISABLE); + + memcpy(p_cb->private_addr, random_bda, BD_ADDR_LEN); + btsnd_hcic_ble_set_random_addr(p_cb->private_addr); + + if (adv_mode == BTM_BLE_ADV_ENABLE) + btsnd_hcic_ble_set_adv_enable (BTM_BLE_ADV_ENABLE); + + +} + +/******************************************************************************* +** +** Function btm_ble_set_keep_rfu_in_auth_req +** +** Description This function indicates if RFU bits have to be kept as is +** (by default they have to be set to 0 by the sender). +** +** Returns void +** +*******************************************************************************/ +void btm_ble_set_keep_rfu_in_auth_req(BOOLEAN keep_rfu) +{ + BTM_TRACE_DEBUG ("btm_ble_set_keep_rfu_in_auth_req keep_rfus=%d", keep_rfu); + btm_cb.devcb.keep_rfu_in_auth_req = keep_rfu; +} + +#endif /* BTM_BLE_CONFORMANCE_TESTING */ + +#endif /* BLE_INCLUDED */ diff --git a/components/bt/bluedroid/stack/btm/btm_ble_addr.c b/components/bt/bluedroid/stack/btm/btm_ble_addr.c new file mode 100755 index 0000000000..70543c3b44 --- /dev/null +++ b/components/bt/bluedroid/stack/btm/btm_ble_addr.c @@ -0,0 +1,634 @@ +/****************************************************************************** + * + * Copyright (C) 1999-2012 Broadcom Corporation + * + * 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 functions for BLE address management. + * + ******************************************************************************/ + +#include + +#include "bt_types.h" +#include "hcimsgs.h" +#include "btu.h" +#include "btm_int.h" +#include "gap_api.h" +#include "controller.h" + +#if (defined BLE_INCLUDED && BLE_INCLUDED == TRUE) +#include "btm_ble_int.h" +#include "smp_api.h" + + +/******************************************************************************* +** +** Function btm_gen_resolve_paddr_cmpl +** +** Description This is callback functioin when resolvable private address +** generation is complete. +** +** Returns void +** +*******************************************************************************/ +static void btm_gen_resolve_paddr_cmpl(tSMP_ENC *p) +{ + tBTM_LE_RANDOM_CB *p_cb = &btm_cb.ble_ctr_cb.addr_mgnt_cb; + BTM_TRACE_EVENT ("btm_gen_resolve_paddr_cmpl"); + + if (p) + { + /* set hash to be LSB of rpAddress */ + p_cb->private_addr[5] = p->param_buf[0]; + p_cb->private_addr[4] = p->param_buf[1]; + p_cb->private_addr[3] = p->param_buf[2]; + /* set it to controller */ + btsnd_hcic_ble_set_random_addr(p_cb->private_addr); + + p_cb->own_addr_type = BLE_ADDR_RANDOM; + + /* start a periodical timer to refresh random addr */ + btu_stop_timer_oneshot(&p_cb->raddr_timer_ent); +#if (BTM_BLE_CONFORMANCE_TESTING == TRUE) + btu_start_timer_oneshot(&p_cb->raddr_timer_ent, BTU_TTYPE_BLE_RANDOM_ADDR, + btm_cb.ble_ctr_cb.rpa_tout); +#else + btu_start_timer_oneshot(&p_cb->raddr_timer_ent, BTU_TTYPE_BLE_RANDOM_ADDR, + BTM_BLE_PRIVATE_ADDR_INT); +#endif + } + else + { + /* random address set failure */ + BTM_TRACE_DEBUG("set random address failed"); + } +} +/******************************************************************************* +** +** Function btm_gen_resolve_paddr_low +** +** Description This function is called when random address has generate the +** random number base for low 3 byte bd address. +** +** Returns void +** +*******************************************************************************/ +void btm_gen_resolve_paddr_low(tBTM_RAND_ENC *p) +{ +#if (BLE_INCLUDED == TRUE && SMP_INCLUDED == TRUE) + tBTM_LE_RANDOM_CB *p_cb = &btm_cb.ble_ctr_cb.addr_mgnt_cb; + tSMP_ENC output; + + BTM_TRACE_EVENT ("btm_gen_resolve_paddr_low"); + if (p) + { + p->param_buf[2] &= (~BLE_RESOLVE_ADDR_MASK); + p->param_buf[2] |= BLE_RESOLVE_ADDR_MSB; + + p_cb->private_addr[2] = p->param_buf[0]; + p_cb->private_addr[1] = p->param_buf[1]; + p_cb->private_addr[0] = p->param_buf[2]; + + /* encrypt with ur IRK */ + if (!SMP_Encrypt(btm_cb.devcb.id_keys.irk, BT_OCTET16_LEN, p->param_buf, 3, &output)) + { + btm_gen_resolve_paddr_cmpl(NULL); + } + else + { + btm_gen_resolve_paddr_cmpl(&output); + } + } +#endif +} +/******************************************************************************* +** +** Function btm_gen_resolvable_private_addr +** +** Description This function generate a resolvable private address. +** +** Returns void +** +*******************************************************************************/ +void btm_gen_resolvable_private_addr (void *p_cmd_cplt_cback) +{ + BTM_TRACE_EVENT ("btm_gen_resolvable_private_addr"); + /* generate 3B rand as BD LSB, SRK with it, get BD MSB */ + if (!btsnd_hcic_ble_rand((void *)p_cmd_cplt_cback)) + btm_gen_resolve_paddr_cmpl(NULL); +} +/******************************************************************************* +** +** Function btm_gen_non_resolve_paddr_cmpl +** +** Description This is the callback function when non-resolvable private +** function is generated and write to controller. +** +** Returns void +** +*******************************************************************************/ +static void btm_gen_non_resolve_paddr_cmpl(tBTM_RAND_ENC *p) +{ + tBTM_LE_RANDOM_CB *p_cb = &btm_cb.ble_ctr_cb.addr_mgnt_cb; + tBTM_BLE_ADDR_CBACK *p_cback = p_cb->p_generate_cback; + void *p_data = p_cb->p; + UINT8 *pp; + BD_ADDR static_random; + + BTM_TRACE_EVENT ("btm_gen_non_resolve_paddr_cmpl"); + + p_cb->p_generate_cback = NULL; + if (p) + { + + pp = p->param_buf; + STREAM_TO_BDADDR(static_random, pp); + /* mask off the 2 MSB */ + static_random[0] &= BLE_STATIC_PRIVATE_MSB_MASK; + + /* report complete */ + if (p_cback) + (* p_cback)(static_random, p_data); + } + else + { + BTM_TRACE_DEBUG("btm_gen_non_resolvable_private_addr failed"); + if (p_cback) + (* p_cback)(NULL, p_data); + } +} +/******************************************************************************* +** +** Function btm_gen_non_resolvable_private_addr +** +** Description This function generate a non-resolvable private address. +** +** +** Returns void +** +*******************************************************************************/ +void btm_gen_non_resolvable_private_addr (tBTM_BLE_ADDR_CBACK *p_cback, void *p) +{ + tBTM_LE_RANDOM_CB *p_mgnt_cb = &btm_cb.ble_ctr_cb.addr_mgnt_cb; + + BTM_TRACE_EVENT ("btm_gen_non_resolvable_private_addr"); + + if (p_mgnt_cb->p_generate_cback != NULL) + return; + + p_mgnt_cb->p_generate_cback = p_cback; + p_mgnt_cb->p = p; + if (!btsnd_hcic_ble_rand((void *)btm_gen_non_resolve_paddr_cmpl)) + { + btm_gen_non_resolve_paddr_cmpl(NULL); + } + +} + +#if SMP_INCLUDED == TRUE +/******************************************************************************* +** Utility functions for Random address resolving +*******************************************************************************/ +/******************************************************************************* +** +** Function btm_ble_resolve_address_cmpl +** +** Description This function sends the random address resolving complete +** callback. +** +** Returns None. +** +*******************************************************************************/ +static void btm_ble_resolve_address_cmpl(void) +{ + tBTM_LE_RANDOM_CB *p_mgnt_cb = &btm_cb.ble_ctr_cb.addr_mgnt_cb; + tBTM_SEC_DEV_REC *p_dev_rec = NULL; + + BTM_TRACE_EVENT ("btm_ble_resolve_address_cmpl p_mgnt_cb->index = %d", p_mgnt_cb->index); + + if (p_mgnt_cb->index < BTM_SEC_MAX_DEVICE_RECORDS) + { + p_dev_rec = &btm_cb.sec_dev_rec[p_mgnt_cb->index]; + } + + p_mgnt_cb->busy = FALSE; + + (* p_mgnt_cb->p_resolve_cback)(p_dev_rec, p_mgnt_cb->p); +} +/******************************************************************************* +** +** Function btm_ble_proc_resolve_x +** +** Description This function compares the X with random address 3 MSO bytes +** to find a match, if not match, continue for next record. +** +** Returns None. +** +*******************************************************************************/ +static BOOLEAN btm_ble_proc_resolve_x(tSMP_ENC *p) +{ + tBTM_LE_RANDOM_CB *p_mgnt_cb = &btm_cb.ble_ctr_cb.addr_mgnt_cb; + UINT8 comp[3]; + BTM_TRACE_EVENT ("btm_ble_proc_resolve_x"); + /* compare the hash with 3 LSB of bd address */ + comp[0] = p_mgnt_cb->random_bda[5]; + comp[1] = p_mgnt_cb->random_bda[4]; + comp[2] = p_mgnt_cb->random_bda[3]; + + if (p) + { + if (!memcmp(p->param_buf, &comp[0], 3)) + { + /* match is found */ + BTM_TRACE_EVENT ("match is found"); + btm_ble_resolve_address_cmpl(); + return TRUE; + } + } + return FALSE; +} + +/******************************************************************************* +** +** Function btm_ble_init_pseudo_addr +** +** Description This function is used to initialize pseudo address. +** If pseudo address is not available, use dummy address +** +** Returns TRUE is updated; FALSE otherwise. +** +*******************************************************************************/ +BOOLEAN btm_ble_init_pseudo_addr (tBTM_SEC_DEV_REC *p_dev_rec, BD_ADDR new_pseudo_addr) +{ + BD_ADDR dummy_bda = {0}; + + if (memcmp(p_dev_rec->ble.pseudo_addr, dummy_bda, BD_ADDR_LEN) == 0) + { + memcpy(p_dev_rec->ble.pseudo_addr, new_pseudo_addr, BD_ADDR_LEN); + return TRUE; + } + + return FALSE; +} + +/******************************************************************************* +** +** Function btm_ble_addr_resolvable +** +** Description This function checks if a RPA is resolvable by the device key. +** +** Returns TRUE is resolvable; FALSE otherwise. +** +*******************************************************************************/ +BOOLEAN btm_ble_addr_resolvable (BD_ADDR rpa, tBTM_SEC_DEV_REC *p_dev_rec) +{ + BOOLEAN rt = FALSE; + + if (!BTM_BLE_IS_RESOLVE_BDA(rpa)) + return rt; + + UINT8 rand[3]; + tSMP_ENC output; + if ((p_dev_rec->device_type & BT_DEVICE_TYPE_BLE) && + (p_dev_rec->ble.key_type & BTM_LE_KEY_PID)) + { + BTM_TRACE_DEBUG("%s try to resolve", __func__); + /* use the 3 MSB of bd address as prand */ + rand[0] = rpa[2]; + rand[1] = rpa[1]; + rand[2] = rpa[0]; + + /* generate X = E irk(R0, R1, R2) and R is random address 3 LSO */ + SMP_Encrypt(p_dev_rec->ble.keys.irk, BT_OCTET16_LEN, + &rand[0], 3, &output); + + rand[0] = rpa[5]; + rand[1] = rpa[4]; + rand[2] = rpa[3]; + + if (!memcmp(output.param_buf, &rand[0], 3)) + { + btm_ble_init_pseudo_addr (p_dev_rec, rpa); + rt = TRUE; + } + } + return rt; +} + +/******************************************************************************* +** +** Function btm_ble_match_random_bda +** +** Description This function match the random address to the appointed device +** record, starting from calculating IRK. If record index exceed +** the maximum record number, matching failed and send callback. +** +** Returns None. +** +*******************************************************************************/ +static BOOLEAN btm_ble_match_random_bda(UINT16 rec_index) +{ +#if (BLE_INCLUDED == TRUE && SMP_INCLUDED == TRUE) + /* use the 3 MSB of bd address as prand */ + + tBTM_LE_RANDOM_CB *p_mgnt_cb = &btm_cb.ble_ctr_cb.addr_mgnt_cb; + UINT8 rand[3]; + rand[0] = p_mgnt_cb->random_bda[2]; + rand[1] = p_mgnt_cb->random_bda[1]; + rand[2] = p_mgnt_cb->random_bda[0]; + + BTM_TRACE_EVENT("%s rec_index = %d", __func__, rec_index); + + if (rec_index < BTM_SEC_MAX_DEVICE_RECORDS) + { + tSMP_ENC output; + tBTM_SEC_DEV_REC *p_dev_rec; + p_dev_rec = &btm_cb.sec_dev_rec[rec_index]; + + BTM_TRACE_DEBUG("sec_flags = %02x device_type = %d", p_dev_rec->sec_flags, + p_dev_rec->device_type); + + if ((p_dev_rec->device_type & BT_DEVICE_TYPE_BLE) && + (p_dev_rec->ble.key_type & BTM_LE_KEY_PID)) + { + /* generate X = E irk(R0, R1, R2) and R is random address 3 LSO */ + SMP_Encrypt(p_dev_rec->ble.keys.irk, BT_OCTET16_LEN, + &rand[0], 3, &output); + return btm_ble_proc_resolve_x(&output); + } + else + { + // not completed + return FALSE; + } + } + else /* no match found */ + { + btm_ble_resolve_address_cmpl(); + return TRUE; + } +#endif +} + +/******************************************************************************* +** +** Function btm_ble_resolve_random_addr +** +** Description This function is called to resolve a random address. +** +** Returns pointer to the security record of the device whom a random +** address is matched to. +** +*******************************************************************************/ +void btm_ble_resolve_random_addr(BD_ADDR random_bda, tBTM_BLE_RESOLVE_CBACK * p_cback, void *p) +{ + tBTM_LE_RANDOM_CB *p_mgnt_cb = &btm_cb.ble_ctr_cb.addr_mgnt_cb; + + BTM_TRACE_EVENT ("btm_ble_resolve_random_addr"); + if ( !p_mgnt_cb->busy) + { + p_mgnt_cb->p = p; + p_mgnt_cb->busy = TRUE; + p_mgnt_cb->index = 0; + p_mgnt_cb->p_resolve_cback = p_cback; + memcpy(p_mgnt_cb->random_bda, random_bda, BD_ADDR_LEN); + /* start to resolve random address */ + /* check for next security record */ + while (TRUE) + { + if (btm_ble_match_random_bda(p_mgnt_cb->index)) + { + /* atch found or went through the list */ + break; + } + p_mgnt_cb->index ++; + } + } + else + (*p_cback)(NULL, p); +} +#endif + +/******************************************************************************* +** address mapping between pseudo address and real connection address +*******************************************************************************/ +/******************************************************************************* +** +** Function btm_find_dev_by_identity_addr +** +** Description find the security record whose LE static address is matching +** +*******************************************************************************/ +tBTM_SEC_DEV_REC* btm_find_dev_by_identity_addr(BD_ADDR bd_addr, UINT8 addr_type) +{ +#if BLE_PRIVACY_SPT == TRUE + UINT8 i; + tBTM_SEC_DEV_REC *p_dev_rec = &btm_cb.sec_dev_rec[0]; + + for (i = 0; i < BTM_SEC_MAX_DEVICE_RECORDS; i ++, p_dev_rec ++) + { + if ((p_dev_rec->sec_flags & BTM_SEC_IN_USE) && + memcmp(p_dev_rec->ble.static_addr, bd_addr, BD_ADDR_LEN) == 0) + { + if ((p_dev_rec->ble.static_addr_type & (~BLE_ADDR_TYPE_ID_BIT)) != + (addr_type & (~BLE_ADDR_TYPE_ID_BIT))) + { + BTM_TRACE_WARNING("%s find pseudo->random match with diff addr type: %d vs %d", + __func__, p_dev_rec->ble.static_addr_type, addr_type); + } + + /* found the match */ + return p_dev_rec; + } + } +#endif + + return NULL; +} + +/******************************************************************************* +** +** Function btm_identity_addr_to_random_pseudo +** +** Description This function map a static BD address to a pseudo random address +** in security database. +** +*******************************************************************************/ +BOOLEAN btm_identity_addr_to_random_pseudo(BD_ADDR bd_addr, UINT8 *p_addr_type, BOOLEAN refresh) +{ +#if BLE_PRIVACY_SPT == TRUE + tBTM_SEC_DEV_REC *p_dev_rec = btm_find_dev_by_identity_addr(bd_addr, *p_addr_type); + + BTM_TRACE_EVENT ("%s", __func__); + /* evt reported on static address, map static address to random pseudo */ + if (p_dev_rec != NULL) + { + /* if RPA offloading is supported, or 4.2 controller, do RPA refresh */ + if (refresh && controller_get_interface()->get_ble_resolving_list_max_size() != 0) + btm_ble_read_resolving_list_entry(p_dev_rec); + + /* assign the original address to be the current report address */ + if (!btm_ble_init_pseudo_addr (p_dev_rec, bd_addr)) + memcpy(bd_addr, p_dev_rec->ble.pseudo_addr, BD_ADDR_LEN); + + *p_addr_type = p_dev_rec->ble.ble_addr_type; + return TRUE; + } +#endif + return FALSE; +} + +/******************************************************************************* +** +** Function btm_random_pseudo_to_identity_addr +** +** Description This function map a random pseudo address to a public address +** random_pseudo is input and output parameter +** +*******************************************************************************/ +BOOLEAN btm_random_pseudo_to_identity_addr(BD_ADDR random_pseudo, UINT8 *p_static_addr_type) +{ +#if BLE_PRIVACY_SPT == TRUE + tBTM_SEC_DEV_REC *p_dev_rec = btm_find_dev (random_pseudo); + + if (p_dev_rec != NULL) + { + if (p_dev_rec->ble.in_controller_list & BTM_RESOLVING_LIST_BIT) + { + * p_static_addr_type = p_dev_rec->ble.static_addr_type; + memcpy(random_pseudo, p_dev_rec->ble.static_addr, BD_ADDR_LEN); + if (controller_get_interface()->supports_ble_privacy()) + *p_static_addr_type |= BLE_ADDR_TYPE_ID_BIT; + return TRUE; + } + } +#endif + return FALSE; +} + +/******************************************************************************* +** +** 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 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 +} +#endif + + diff --git a/components/bt/bluedroid/stack/btm/btm_ble_adv_filter.c b/components/bt/bluedroid/stack/btm/btm_ble_adv_filter.c new file mode 100755 index 0000000000..933bd3d315 --- /dev/null +++ b/components/bt/bluedroid/stack/btm/btm_ble_adv_filter.c @@ -0,0 +1,1345 @@ +/****************************************************************************** + * + * Copyright (C) 2014 Broadcom Corporation + * + * 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. + * + ******************************************************************************/ + +//#define LOG_TAG "bt_btm_ble" + +#include +#include "bt_target.h" + +#if (BLE_INCLUDED == TRUE) +#include "bt_types.h" +#include "hcimsgs.h" +#include "btu.h" +#include "btm_int.h" +//#include "bt_utils.h" +#include "hcidefs.h" +#include "btm_ble_api.h" +#include "controller.h" + +#define BTM_BLE_ADV_FILT_META_HDR_LENGTH 3 +#define BTM_BLE_ADV_FILT_FEAT_SELN_LEN 13 +#define BTM_BLE_ADV_FILT_TRACK_NUM 2 + +#define BTM_BLE_PF_SELECT_NONE 0 + +/* BLE meta vsc header: 1 bytes of sub_code, 1 byte of PCF action */ +#define BTM_BLE_META_HDR_LENGTH 3 +#define BTM_BLE_PF_FEAT_SEL_LEN 18 +#define BTM_BLE_PCF_ENABLE_LEN 2 + +#define BTM_BLE_META_ADDR_LEN 7 +#define BTM_BLE_META_UUID_LEN 40 + +#define BTM_BLE_PF_BIT_TO_MASK(x) (UINT16)(1 << (x)) + + +tBTM_BLE_ADV_FILTER_CB btm_ble_adv_filt_cb; +tBTM_BLE_VSC_CB cmn_ble_vsc_cb; +static const BD_ADDR na_bda= {0}; + +static UINT8 btm_ble_cs_update_pf_counter(tBTM_BLE_SCAN_COND_OP action, + UINT8 cond_type, tBLE_BD_ADDR *p_bd_addr, UINT8 num_available); + +#define BTM_BLE_SET_SCAN_PF_OPCODE(x, y) (((x)<<4)|y) +#define BTM_BLE_GET_SCAN_PF_SUBCODE(x) ((x) >> 4) +#define BTM_BLE_GET_SCAN_PF_ACTION(x) ((x) & 0x0f) +#define BTM_BLE_INVALID_COUNTER 0xff + + +/* length of each multi adv sub command */ +#define BTM_BLE_ADV_FILTER_ENB_LEN 3 + +/* length of each batch scan command */ +#define BTM_BLE_ADV_FILTER_CLEAR_LEN 3 +#define BTM_BLE_ADV_FILTER_LEN 2 + +#define BTM_BLE_ADV_FILT_CB_EVT_MASK 0xF0 +#define BTM_BLE_ADV_FILT_SUBCODE_MASK 0x0F + +/******************************************************************************* +** +** Function btm_ble_obtain_vsc_details +** +** Description This function obtains the VSC details +** +** Parameters +** +** Returns status +** +*******************************************************************************/ +tBTM_STATUS btm_ble_obtain_vsc_details() +{ + tBTM_STATUS st = BTM_SUCCESS; + +#if BLE_VND_INCLUDED == TRUE + BTM_BleGetVendorCapabilities(&cmn_ble_vsc_cb); + if (0 == cmn_ble_vsc_cb.max_filter) + { + st = BTM_MODE_UNSUPPORTED; + return st; + } +#else + cmn_ble_vsc_cb.max_filter = BTM_BLE_MAX_FILTER_COUNTER; +#endif + return st; +} + +/******************************************************************************* +** +** Function btm_ble_advfilt_enq_op_q +** +** Description enqueue an adv filter operation in q to check command complete +** status +** +** Returns void +** +*******************************************************************************/ +void btm_ble_advfilt_enq_op_q(UINT8 action, UINT8 ocf, tBTM_BLE_FILT_CB_EVT cb_evt, + tBTM_BLE_REF_VALUE ref, tBTM_BLE_PF_CFG_CBACK *p_cmpl_cback, + tBTM_BLE_PF_PARAM_CBACK *p_filt_param_cback) +{ + btm_ble_adv_filt_cb.op_q.action_ocf[btm_ble_adv_filt_cb.op_q.next_idx] = (action |(ocf << 4)); + btm_ble_adv_filt_cb.op_q.ref_value[btm_ble_adv_filt_cb.op_q.next_idx] = ref; + btm_ble_adv_filt_cb.op_q.cb_evt[btm_ble_adv_filt_cb.op_q.next_idx] = cb_evt; + btm_ble_adv_filt_cb.op_q.p_scan_cfg_cback[btm_ble_adv_filt_cb.op_q.next_idx] = p_cmpl_cback; + btm_ble_adv_filt_cb.op_q.p_filt_param_cback[btm_ble_adv_filt_cb.op_q.next_idx] + = p_filt_param_cback; + BTM_TRACE_DEBUG("btm_ble_advfilt_enq_op_q: act_ocf:%d, action:%d, ocf:%d,cb_evt;%d, cback:%x", + btm_ble_adv_filt_cb.op_q.action_ocf[btm_ble_adv_filt_cb.op_q.next_idx], action, + ocf, cb_evt, p_cmpl_cback); + btm_ble_adv_filt_cb.op_q.next_idx = (btm_ble_adv_filt_cb.op_q.next_idx + 1) + % BTM_BLE_PF_TYPE_MAX; +} + +/******************************************************************************* +** +** Function btm_ble_advfilt_deq_op_q +** +** Description dequeue an adv filter operation from q when command complete +** is received +** +** Returns void +** +*******************************************************************************/ +void btm_ble_advfilt_deq_op_q(UINT8 *p_action,UINT8 *p_ocf, tBTM_BLE_FILT_CB_EVT *p_cb_evt, + tBTM_BLE_REF_VALUE *p_ref, tBTM_BLE_PF_CFG_CBACK ** p_cmpl_cback, + tBTM_BLE_PF_PARAM_CBACK **p_filt_param_cback) +{ + *p_ocf = (btm_ble_adv_filt_cb.op_q.action_ocf[btm_ble_adv_filt_cb.op_q.pending_idx] >> 4); + *p_action = (btm_ble_adv_filt_cb.op_q.action_ocf[btm_ble_adv_filt_cb.op_q.pending_idx] + & BTM_BLE_ADV_FILT_SUBCODE_MASK); + *p_ref = btm_ble_adv_filt_cb.op_q.ref_value[btm_ble_adv_filt_cb.op_q.pending_idx]; + *p_cb_evt = btm_ble_adv_filt_cb.op_q.cb_evt[btm_ble_adv_filt_cb.op_q.pending_idx]; + *p_cmpl_cback = btm_ble_adv_filt_cb.op_q.p_scan_cfg_cback[btm_ble_adv_filt_cb.op_q.pending_idx]; + *p_filt_param_cback = + btm_ble_adv_filt_cb.op_q.p_filt_param_cback[btm_ble_adv_filt_cb.op_q.pending_idx]; + + btm_ble_adv_filt_cb.op_q.pending_idx = (btm_ble_adv_filt_cb.op_q.pending_idx + 1) + % BTM_BLE_PF_TYPE_MAX; + BTM_TRACE_DEBUG("btm_ble_advfilt_deq_op_q: ocf:%d, action:%d, ref_value:%d, cb_evt:%x", + *p_ocf,*p_action, *p_ref, *p_cb_evt); +} + +/******************************************************************************* +** +** Function btm_ble_condtype_to_ocf +** +** Description Convert cond_type to OCF +** +** Returns Returns ocf value +** +*******************************************************************************/ +UINT8 btm_ble_condtype_to_ocf(UINT8 cond_type) +{ + UINT8 ocf = 0; + + switch(cond_type) + { + case BTM_BLE_PF_ADDR_FILTER: + ocf = BTM_BLE_META_PF_ADDR; + break; + case BTM_BLE_PF_SRVC_UUID: + ocf = BTM_BLE_META_PF_UUID; + break; + case BTM_BLE_PF_SRVC_SOL_UUID: + ocf = BTM_BLE_META_PF_SOL_UUID; + break; + case BTM_BLE_PF_LOCAL_NAME: + ocf = BTM_BLE_META_PF_LOCAL_NAME; + break; + case BTM_BLE_PF_MANU_DATA: + ocf = BTM_BLE_META_PF_MANU_DATA; + break; + case BTM_BLE_PF_SRVC_DATA_PATTERN: + ocf = BTM_BLE_META_PF_SRVC_DATA; + break; + case BTM_BLE_PF_TYPE_ALL: + ocf = BTM_BLE_META_PF_ALL; + break; + default: + ocf = BTM_BLE_PF_TYPE_MAX; + break; + } + return ocf; +} + +/******************************************************************************* +** +** Function btm_ble_ocf_to_condtype +** +** Description Convert OCF to cond type +** +** Returns Returns condtype value +** +*******************************************************************************/ +UINT8 btm_ble_ocf_to_condtype(UINT8 ocf) +{ + UINT8 cond_type = 0; + + switch(ocf) + { + case BTM_BLE_META_PF_FEAT_SEL: + cond_type = BTM_BLE_META_PF_FEAT_SEL; + break; + case BTM_BLE_META_PF_ADDR: + cond_type = BTM_BLE_PF_ADDR_FILTER; + break; + case BTM_BLE_META_PF_UUID: + cond_type = BTM_BLE_PF_SRVC_UUID; + break; + case BTM_BLE_META_PF_SOL_UUID: + cond_type = BTM_BLE_PF_SRVC_SOL_UUID; + break; + case BTM_BLE_META_PF_LOCAL_NAME: + cond_type = BTM_BLE_PF_LOCAL_NAME; + break; + case BTM_BLE_META_PF_MANU_DATA: + cond_type = BTM_BLE_PF_MANU_DATA; + break; + case BTM_BLE_META_PF_SRVC_DATA: + cond_type = BTM_BLE_PF_SRVC_DATA_PATTERN; + break; + case BTM_BLE_META_PF_ALL: + cond_type = BTM_BLE_PF_TYPE_ALL; + break; + default: + cond_type = BTM_BLE_PF_TYPE_MAX; + break; + } + return cond_type; +} + +/******************************************************************************* +** +** Function btm_ble_scan_pf_cmpl_cback +** +** Description the BTM BLE customer feature VSC complete callback for ADV PF filtering +** +** Returns pointer to the counter if found; NULL otherwise. +** +*******************************************************************************/ +void btm_ble_scan_pf_cmpl_cback(tBTM_VSC_CMPL *p_params) +{ + UINT8 status = 0; + UINT8 *p = p_params->p_param_buf, op_subcode = 0, action = 0xff; + UINT16 evt_len = p_params->param_len; + UINT8 ocf = BTM_BLE_META_PF_ALL, cond_type = 0; + UINT8 num_avail = 0, cb_evt = 0; + tBTM_BLE_REF_VALUE ref_value = 0; + tBTM_BLE_PF_CFG_CBACK *p_scan_cfg_cback = NULL; + tBTM_BLE_PF_PARAM_CBACK *p_filt_param_cback = NULL; + + if (evt_len < 3 || evt_len > 4) + { + BTM_TRACE_ERROR("%s cannot interpret APCF callback status = %d, length = %d", + __func__, status, evt_len); + btm_ble_advfilt_deq_op_q(&action, &ocf, &cb_evt, &ref_value, &p_scan_cfg_cback, + &p_filt_param_cback); + return; + } + + btm_ble_advfilt_deq_op_q(&action, &ocf, &cb_evt, &ref_value, &p_scan_cfg_cback, + &p_filt_param_cback); + + STREAM_TO_UINT8(status, p); + STREAM_TO_UINT8(op_subcode, p); + STREAM_TO_UINT8(action, p); + + /* Ignore the event, if it is not the same one expected */ + if (3 == evt_len) + { + if(ocf != op_subcode) + { + BTM_TRACE_ERROR("btm_ble_scan_pf_cmpl_cback:3-Incorrect opcode :%d, %d, %d, %d, %d, %d", + ocf, op_subcode, action, evt_len, ref_value, status); + return; + } + else + { + if(NULL != btm_ble_adv_filt_cb.p_filt_stat_cback) + btm_ble_adv_filt_cb.p_filt_stat_cback(action, status, ref_value); + BTM_TRACE_DEBUG("btm_ble_scan_pf_cmpl_cback enabled/disabled, %d, %d, %d, %d", + ocf, action, status, ref_value); + return; + } + } + + if (4 == evt_len && ocf != op_subcode) + { + BTM_TRACE_ERROR("btm_ble_scan_pf_cmpl_cback:4-Incorrect opcode: %d, %d, %d, %d, %d", + ocf, op_subcode, action, status, ref_value); + return; + } + + STREAM_TO_UINT8(num_avail, p); + switch (op_subcode) + { + case BTM_BLE_META_PF_ADDR: + case BTM_BLE_META_PF_UUID: + case BTM_BLE_META_PF_SOL_UUID: + case BTM_BLE_META_PF_LOCAL_NAME: + case BTM_BLE_META_PF_MANU_DATA: + case BTM_BLE_META_PF_SRVC_DATA: + cond_type = btm_ble_ocf_to_condtype(ocf); + BTM_TRACE_DEBUG("btm_ble_scan_pf_cmpl_cback Recd: %d, %d, %d, %d, %d, %d", op_subcode, + ocf, action, status, ref_value, num_avail); + if (HCI_SUCCESS == status) + { + if (memcmp(&btm_ble_adv_filt_cb.cur_filter_target.bda, &na_bda, BD_ADDR_LEN) == 0) + btm_ble_cs_update_pf_counter(action, cond_type, NULL, num_avail); + else + btm_ble_cs_update_pf_counter(action, cond_type, + &btm_ble_adv_filt_cb.cur_filter_target, num_avail); + } + + /* send ADV PF operation complete */ + btm_ble_adv_filt_cb.op_type = 0; + break; + + case BTM_BLE_META_PF_FEAT_SEL: + BTM_TRACE_DEBUG("btm_ble_scan_pf_cmpl_cback-Feat sel event: %d, %d, %d, %d", + action, status, ref_value, num_avail); + break; + + default: + BTM_TRACE_ERROR("btm_ble_scan_pf_cmpl_cback: unknown operation: %d", op_subcode); + break; + } + + switch(cb_evt) + { + BTM_TRACE_DEBUG("btm_ble_scan_pf_cmpl_cback: calling the cback: %d", cb_evt); + case BTM_BLE_FILT_CFG: + if(NULL != p_scan_cfg_cback) + p_scan_cfg_cback(action, cond_type, num_avail, status, ref_value); + break; + case BTM_BLE_FILT_ADV_PARAM: + if(NULL != p_filt_param_cback) + p_filt_param_cback(action, num_avail, ref_value, status); + break; + default: + break; + } +} + +/******************************************************************************* +** +** Function btm_ble_find_addr_filter_counter +** +** Description find the per bd address ADV payload filter counter by BD_ADDR. +** +** Returns pointer to the counter if found; NULL otherwise. +** +*******************************************************************************/ +tBTM_BLE_PF_COUNT* btm_ble_find_addr_filter_counter(tBLE_BD_ADDR *p_le_bda) +{ + UINT8 i; + tBTM_BLE_PF_COUNT *p_addr_filter = &btm_ble_adv_filt_cb.p_addr_filter_count[1]; + + if (p_le_bda == NULL) + return &btm_ble_adv_filt_cb.p_addr_filter_count[0]; + + for (i = 0; i < cmn_ble_vsc_cb.max_filter; i ++, p_addr_filter ++) + { + if (p_addr_filter->in_use && + memcmp(p_le_bda->bda, p_addr_filter->bd_addr, BD_ADDR_LEN) == 0) + { + return p_addr_filter; + } + } + return NULL; +} + +/******************************************************************************* +** +** Function btm_ble_alloc_addr_filter_counter +** +** Description allocate the per device adv payload filter counter. +** +** Returns pointer to the counter if allocation succeed; NULL otherwise. +** +*******************************************************************************/ +tBTM_BLE_PF_COUNT * btm_ble_alloc_addr_filter_counter(BD_ADDR bd_addr) +{ + UINT8 i; + tBTM_BLE_PF_COUNT *p_addr_filter = &btm_ble_adv_filt_cb.p_addr_filter_count[1]; + + for (i = 0; i < cmn_ble_vsc_cb.max_filter; i ++, p_addr_filter ++) + { + if (memcmp(na_bda, p_addr_filter->bd_addr, BD_ADDR_LEN) == 0) + { + memcpy(p_addr_filter->bd_addr, bd_addr, BD_ADDR_LEN); + p_addr_filter->in_use = TRUE; + return p_addr_filter; + } + } + return NULL; +} +/******************************************************************************* +** +** Function btm_ble_dealloc_addr_filter_counter +** +** Description de-allocate the per device adv payload filter counter. +** +** Returns TRUE if deallocation succeed; FALSE otherwise. +** +*******************************************************************************/ +BOOLEAN btm_ble_dealloc_addr_filter_counter(tBLE_BD_ADDR *p_bd_addr, UINT8 filter_type) +{ + UINT8 i; + tBTM_BLE_PF_COUNT *p_addr_filter = &btm_ble_adv_filt_cb.p_addr_filter_count[1]; + BOOLEAN found = FALSE; + + if (BTM_BLE_PF_TYPE_ALL == filter_type && NULL == p_bd_addr) + memset(&btm_ble_adv_filt_cb.p_addr_filter_count[0], 0, sizeof(tBTM_BLE_PF_COUNT)); + + for (i = 0; i < cmn_ble_vsc_cb.max_filter; i ++, p_addr_filter ++) + { + if ((p_addr_filter->in_use) && (NULL == p_bd_addr || + (NULL != p_bd_addr && + memcmp(p_bd_addr->bda, p_addr_filter->bd_addr, BD_ADDR_LEN) == 0))) + { + found = TRUE; + memset(p_addr_filter, 0, sizeof(tBTM_BLE_PF_COUNT)); + + if (NULL != p_bd_addr) break; + } + } + return found; +} + +/******************************************************************************* +** +** Function btm_ble_update_pf_local_name +** +** Description this function update(add,delete or clear) the adv lcoal name filtering condition. +** +** +** Returns BTM_SUCCESS if sucessful, +** BTM_ILLEGAL_VALUE if paramter is not valid. +** +*******************************************************************************/ +tBTM_STATUS btm_ble_update_pf_local_name(tBTM_BLE_SCAN_COND_OP action, + tBTM_BLE_PF_FILT_INDEX filt_index, + tBTM_BLE_PF_COND_PARAM *p_cond) +{ + tBTM_BLE_PF_LOCAL_NAME_COND *p_local_name = (p_cond == NULL) ? NULL : &p_cond->local_name; + UINT8 param[BTM_BLE_PF_STR_LEN_MAX + BTM_BLE_ADV_FILT_META_HDR_LENGTH], + *p = param, + len = BTM_BLE_ADV_FILT_META_HDR_LENGTH; + tBTM_STATUS st = BTM_ILLEGAL_VALUE; + + memset(param, 0, BTM_BLE_PF_STR_LEN_MAX + BTM_BLE_ADV_FILT_META_HDR_LENGTH); + + UINT8_TO_STREAM(p, BTM_BLE_META_PF_LOCAL_NAME); + UINT8_TO_STREAM(p, action); + + /* Filter index */ + UINT8_TO_STREAM(p, filt_index); + + if (BTM_BLE_SCAN_COND_ADD == action || + BTM_BLE_SCAN_COND_DELETE == action) + { + if (NULL == p_local_name) + return st; + + if (p_local_name->data_len > BTM_BLE_PF_STR_LEN_MAX) + p_local_name->data_len = BTM_BLE_PF_STR_LEN_MAX; + + ARRAY_TO_STREAM(p, p_local_name->p_data, p_local_name->data_len); + len += p_local_name->data_len; + } + + /* send local name filter */ + if ((st = BTM_VendorSpecificCommand (HCI_BLE_ADV_FILTER_OCF, + len, + param, + btm_ble_scan_pf_cmpl_cback)) + != BTM_NO_RESOURCES) + { + memset(&btm_ble_adv_filt_cb.cur_filter_target, 0, sizeof(tBLE_BD_ADDR)); + } + else + { + BTM_TRACE_ERROR("Local Name PF filter update failed"); + } + + return st; +} + + +/******************************************************************************* +** +** Function btm_ble_update_srvc_data_change +** +** Description this function update(add/remove) service data change filter. +** +** +** Returns BTM_SUCCESS if sucessful, +** BTM_ILLEGAL_VALUE if paramter is not valid. +** +*******************************************************************************/ +tBTM_STATUS btm_ble_update_srvc_data_change(tBTM_BLE_SCAN_COND_OP action, + tBTM_BLE_PF_FILT_INDEX filt_index, + tBTM_BLE_PF_COND_PARAM *p_cond) +{ + tBTM_STATUS st = BTM_ILLEGAL_VALUE; + tBLE_BD_ADDR *p_bd_addr = p_cond ? &p_cond->target_addr : NULL; + UINT8 num_avail = (action == BTM_BLE_SCAN_COND_ADD) ? 0 : 1; + + if (btm_ble_cs_update_pf_counter (action, BTM_BLE_PF_SRVC_DATA, p_bd_addr, num_avail) + != BTM_BLE_INVALID_COUNTER) + st = BTM_SUCCESS; + + return st; +} + +/******************************************************************************* +** +** Function btm_ble_update_pf_manu_data +** +** Description this function update(add,delete or clear) the adv manufacturer +** data filtering condition. +** +** +** Returns BTM_SUCCESS if sucessful, +** BTM_ILLEGAL_VALUE if paramter is not valid. +** +*******************************************************************************/ +tBTM_STATUS btm_ble_update_pf_manu_data(tBTM_BLE_SCAN_COND_OP action, + tBTM_BLE_PF_FILT_INDEX filt_index, + tBTM_BLE_PF_COND_PARAM *p_data, + tBTM_BLE_PF_COND_TYPE cond_type, + tBTM_BLE_FILT_CB_EVT cb_evt, + tBTM_BLE_REF_VALUE ref_value) +{ + tBTM_BLE_PF_MANU_COND *p_manu_data = (p_data == NULL) ? NULL : &p_data->manu_data; + tBTM_BLE_PF_SRVC_PATTERN_COND *p_srvc_data = (p_data == NULL) ? NULL : &p_data->srvc_data; + + UINT8 param[BTM_BLE_PF_STR_LEN_MAX + BTM_BLE_PF_STR_LEN_MAX + BTM_BLE_ADV_FILT_META_HDR_LENGTH], + *p = param, + len = BTM_BLE_ADV_FILT_META_HDR_LENGTH; + tBTM_STATUS st = BTM_ILLEGAL_VALUE; + + if (NULL == p_data) + return st; + + memset(param, 0, BTM_BLE_PF_STR_LEN_MAX + BTM_BLE_PF_STR_LEN_MAX + + BTM_BLE_ADV_FILT_META_HDR_LENGTH); + + if (BTM_BLE_PF_SRVC_DATA_PATTERN == cond_type) + { + UINT8_TO_STREAM(p, BTM_BLE_META_PF_SRVC_DATA); + } + else + { + UINT8_TO_STREAM(p, BTM_BLE_META_PF_MANU_DATA); + } + + UINT8_TO_STREAM(p, action); + + /* Filter index */ + UINT8_TO_STREAM(p, filt_index); + + if (BTM_BLE_SCAN_COND_ADD == action || BTM_BLE_SCAN_COND_DELETE == action) + { + if (BTM_BLE_PF_SRVC_DATA_PATTERN == cond_type) + { + if (NULL == p_srvc_data) + return st; + if (p_srvc_data->data_len > (BTM_BLE_PF_STR_LEN_MAX - 2)) + p_srvc_data->data_len = (BTM_BLE_PF_STR_LEN_MAX - 2); + + if (p_srvc_data->data_len > 0) + { + ARRAY_TO_STREAM(p, p_srvc_data->p_pattern, p_srvc_data->data_len); + len += (p_srvc_data->data_len); + ARRAY_TO_STREAM(p, p_srvc_data->p_pattern_mask, p_srvc_data->data_len); + } + + len += (p_srvc_data->data_len); + BTM_TRACE_DEBUG("Service data length: %d", len); + } + else + { + if (NULL == p_manu_data) + { + BTM_TRACE_ERROR("btm_ble_update_pf_manu_data - No manuf data"); + return st; + } + BTM_TRACE_EVENT("btm_ble_update_pf_manu_data length: %d", + p_manu_data->data_len); + if (p_manu_data->data_len > (BTM_BLE_PF_STR_LEN_MAX - 2)) + p_manu_data->data_len = (BTM_BLE_PF_STR_LEN_MAX - 2); + + UINT16_TO_STREAM(p, p_manu_data->company_id); + if (p_manu_data->data_len > 0 && p_manu_data->p_pattern_mask != NULL) + { + ARRAY_TO_STREAM(p, p_manu_data->p_pattern, p_manu_data->data_len); + len += (p_manu_data->data_len + 2); + } + else + len += 2; + + if (p_manu_data->company_id_mask != 0) + { + UINT16_TO_STREAM (p, p_manu_data->company_id_mask); + } + else + { + memset(p, 0xff, 2); + p += 2; + } + len += 2; + + if (p_manu_data->data_len > 0 && p_manu_data->p_pattern_mask != NULL) + { + ARRAY_TO_STREAM(p, p_manu_data->p_pattern_mask, p_manu_data->data_len); + len += (p_manu_data->data_len); + } + + BTM_TRACE_DEBUG("Manuf data length: %d", len); + } + } + + /* send manufacturer*/ + if ((st = BTM_VendorSpecificCommand (HCI_BLE_ADV_FILTER_OCF, + len, + param, + btm_ble_scan_pf_cmpl_cback)) != BTM_NO_RESOURCES) + { + memset(&btm_ble_adv_filt_cb.cur_filter_target, 0, sizeof(tBLE_BD_ADDR)); + } + else + { + BTM_TRACE_ERROR("manufacturer data PF filter update failed"); + } + + return st; +} + +/******************************************************************************* +** +** Function btm_ble_cs_update_pf_counter +** +** Description this function is to update the adv data payload filter counter +** +** Returns current number of the counter; BTM_BLE_INVALID_COUNTER if +** counter update failed. +** +*******************************************************************************/ +UINT8 btm_ble_cs_update_pf_counter(tBTM_BLE_SCAN_COND_OP action, + UINT8 cond_type, tBLE_BD_ADDR *p_bd_addr, + UINT8 num_available) +{ + tBTM_BLE_PF_COUNT *p_addr_filter = NULL; + UINT8 *p_counter = NULL; + + btm_ble_obtain_vsc_details(); + + if (cond_type > BTM_BLE_PF_TYPE_ALL) + { + BTM_TRACE_ERROR("unknown PF filter condition type %d", cond_type); + return BTM_BLE_INVALID_COUNTER; + } + + /* for these three types of filter, always generic */ + if (BTM_BLE_PF_ADDR_FILTER == cond_type || + BTM_BLE_PF_MANU_DATA == cond_type || + BTM_BLE_PF_LOCAL_NAME == cond_type || + BTM_BLE_PF_SRVC_DATA_PATTERN == cond_type) + p_bd_addr = NULL; + + if ((p_addr_filter = btm_ble_find_addr_filter_counter(p_bd_addr)) == NULL && + BTM_BLE_SCAN_COND_ADD == action) + { + p_addr_filter = btm_ble_alloc_addr_filter_counter(p_bd_addr->bda); + } + + if (NULL != p_addr_filter) + { + /* all filter just cleared */ + if ((BTM_BLE_PF_TYPE_ALL == cond_type && BTM_BLE_SCAN_COND_CLEAR == action) || + /* or bd address filter been deleted */ + (BTM_BLE_PF_ADDR_FILTER == cond_type && + (BTM_BLE_SCAN_COND_DELETE == action || BTM_BLE_SCAN_COND_CLEAR == action))) + { + btm_ble_dealloc_addr_filter_counter(p_bd_addr, cond_type); + } + /* if not feature selection, update new addition/reduction of the filter counter */ + else if (cond_type != BTM_BLE_PF_TYPE_ALL) + { + p_counter = p_addr_filter->pf_counter; + if (num_available > 0) + p_counter[cond_type] += 1; + + BTM_TRACE_DEBUG("counter = %d, maxfilt = %d, num_avbl=%d", + p_counter[cond_type], cmn_ble_vsc_cb.max_filter, num_available); + return p_counter[cond_type]; + } + } + else + { + BTM_TRACE_ERROR("no matching filter counter found"); + } + /* no matching filter located and updated */ + return BTM_BLE_INVALID_COUNTER; +} + + +/******************************************************************************* +** +** Function btm_ble_update_addr_filter +** +** Description this function update(add,delete or clear) the address filter of adv. +** +** +** Returns BTM_SUCCESS if sucessful, +** BTM_ILLEGAL_VALUE if paramter is not valid. +** +*******************************************************************************/ +tBTM_STATUS btm_ble_update_addr_filter(tBTM_BLE_SCAN_COND_OP action, + tBTM_BLE_PF_FILT_INDEX filt_index, + tBTM_BLE_PF_COND_PARAM *p_cond) +{ + UINT8 param[BTM_BLE_META_ADDR_LEN + BTM_BLE_ADV_FILT_META_HDR_LENGTH], + * p= param; + tBTM_STATUS st = BTM_ILLEGAL_VALUE; + tBLE_BD_ADDR *p_addr = (p_cond == NULL) ? NULL : &p_cond->target_addr; + + memset(param, 0, BTM_BLE_META_ADDR_LEN + BTM_BLE_ADV_FILT_META_HDR_LENGTH); + + UINT8_TO_STREAM(p, BTM_BLE_META_PF_ADDR); + UINT8_TO_STREAM(p, action); + + /* Filter index */ + UINT8_TO_STREAM(p, filt_index); + + if (BTM_BLE_SCAN_COND_ADD == action || + BTM_BLE_SCAN_COND_DELETE == action) + { + if (NULL == p_addr) + return st; + + BDADDR_TO_STREAM(p, p_addr->bda); + UINT8_TO_STREAM(p, p_addr->type); + } + /* send address filter */ + if ((st = BTM_VendorSpecificCommand (HCI_BLE_ADV_FILTER_OCF, + (UINT8)(BTM_BLE_ADV_FILT_META_HDR_LENGTH + BTM_BLE_META_ADDR_LEN), + param, + btm_ble_scan_pf_cmpl_cback)) != BTM_NO_RESOURCES) + { + memset(&btm_ble_adv_filt_cb.cur_filter_target, 0, sizeof(tBLE_BD_ADDR)); + } + else + { + BTM_TRACE_ERROR("Broadcaster Address Filter Update failed"); + } + return st; +} + +/******************************************************************************* +** +** Function btm_ble_update_uuid_filter +** +** Description this function update(add,delete or clear) service UUID filter. +** +** +** Returns BTM_SUCCESS if sucessful, +** BTM_ILLEGAL_VALUE if paramter is not valid. +** +*******************************************************************************/ +tBTM_STATUS btm_ble_update_uuid_filter(tBTM_BLE_SCAN_COND_OP action, + tBTM_BLE_PF_FILT_INDEX filt_index, + tBTM_BLE_PF_COND_TYPE filter_type, + tBTM_BLE_PF_COND_PARAM *p_cond, + tBTM_BLE_FILT_CB_EVT cb_evt, + tBTM_BLE_REF_VALUE ref_value) +{ + UINT8 param[BTM_BLE_META_UUID_LEN + BTM_BLE_ADV_FILT_META_HDR_LENGTH], + * p= param, + len = BTM_BLE_ADV_FILT_META_HDR_LENGTH; + tBTM_STATUS st = BTM_ILLEGAL_VALUE; + tBTM_BLE_PF_UUID_COND *p_uuid_cond; + UINT8 evt_type; + + memset(param, 0, BTM_BLE_META_UUID_LEN + BTM_BLE_ADV_FILT_META_HDR_LENGTH); + + if (BTM_BLE_PF_SRVC_UUID == filter_type) + { + evt_type = BTM_BLE_META_PF_UUID; + p_uuid_cond = p_cond ? &p_cond->srvc_uuid : NULL; + } + else + { + evt_type = BTM_BLE_META_PF_SOL_UUID; + p_uuid_cond = p_cond ? &p_cond->solicitate_uuid : NULL; + } + + if (NULL == p_uuid_cond && action != BTM_BLE_SCAN_COND_CLEAR) + { + BTM_TRACE_ERROR("Illegal param for add/delete UUID filter"); + return st; + } + + /* need to add address filter first, if adding per bda UUID filter without address filter */ + if (BTM_BLE_SCAN_COND_ADD == action && NULL != p_uuid_cond && + p_uuid_cond->p_target_addr && + btm_ble_find_addr_filter_counter(p_uuid_cond->p_target_addr) == NULL) + { + UINT8_TO_STREAM(p, BTM_BLE_META_PF_ADDR); + UINT8_TO_STREAM(p, action); + + /* Filter index */ + UINT8_TO_STREAM(p, filt_index); + + BDADDR_TO_STREAM(p, p_uuid_cond->p_target_addr->bda); + UINT8_TO_STREAM(p, p_uuid_cond->p_target_addr->type); + + /* send address filter */ + if ((st = BTM_VendorSpecificCommand (HCI_BLE_ADV_FILTER_OCF, + (UINT8)(BTM_BLE_ADV_FILT_META_HDR_LENGTH + BTM_BLE_META_ADDR_LEN), + param, + btm_ble_scan_pf_cmpl_cback)) == BTM_NO_RESOURCES) + { + BTM_TRACE_ERROR("Update Address filter into controller failed."); + return st; + } + + btm_ble_advfilt_enq_op_q(action, BTM_BLE_META_PF_ADDR, cb_evt, ref_value, NULL, NULL); + BTM_TRACE_DEBUG("Updated Address filter"); + } + + p = param; + UINT8_TO_STREAM(p, evt_type); + UINT8_TO_STREAM(p, action); + + /* Filter index */ + UINT8_TO_STREAM(p, filt_index); + + if ((BTM_BLE_SCAN_COND_ADD == action || + BTM_BLE_SCAN_COND_DELETE == action) && + NULL != p_uuid_cond) + { + if (p_uuid_cond->uuid.len == LEN_UUID_16) + { + UINT16_TO_STREAM(p, p_uuid_cond->uuid.uu.uuid16); + len += LEN_UUID_16; + } + else if (p_uuid_cond->uuid.len == LEN_UUID_32)/*4 bytes */ + { + UINT32_TO_STREAM(p, p_uuid_cond->uuid.uu.uuid32); + len += LEN_UUID_32; + } + else if (p_uuid_cond->uuid.len == LEN_UUID_128) + { + ARRAY_TO_STREAM (p, p_uuid_cond->uuid.uu.uuid128, LEN_UUID_128); + len += LEN_UUID_128; + } + else + { + BTM_TRACE_ERROR("illegal UUID length: %d", p_uuid_cond->uuid.len); + return BTM_ILLEGAL_VALUE; + } + + if (NULL != p_uuid_cond->p_uuid_mask) + { + if (p_uuid_cond->uuid.len == LEN_UUID_16) + { + UINT16_TO_STREAM(p, p_uuid_cond->p_uuid_mask->uuid16_mask); + len += LEN_UUID_16; + } + else if (p_uuid_cond->uuid.len == LEN_UUID_32)/*4 bytes */ + { + UINT32_TO_STREAM(p, p_uuid_cond->p_uuid_mask->uuid32_mask); + len += LEN_UUID_32; + } + else if (p_uuid_cond->uuid.len == LEN_UUID_128) + { + ARRAY_TO_STREAM (p, p_uuid_cond->p_uuid_mask->uuid128_mask, LEN_UUID_128); + len += LEN_UUID_128; + } + } + else + { + memset(p, 0xff, p_uuid_cond->uuid.len); + len += p_uuid_cond->uuid.len; + } + BTM_TRACE_DEBUG("btm_ble_update_uuid_filter : %d, %d, %d, %d", filter_type, evt_type, + p_uuid_cond->uuid.len, len); + } + + /* send UUID filter update */ + if ((st = BTM_VendorSpecificCommand (HCI_BLE_ADV_FILTER_OCF, + len, + param, + btm_ble_scan_pf_cmpl_cback)) != BTM_NO_RESOURCES) + { + if (p_uuid_cond && p_uuid_cond->p_target_addr) + memcpy(&btm_ble_adv_filt_cb.cur_filter_target, p_uuid_cond->p_target_addr, + sizeof(tBLE_BD_ADDR)); + else + memset(&btm_ble_adv_filt_cb.cur_filter_target, 0, sizeof(tBLE_BD_ADDR)); + } + else + { + BTM_TRACE_ERROR("UUID filter udpating failed"); + } + + return st; +} + + +/******************************************************************************* +** +** Function btm_ble_clear_scan_pf_filter +** +** Description clear all adv payload filter by de-select all the adv pf feature bits +** +** +** Returns BTM_SUCCESS if sucessful, +** BTM_ILLEGAL_VALUE if paramter is not valid. +** +*******************************************************************************/ +tBTM_STATUS btm_ble_clear_scan_pf_filter(tBTM_BLE_SCAN_COND_OP action, + tBTM_BLE_PF_FILT_INDEX filt_index, + tBTM_BLE_PF_COND_PARAM *p_cond, + tBTM_BLE_PF_CFG_CBACK *p_cmpl_cback, + tBTM_BLE_FILT_CB_EVT cb_evt, + tBTM_BLE_REF_VALUE ref_value) +{ + tBLE_BD_ADDR *p_target = (p_cond == NULL)? NULL : &p_cond->target_addr; + tBTM_BLE_PF_COUNT *p_bda_filter; + tBTM_STATUS st = BTM_WRONG_MODE; + UINT8 param[20], *p; + + if (BTM_BLE_SCAN_COND_CLEAR != action) + { + BTM_TRACE_ERROR("unable to perform action:%d for generic adv filter type", action); + return BTM_ILLEGAL_VALUE; + } + + p = param; + memset(param, 0, 20); + + p_bda_filter = btm_ble_find_addr_filter_counter(p_target); + + if (NULL == p_bda_filter || + /* not a generic filter */ + (p_target != NULL && p_bda_filter)) + { + BTM_TRACE_ERROR("Error: Can not clear filter, No PF filter has been configured!"); + return st; + } + + /* clear the general filter entry */ + if (NULL == p_target) + { + /* clear manufactuer data filter */ + st = btm_ble_update_pf_manu_data(BTM_BLE_SCAN_COND_CLEAR, filt_index, NULL, + BTM_BLE_PF_MANU_DATA, cb_evt, ref_value); + if(BTM_CMD_STARTED == st) + btm_ble_advfilt_enq_op_q(action, BTM_BLE_META_PF_MANU_DATA, cb_evt, + ref_value, NULL, NULL); + + /* clear local name filter */ + st = btm_ble_update_pf_local_name(BTM_BLE_SCAN_COND_CLEAR, filt_index, NULL); + if(BTM_CMD_STARTED == st) + btm_ble_advfilt_enq_op_q(action, BTM_BLE_META_PF_LOCAL_NAME, cb_evt, + ref_value, NULL, NULL); + + /* update the counter for service data */ + st = btm_ble_update_srvc_data_change(BTM_BLE_SCAN_COND_CLEAR, filt_index, NULL); + + /* clear UUID filter */ + st = btm_ble_update_uuid_filter(BTM_BLE_SCAN_COND_CLEAR, filt_index, + BTM_BLE_PF_SRVC_UUID, NULL, cb_evt, ref_value); + if(BTM_CMD_STARTED == st) + btm_ble_advfilt_enq_op_q(action, BTM_BLE_META_PF_UUID, cb_evt, ref_value, NULL, NULL); + + st = btm_ble_update_uuid_filter(BTM_BLE_SCAN_COND_CLEAR, filt_index, + BTM_BLE_PF_SRVC_SOL_UUID, NULL, cb_evt, ref_value); + if(BTM_CMD_STARTED == st) + btm_ble_advfilt_enq_op_q(action, BTM_BLE_META_PF_SOL_UUID, cb_evt, + ref_value, NULL, NULL); + + /* clear service data filter */ + st = btm_ble_update_pf_manu_data(BTM_BLE_SCAN_COND_CLEAR, filt_index, NULL, + BTM_BLE_PF_SRVC_DATA_PATTERN, cb_evt, ref_value); + if(BTM_CMD_STARTED == st) + btm_ble_advfilt_enq_op_q(action, BTM_BLE_META_PF_SRVC_DATA, cb_evt, + ref_value, NULL, NULL); + } + + /* select feature based on control block settings */ + UINT8_TO_STREAM(p, BTM_BLE_META_PF_FEAT_SEL); + UINT8_TO_STREAM(p, BTM_BLE_SCAN_COND_CLEAR); + + /* Filter index */ + UINT8_TO_STREAM(p, filt_index); + + /* set PCF selection */ + UINT32_TO_STREAM(p, BTM_BLE_PF_SELECT_NONE); + /* set logic condition as OR as default */ + UINT8_TO_STREAM(p, BTM_BLE_PF_LOGIC_OR); + + if ((st = BTM_VendorSpecificCommand (HCI_BLE_ADV_FILTER_OCF, + (UINT8)(BTM_BLE_ADV_FILT_META_HDR_LENGTH + BTM_BLE_PF_FEAT_SEL_LEN), + param, + btm_ble_scan_pf_cmpl_cback)) + != BTM_NO_RESOURCES) + { + if (p_target) + memcpy(&btm_ble_adv_filt_cb.cur_filter_target, p_target, sizeof(tBLE_BD_ADDR)); + else + memset(&btm_ble_adv_filt_cb.cur_filter_target, 0, sizeof(tBLE_BD_ADDR)); + } + return st; +} + +/******************************************************************************* +** +** Function BTM_BleAdvFilterParamSetup +** +** Description This function is called to setup the adv data payload filter +** condition. +** +** Parameters action - Type of action to be performed +** filt_index - Filter index +** p_filt_params - Filter parameters +** p_target - Target device +** p_cmpl_back - Callback pointer +** ref_value - reference value +** +** Returns void +** +*******************************************************************************/ +tBTM_STATUS BTM_BleAdvFilterParamSetup(int action, tBTM_BLE_PF_FILT_INDEX filt_index, + tBTM_BLE_PF_FILT_PARAMS *p_filt_params, + tBLE_BD_ADDR *p_target, tBTM_BLE_PF_PARAM_CBACK *p_cmpl_cback, + tBTM_BLE_REF_VALUE ref_value) +{ + tBTM_STATUS st = BTM_WRONG_MODE; + tBTM_BLE_PF_COUNT *p_bda_filter = NULL; + UINT8 len = BTM_BLE_ADV_FILT_META_HDR_LENGTH + BTM_BLE_ADV_FILT_FEAT_SELN_LEN + + BTM_BLE_ADV_FILT_TRACK_NUM; + UINT8 param[len], *p; + + if (BTM_SUCCESS != btm_ble_obtain_vsc_details()) + return st; + + p = param; + memset(param, 0, len); + BTM_TRACE_EVENT (" BTM_BleAdvFilterParamSetup"); + + if (BTM_BLE_SCAN_COND_ADD == action) + { + p_bda_filter = btm_ble_find_addr_filter_counter(p_target); + if (NULL == p_bda_filter) + { + BTM_TRACE_ERROR("BD Address not found!"); + return st; + } + + BTM_TRACE_DEBUG("BTM_BleAdvFilterParamSetup : Feat mask:%d", p_filt_params->feat_seln); + /* select feature based on control block settings */ + UINT8_TO_STREAM(p, BTM_BLE_META_PF_FEAT_SEL); + UINT8_TO_STREAM(p, BTM_BLE_SCAN_COND_ADD); + + /* Filter index */ + UINT8_TO_STREAM(p, filt_index); + + /* set PCF selection */ + UINT16_TO_STREAM(p, p_filt_params->feat_seln); + /* set logic type */ + UINT16_TO_STREAM(p, p_filt_params->logic_type); + /* set logic condition */ + UINT8_TO_STREAM(p, p_filt_params->filt_logic_type); + /* set RSSI high threshold */ + UINT8_TO_STREAM(p, p_filt_params->rssi_high_thres); + /* set delivery mode */ + UINT8_TO_STREAM(p, p_filt_params->dely_mode); + + if (0x01 == p_filt_params->dely_mode) + { + /* set onfound timeout */ + UINT16_TO_STREAM(p, p_filt_params->found_timeout); + /* set onfound timeout count*/ + UINT8_TO_STREAM(p, p_filt_params->found_timeout_cnt); + /* set RSSI low threshold */ + UINT8_TO_STREAM(p, p_filt_params->rssi_low_thres); + /* set onlost timeout */ + UINT16_TO_STREAM(p, p_filt_params->lost_timeout); + /* set num_of_track_entries for firmware greater than L-release version */ + if (cmn_ble_vsc_cb.version_supported > BTM_VSC_CHIP_CAPABILITY_L_VERSION) + UINT16_TO_STREAM(p, p_filt_params->num_of_tracking_entries); + } + + if (cmn_ble_vsc_cb.version_supported == BTM_VSC_CHIP_CAPABILITY_L_VERSION) + len = BTM_BLE_ADV_FILT_META_HDR_LENGTH + BTM_BLE_ADV_FILT_FEAT_SELN_LEN; + else + len = BTM_BLE_ADV_FILT_META_HDR_LENGTH + BTM_BLE_ADV_FILT_FEAT_SELN_LEN + + BTM_BLE_ADV_FILT_TRACK_NUM; + + if ((st = BTM_VendorSpecificCommand (HCI_BLE_ADV_FILTER_OCF, + (UINT8)len, + param, + btm_ble_scan_pf_cmpl_cback)) + == BTM_NO_RESOURCES) + { + return st; + } + btm_ble_advfilt_enq_op_q(action, BTM_BLE_META_PF_FEAT_SEL, BTM_BLE_FILT_ADV_PARAM, + ref_value, NULL, p_cmpl_cback); + } + else + if (BTM_BLE_SCAN_COND_DELETE == action) + { + /* select feature based on control block settings */ + UINT8_TO_STREAM(p, BTM_BLE_META_PF_FEAT_SEL); + UINT8_TO_STREAM(p, BTM_BLE_SCAN_COND_DELETE); + /* Filter index */ + UINT8_TO_STREAM(p, filt_index); + + if ((st = BTM_VendorSpecificCommand (HCI_BLE_ADV_FILTER_OCF, + (UINT8)(BTM_BLE_ADV_FILT_META_HDR_LENGTH), + param, + btm_ble_scan_pf_cmpl_cback)) + == BTM_NO_RESOURCES) + { + return st; + } + btm_ble_advfilt_enq_op_q(action, BTM_BLE_META_PF_FEAT_SEL, BTM_BLE_FILT_ADV_PARAM, + ref_value, NULL, p_cmpl_cback); + } + else + if (BTM_BLE_SCAN_COND_CLEAR == action) + { + /* Deallocate all filters here */ + btm_ble_dealloc_addr_filter_counter(NULL, BTM_BLE_PF_TYPE_ALL); + + /* select feature based on control block settings */ + UINT8_TO_STREAM(p, BTM_BLE_META_PF_FEAT_SEL); + UINT8_TO_STREAM(p, BTM_BLE_SCAN_COND_CLEAR); + + if ((st = BTM_VendorSpecificCommand (HCI_BLE_ADV_FILTER_OCF, + (UINT8)(BTM_BLE_ADV_FILT_META_HDR_LENGTH-1), + param, + btm_ble_scan_pf_cmpl_cback)) + == BTM_NO_RESOURCES) + { + return st; + } + btm_ble_advfilt_enq_op_q(action, BTM_BLE_META_PF_FEAT_SEL, BTM_BLE_FILT_ADV_PARAM, + ref_value, NULL, p_cmpl_cback); + } + + return st; +} + +/******************************************************************************* +** +** Function BTM_BleEnableDisableFilterFeature +** +** Description This function is called to enable / disable the APCF feature +** +** Parameters enable the generic scan condition. +** enable: enable or disable the filter condition +** p_stat_cback - Status callback pointer +** ref_value - Ref value +** Returns void +** +*******************************************************************************/ +tBTM_STATUS BTM_BleEnableDisableFilterFeature(UINT8 enable, + tBTM_BLE_PF_STATUS_CBACK *p_stat_cback, + tBTM_BLE_REF_VALUE ref_value) +{ + UINT8 param[20], *p; + tBTM_STATUS st = BTM_WRONG_MODE; + + if (BTM_SUCCESS != btm_ble_obtain_vsc_details()) + return st; + + p = param; + memset(param, 0, 20); + + /* enable the content filter in controller */ + p = param; + UINT8_TO_STREAM(p, BTM_BLE_META_PF_ENABLE); + /* enable adv data payload filtering */ + UINT8_TO_STREAM(p, enable); + + if ((st = BTM_VendorSpecificCommand (HCI_BLE_ADV_FILTER_OCF, + BTM_BLE_PCF_ENABLE_LEN, param, + btm_ble_scan_pf_cmpl_cback)) == BTM_CMD_STARTED) + { + btm_ble_adv_filt_cb.p_filt_stat_cback = p_stat_cback; + btm_ble_advfilt_enq_op_q(enable, BTM_BLE_META_PF_ENABLE, BTM_BLE_FILT_ENABLE_DISABLE, + ref_value, NULL, NULL); + } + return st; +} + +/******************************************************************************* +** +** Function BTM_BleCfgFilterCondition +** +** Description This function is called to configure the adv data payload filter +** condition. +** +** Parameters action: to read/write/clear +** cond_type: filter condition type. +** filt_index - Filter index +** p_cond: filter condition parameter +** p_cmpl_cback - Config callback pointer +** ref_value - Reference value +** +** Returns void +** +*******************************************************************************/ +tBTM_STATUS BTM_BleCfgFilterCondition(tBTM_BLE_SCAN_COND_OP action, + tBTM_BLE_PF_COND_TYPE cond_type, + tBTM_BLE_PF_FILT_INDEX filt_index, + tBTM_BLE_PF_COND_PARAM *p_cond, + tBTM_BLE_PF_CFG_CBACK *p_cmpl_cback, + tBTM_BLE_REF_VALUE ref_value) +{ + tBTM_STATUS st = BTM_ILLEGAL_VALUE; + UINT8 ocf = 0; + BTM_TRACE_EVENT (" BTM_BleCfgFilterCondition action:%d, cond_type:%d, index:%d", action, + cond_type, filt_index); + + if (BTM_SUCCESS != btm_ble_obtain_vsc_details()) + return st; + + switch (cond_type) + { + /* write service data filter */ + case BTM_BLE_PF_SRVC_DATA_PATTERN: + /* write manufacturer data filter */ + case BTM_BLE_PF_MANU_DATA: + st = btm_ble_update_pf_manu_data(action, filt_index, p_cond, cond_type, 0, ref_value); + break; + + /* write local name filter */ + case BTM_BLE_PF_LOCAL_NAME: + st = btm_ble_update_pf_local_name(action, filt_index, p_cond); + break; + + /* filter on advertiser address */ + case BTM_BLE_PF_ADDR_FILTER: + st = btm_ble_update_addr_filter(action, filt_index, p_cond); + break; + + /* filter on service/solicitated UUID */ + case BTM_BLE_PF_SRVC_UUID: + case BTM_BLE_PF_SRVC_SOL_UUID: + st = btm_ble_update_uuid_filter(action, filt_index, cond_type, p_cond, 0, ref_value); + break; + + case BTM_BLE_PF_SRVC_DATA: + st = btm_ble_update_srvc_data_change(action, filt_index, p_cond); + break; + + case BTM_BLE_PF_TYPE_ALL: /* only used to clear filter */ + st = btm_ble_clear_scan_pf_filter(action, filt_index, p_cond, p_cmpl_cback, + 0, ref_value); + break; + + default: + BTM_TRACE_WARNING("condition type [%d] not supported currently.", cond_type); + break; + } + + if(BTM_CMD_STARTED == st && cond_type != BTM_BLE_PF_TYPE_ALL) + { + ocf = btm_ble_condtype_to_ocf(cond_type); + btm_ble_advfilt_enq_op_q(action, ocf, BTM_BLE_FILT_CFG, ref_value, p_cmpl_cback, NULL); + } + else + if(BTM_CMD_STARTED == st && BTM_BLE_PF_TYPE_ALL == cond_type) + { + btm_ble_advfilt_enq_op_q(action, BTM_BLE_META_PF_FEAT_SEL, BTM_BLE_FILT_CFG, + ref_value, p_cmpl_cback, NULL); + } + return st; +} + +/******************************************************************************* +** +** Function btm_ble_adv_filter_init +** +** Description This function initializes the adv filter control block +** +** Parameters +** +** Returns status +** +*******************************************************************************/ +void btm_ble_adv_filter_init(void) +{ + memset(&btm_ble_adv_filt_cb, 0, sizeof(tBTM_BLE_MULTI_ADV_CB)); + if (BTM_SUCCESS != btm_ble_obtain_vsc_details()) + return; + + if (cmn_ble_vsc_cb.max_filter > 0) + { + btm_ble_adv_filt_cb.p_addr_filter_count = + (tBTM_BLE_PF_COUNT*) GKI_getbuf( sizeof(tBTM_BLE_PF_COUNT) * cmn_ble_vsc_cb.max_filter); + } +} + +/******************************************************************************* +** +** Function btm_ble_adv_filter_cleanup +** +** Description This function de-initializes the adv filter control block +** +** Parameters +** +** Returns status +** +*******************************************************************************/ +void btm_ble_adv_filter_cleanup(void) +{ + if (btm_ble_adv_filt_cb.p_addr_filter_count) + GKI_freebuf (btm_ble_adv_filt_cb.p_addr_filter_count); +} + +#endif diff --git a/components/bt/bluedroid/stack/btm/btm_ble_batchscan.c b/components/bt/bluedroid/stack/btm/btm_ble_batchscan.c new file mode 100755 index 0000000000..22d01c6b4d --- /dev/null +++ b/components/bt/bluedroid/stack/btm/btm_ble_batchscan.c @@ -0,0 +1,972 @@ +/****************************************************************************** + * + * Copyright (C) 2014 Broadcom Corporation + * + * 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. + * + ******************************************************************************/ +#include +//#include +#include +#include "bt_target.h" + +#include "btm_ble_api.h" +#include "bt_types.h" +//#include "bt_utils.h" +#include "btu.h" +#include "btm_int.h" +#include "controller.h" +#include "hcimsgs.h" + +#if (BLE_INCLUDED == TRUE) + +tBTM_BLE_BATCH_SCAN_CB ble_batchscan_cb; +tBTM_BLE_ADV_TRACK_CB ble_advtrack_cb; + + +/* length of each batch scan command */ +#define BTM_BLE_BATCH_SCAN_STORAGE_CFG_LEN 4 +#define BTM_BLE_BATCH_SCAN_PARAM_CONFIG_LEN 12 +#define BTM_BLE_BATCH_SCAN_ENB_DISB_LEN 2 +#define BTM_BLE_BATCH_SCAN_READ_RESULTS_LEN 2 + +#define BTM_BLE_BATCH_SCAN_CB_EVT_MASK 0xF0 +#define BTM_BLE_BATCH_SCAN_SUBCODE_MASK 0x0F + +/******************************************************************************* +** Local functions +*******************************************************************************/ +void btm_ble_batchscan_vsc_cmpl_cback (tBTM_VSC_CMPL *p_params); +void btm_ble_batchscan_cleanup(void); + +/******************************************************************************* +** +** Function btm_ble_batchscan_filter_track_adv_vse_cback +** +** Description VSE callback for batch scan, filter, and tracking events. +** +** Returns None +** +*******************************************************************************/ +void btm_ble_batchscan_filter_track_adv_vse_cback(UINT8 len, UINT8 *p) +{ + tBTM_BLE_TRACK_ADV_DATA adv_data; + + UINT8 sub_event = 0; + tBTM_BLE_VSC_CB cmn_ble_vsc_cb; + STREAM_TO_UINT8(sub_event, p); + + BTM_TRACE_EVENT("btm_ble_batchscan_filter_track_adv_vse_cback called with event:%x", sub_event); + if (HCI_VSE_SUBCODE_BLE_THRESHOLD_SUB_EVT == sub_event && + NULL != ble_batchscan_cb.p_thres_cback) + { + ble_batchscan_cb.p_thres_cback(ble_batchscan_cb.ref_value); + return; + } + + if (HCI_VSE_SUBCODE_BLE_TRACKING_SUB_EVT == sub_event && NULL != ble_advtrack_cb.p_track_cback) + { + if (len < 10) + return; + + memset(&adv_data, 0 , sizeof(tBTM_BLE_TRACK_ADV_DATA)); + BTM_BleGetVendorCapabilities(&cmn_ble_vsc_cb); + adv_data.client_if = (UINT8)ble_advtrack_cb.ref_value; + if (cmn_ble_vsc_cb.version_supported > BTM_VSC_CHIP_CAPABILITY_L_VERSION) + { + STREAM_TO_UINT8(adv_data.filt_index, p); + STREAM_TO_UINT8(adv_data.advertiser_state, p); + STREAM_TO_UINT8(adv_data.advertiser_info_present, p); + STREAM_TO_BDADDR(adv_data.bd_addr.address, p); + STREAM_TO_UINT8(adv_data.addr_type, p); + + /* Extract the adv info details */ + if (ADV_INFO_PRESENT == adv_data.advertiser_info_present) + { + STREAM_TO_UINT8(adv_data.tx_power, p); + STREAM_TO_UINT8(adv_data.rssi_value, p); + STREAM_TO_UINT16(adv_data.time_stamp, p); + + STREAM_TO_UINT8(adv_data.adv_pkt_len, p); + if (adv_data.adv_pkt_len > 0) + { + adv_data.p_adv_pkt_data = GKI_getbuf(adv_data.adv_pkt_len); + memcpy(adv_data.p_adv_pkt_data, p, adv_data.adv_pkt_len); + } + + STREAM_TO_UINT8(adv_data.scan_rsp_len, p); + if (adv_data.scan_rsp_len > 0) + { + adv_data.p_scan_rsp_data = GKI_getbuf(adv_data.scan_rsp_len); + memcpy(adv_data.p_scan_rsp_data, p, adv_data.scan_rsp_len); + } + } + } + else + { + /* Based on L-release version */ + STREAM_TO_UINT8(adv_data.filt_index, p); + STREAM_TO_UINT8(adv_data.addr_type, p); + STREAM_TO_BDADDR(adv_data.bd_addr.address, p); + STREAM_TO_UINT8(adv_data.advertiser_state, p); + } + + BTM_TRACE_EVENT("track_adv_vse_cback called: %d, %d, %d", adv_data.filt_index, + adv_data.addr_type, adv_data.advertiser_state); + ble_advtrack_cb.p_track_cback(&adv_data); + return; + } +} + +/******************************************************************************* +** +** Function btm_ble_batchscan_enq_op_q +** +** Description enqueue a batchscan operation in q to check command complete +** status +** +** Returns void +** +*******************************************************************************/ +void btm_ble_batchscan_enq_op_q(UINT8 opcode, tBTM_BLE_BATCH_SCAN_STATE cur_state, + UINT8 cb_evt, tBTM_BLE_REF_VALUE ref_value) +{ + ble_batchscan_cb.op_q.sub_code[ble_batchscan_cb.op_q.next_idx] = (opcode |(cb_evt << 4)); + ble_batchscan_cb.op_q.cur_state[ble_batchscan_cb.op_q.next_idx] = cur_state; + ble_batchscan_cb.op_q.ref_value[ble_batchscan_cb.op_q.next_idx] = ref_value; + BTM_TRACE_DEBUG("btm_ble_batchscan_enq_op_q: subcode:%d, Cur_state:%d, ref_value:%d", + ble_batchscan_cb.op_q.sub_code[ble_batchscan_cb.op_q.next_idx], + ble_batchscan_cb.op_q.cur_state[ble_batchscan_cb.op_q.next_idx], + ble_batchscan_cb.op_q.ref_value[ble_batchscan_cb.op_q.next_idx]); + ble_batchscan_cb.op_q.next_idx = (ble_batchscan_cb.op_q.next_idx + 1) + % BTM_BLE_BATCH_SCAN_MAX; +} + +/******************************************************************************* +** +** Function btm_ble_batchscan_enq_rep_q +** +** Description enqueue a batchscan report operation in q to check command complete +** status +** +** Returns void +** +*******************************************************************************/ +tBTM_STATUS btm_ble_batchscan_enq_rep_q(UINT8 report_format, tBTM_BLE_REF_VALUE ref_value) +{ + int i = 0; + for (i = 0; i < BTM_BLE_BATCH_REP_MAIN_Q_SIZE; i++) + { + if (report_format == ble_batchscan_cb.main_rep_q.rep_mode[i]) + return BTM_ILLEGAL_VALUE; + } + + ble_batchscan_cb.main_rep_q.rep_mode[ble_batchscan_cb.main_rep_q.next_idx] = report_format; + ble_batchscan_cb.main_rep_q.ref_value[ble_batchscan_cb.main_rep_q.next_idx] = ref_value; + ble_batchscan_cb.main_rep_q.num_records[ble_batchscan_cb.main_rep_q.next_idx] = 0; + ble_batchscan_cb.main_rep_q.data_len[ble_batchscan_cb.main_rep_q.next_idx] = 0; + ble_batchscan_cb.main_rep_q.p_data[ble_batchscan_cb.main_rep_q.next_idx] = NULL; + BTM_TRACE_DEBUG("btm_ble_batchscan_enq_rep_q: index:%d, rep %d, ref %d", + ble_batchscan_cb.main_rep_q.next_idx, report_format, ref_value); + + ble_batchscan_cb.main_rep_q.next_idx = (ble_batchscan_cb.main_rep_q.next_idx + 1) + % BTM_BLE_BATCH_REP_MAIN_Q_SIZE; + return BTM_SUCCESS; +} + +/******************************************************************************* +** +** Function btm_ble_batchscan_enq_rep_data +** +** Description setup the data in the main report queue +** +** Returns void +** +*******************************************************************************/ +void btm_ble_batchscan_enq_rep_data(UINT8 report_format, UINT8 num_records, UINT8 *p_data, + UINT8 data_len) +{ + int index = 0, len = 0; + UINT8 *p_orig_data = NULL, *p_app_data = NULL; + + for (index = 0; index < BTM_BLE_BATCH_REP_MAIN_Q_SIZE; index++) + { + if (report_format == ble_batchscan_cb.main_rep_q.rep_mode[index]) + break; + } + + BTM_TRACE_DEBUG("btm_ble_batchscan_enq_rep_data: index:%d, rep %d, num %d len : %d", + index, report_format, num_records, data_len); + + if (index < BTM_BLE_BATCH_REP_MAIN_Q_SIZE && data_len > 0 && num_records > 0) + { + len = ble_batchscan_cb.main_rep_q.data_len[index]; + p_orig_data = ble_batchscan_cb.main_rep_q.p_data[index]; + if (NULL != p_orig_data) + { + p_app_data = GKI_getbuf(len + data_len); + memcpy(p_app_data, p_orig_data, len); + memcpy(p_app_data+len, p_data, data_len); + GKI_freebuf(p_orig_data); + ble_batchscan_cb.main_rep_q.p_data[index] = p_app_data; + ble_batchscan_cb.main_rep_q.num_records[index] += num_records; + ble_batchscan_cb.main_rep_q.data_len[index] += data_len; + } + else + { + p_app_data = GKI_getbuf(data_len); + memcpy(p_app_data, p_data, data_len); + ble_batchscan_cb.main_rep_q.p_data[index] = p_app_data; + ble_batchscan_cb.main_rep_q.num_records[index] = num_records; + ble_batchscan_cb.main_rep_q.data_len[index] = data_len; + } + } +} + +/******************************************************************************* +** +** Function btm_ble_batchscan_deq_rep_q +** +** Description dequeue a batchscan report in q when command complete +** is received +** +** Returns void +** +*******************************************************************************/ +void btm_ble_batchscan_deq_rep_data(UINT8 report_format, tBTM_BLE_REF_VALUE *p_ref_value, + UINT8 *p_num_records, UINT8 **p_data, UINT16 *p_data_len) +{ + int index = 0; + + for (index = 0; index < BTM_BLE_BATCH_REP_MAIN_Q_SIZE; index++) + { + if (report_format == ble_batchscan_cb.main_rep_q.rep_mode[index]) + break; + } + + if (BTM_BLE_BATCH_REP_MAIN_Q_SIZE == index) + { + BTM_TRACE_ERROR("btm_ble_batchscan_deq_rep_data: rep_format:%d not found", report_format); + return; + } + + *p_num_records = ble_batchscan_cb.main_rep_q.num_records[index]; + *p_ref_value = ble_batchscan_cb.main_rep_q.ref_value[index]; + *p_data = ble_batchscan_cb.main_rep_q.p_data[index]; + *p_data_len = ble_batchscan_cb.main_rep_q.data_len[index]; + + ble_batchscan_cb.main_rep_q.p_data[index] = NULL; + ble_batchscan_cb.main_rep_q.data_len[index] = 0; + ble_batchscan_cb.main_rep_q.rep_mode[index] = 0; + ble_batchscan_cb.main_rep_q.ref_value[index] = 0; + ble_batchscan_cb.main_rep_q.num_records[index] = 0; + + BTM_TRACE_DEBUG("btm_ble_batchscan_deq_rep_data: index:%d, rep %d, num %d, data_len %d", + index, report_format, *p_num_records, *p_data_len); + + ble_batchscan_cb.main_rep_q.pending_idx = (ble_batchscan_cb.main_rep_q.pending_idx + 1) + % BTM_BLE_BATCH_SCAN_MAX; +} + +/******************************************************************************* +** +** Function btm_ble_batchscan_deq_op_q +** +** Description dequeue a batch scan operation from q when command complete +** is received +** +** Returns void +** +*******************************************************************************/ +void btm_ble_batchscan_deq_op_q(UINT8 *p_opcode,tBTM_BLE_BATCH_SCAN_STATE *cur_state, + UINT8 *p_cb_evt, tBTM_BLE_REF_VALUE *p_ref) +{ + *p_cb_evt = (ble_batchscan_cb.op_q.sub_code[ble_batchscan_cb.op_q.pending_idx] >> 4); + *p_opcode = (ble_batchscan_cb.op_q.sub_code[ble_batchscan_cb.op_q.pending_idx] + & BTM_BLE_BATCH_SCAN_SUBCODE_MASK); + *p_ref = ble_batchscan_cb.op_q.ref_value[ble_batchscan_cb.op_q.pending_idx]; + *cur_state = (ble_batchscan_cb.op_q.cur_state[ble_batchscan_cb.op_q.pending_idx]); + ble_batchscan_cb.op_q.pending_idx = (ble_batchscan_cb.op_q.pending_idx + 1) + % BTM_BLE_BATCH_SCAN_MAX; +} + +/******************************************************************************* +** +** Function btm_ble_read_batchscan_reports +** +** Description This function reads the reports from controller +** +** Parameters scan_mode - The mode for which the reports are to be read out from the controller +** ref_value - Reference value +** +** Returns status +** +*******************************************************************************/ +tBTM_STATUS btm_ble_read_batchscan_reports(tBTM_BLE_BATCH_SCAN_MODE scan_mode, + tBTM_BLE_REF_VALUE ref_value) +{ + tBTM_STATUS status = BTM_NO_RESOURCES; + UINT8 param[BTM_BLE_BATCH_SCAN_READ_RESULTS_LEN], *pp; + pp = param; + + memset(param, 0, BTM_BLE_BATCH_SCAN_READ_RESULTS_LEN); + + UINT8_TO_STREAM (pp, BTM_BLE_BATCH_SCAN_READ_RESULTS); + UINT8_TO_STREAM (pp, scan_mode); + + if ((status = BTM_VendorSpecificCommand (HCI_BLE_BATCH_SCAN_OCF, + BTM_BLE_BATCH_SCAN_READ_RESULTS_LEN, param, btm_ble_batchscan_vsc_cmpl_cback)) + != BTM_CMD_STARTED) + { + BTM_TRACE_ERROR("btm_ble_read_batchscan_reports %d", status); + return BTM_ILLEGAL_VALUE; + } + + if (BTM_CMD_STARTED == status) + { + /* The user needs to be provided scan read reports event */ + btm_ble_batchscan_enq_op_q(BTM_BLE_BATCH_SCAN_READ_RESULTS, ble_batchscan_cb.cur_state, + BTM_BLE_BATCH_SCAN_READ_REPTS_EVT, ref_value); + } + + return status; +} + +/******************************************************************************* +** +** Function btm_ble_batchscan_vsc_cmpl_cback +** +** Description Batch scan VSC complete callback +** +** Parameters p_params - VSC completed callback parameters +** +** Returns void +** +*******************************************************************************/ +void btm_ble_batchscan_vsc_cmpl_cback (tBTM_VSC_CMPL *p_params) +{ + UINT8 *p = p_params->p_param_buf; + UINT16 len = p_params->param_len; + tBTM_BLE_REF_VALUE ref_value = 0; + + UINT8 status = 0, subcode = 0, opcode = 0; + UINT8 report_format = 0, num_records = 0, cb_evt = 0; + UINT16 data_len = 0; + tBTM_BLE_BATCH_SCAN_STATE cur_state = 0; + tBTM_STATUS btm_status = 0; + UINT8 *p_data = NULL; + + if (len < 2) + { + BTM_TRACE_ERROR("wrong length for btm_ble_batch_scan_vsc_cmpl_cback"); + btm_ble_batchscan_deq_op_q(&opcode, &cur_state, &cb_evt, &ref_value); + return; + } + + STREAM_TO_UINT8(status, p); + STREAM_TO_UINT8(subcode, p); + + btm_ble_batchscan_deq_op_q(&opcode, &cur_state, &cb_evt, &ref_value); + + BTM_TRACE_DEBUG("btm_ble_batchscan op_code = %02x state = %02x cb_evt = %02x,ref_value=%d", + opcode, cur_state, cb_evt, ref_value); + + if (opcode != subcode) + { + BTM_TRACE_ERROR("Got unexpected VSC cmpl, expected: %d got: %d",subcode,opcode); + return; + } + + switch (subcode) + { + case BTM_BLE_BATCH_SCAN_ENB_DISAB_CUST_FEATURE: + { + if (BTM_SUCCESS == status && BTM_BLE_SCAN_ENABLE_CALLED == cur_state) + ble_batchscan_cb.cur_state = BTM_BLE_SCAN_ENABLED_STATE; + else + if (BTM_BLE_SCAN_ENABLE_CALLED == cur_state) + { + BTM_TRACE_ERROR("SCAN_ENB_DISAB_CUST_FEATURE - Invalid state after enb"); + ble_batchscan_cb.cur_state = BTM_BLE_SCAN_INVALID_STATE; + } + + BTM_TRACE_DEBUG("BTM_BLE_BATCH_SCAN_ENB_DISAB_CUST_FEAT status = %d, state: %d,evt=%d", + status, ble_batchscan_cb.cur_state, cb_evt); + + if (cb_evt != 0 && NULL != ble_batchscan_cb.p_setup_cback) + ble_batchscan_cb.p_setup_cback(cb_evt, ref_value, status); + break; + } + + case BTM_BLE_BATCH_SCAN_SET_STORAGE_PARAM: + { + BTM_TRACE_DEBUG("BTM_BLE_BATCH_SCAN_SET_STORAGE_PARAM status = %d, evt=%d", + status, cb_evt); + if (cb_evt != 0 && NULL != ble_batchscan_cb.p_setup_cback) + ble_batchscan_cb.p_setup_cback(cb_evt, ref_value, status); + break; + } + + case BTM_BLE_BATCH_SCAN_SET_PARAMS: + { + BTM_TRACE_DEBUG("BTM_BLE_BATCH_SCAN_SET_PARAMS status = %d,evt=%d", status, cb_evt); + + if (BTM_BLE_SCAN_DISABLE_CALLED == cur_state) + { + if (BTM_SUCCESS == status) + { + ble_batchscan_cb.cur_state = BTM_BLE_SCAN_DISABLED_STATE; + } + else + { + BTM_TRACE_ERROR("BTM_BLE_BATCH_SCAN_SET_PARAMS - Invalid state after disabled"); + ble_batchscan_cb.cur_state = BTM_BLE_SCAN_INVALID_STATE; + } + } + + if (cb_evt != 0 && NULL != ble_batchscan_cb.p_setup_cback) + ble_batchscan_cb.p_setup_cback(cb_evt, ref_value, status); + break; + } + + case BTM_BLE_BATCH_SCAN_READ_RESULTS: + { + if (cb_evt != 0 && NULL != ble_batchscan_cb.p_scan_rep_cback) + { + STREAM_TO_UINT8(report_format,p); + STREAM_TO_UINT8(num_records, p); + p = (uint8_t *)(p_params->p_param_buf + 4); + BTM_TRACE_DEBUG("BTM_BLE_BATCH_SCAN_READ_RESULTS status=%d,len=%d,rec=%d", + status, len-4, num_records); + + if (0 == num_records) + { + btm_ble_batchscan_deq_rep_data(report_format, &ref_value, &num_records, + &p_data, &data_len); + if (NULL != ble_batchscan_cb.p_scan_rep_cback) + ble_batchscan_cb.p_scan_rep_cback(ref_value,report_format, num_records, + data_len, p_data, status); + } + else + { + if ((len-4) > 0) + { + btm_ble_batchscan_enq_rep_data(report_format, num_records, p, len-4); + /* More records could be in the buffer and needs to be pulled out */ + btm_status = btm_ble_read_batchscan_reports(report_format, ref_value); + if (BTM_CMD_STARTED != btm_status) + { + btm_ble_batchscan_deq_rep_data(report_format, &ref_value, &num_records, + &p_data, &data_len); + /* Send whatever is available, in case of a command failure */ + if (NULL != ble_batchscan_cb.p_scan_rep_cback && NULL != p_data) + ble_batchscan_cb.p_scan_rep_cback(ref_value,report_format, + num_records, data_len, p_data, status); + } + } + } + } + break; + } + + default: + break; + } + + return; +} + +/******************************************************************************* +** +** Function btm_ble_set_storage_config +** +** Description This function writes the storage configuration in controller +** +** Parameters batch_scan_full_max -Max storage space (in %) allocated to full scanning +** batch_scan_trunc_max -Max storage space (in %) allocated to truncated scanning +** batch_scan_notify_threshold - Setup notification level based on total space +** +** Returns status +** +*******************************************************************************/ +tBTM_STATUS btm_ble_set_storage_config(UINT8 batch_scan_full_max, UINT8 batch_scan_trunc_max, + UINT8 batch_scan_notify_threshold) +{ + tBTM_STATUS status = BTM_NO_RESOURCES; + UINT8 param[BTM_BLE_BATCH_SCAN_STORAGE_CFG_LEN], *pp; + + pp = param; + memset(param, 0, BTM_BLE_BATCH_SCAN_STORAGE_CFG_LEN); + + UINT8_TO_STREAM (pp, BTM_BLE_BATCH_SCAN_SET_STORAGE_PARAM); + UINT8_TO_STREAM (pp, batch_scan_full_max); + UINT8_TO_STREAM (pp, batch_scan_trunc_max); + UINT8_TO_STREAM (pp, batch_scan_notify_threshold); + + if ((status = BTM_VendorSpecificCommand (HCI_BLE_BATCH_SCAN_OCF, + BTM_BLE_BATCH_SCAN_STORAGE_CFG_LEN, param, + btm_ble_batchscan_vsc_cmpl_cback))!= BTM_CMD_STARTED) + { + BTM_TRACE_ERROR("btm_ble_set_storage_config %d", status); + return BTM_ILLEGAL_VALUE; + } + + return status; +} + +/******************************************************************************* +** +** Function btm_ble_set_batchscan_param +** +** Description This function writes the batch scan params in controller +** +** Parameters scan_mode -Batch scan mode +** scan_interval - Scan interval +** scan_window - Scan window +** discard_rule -Discard rules +** addr_type - Address type +** +** Returns status +** +*******************************************************************************/ +tBTM_STATUS btm_ble_set_batchscan_param(tBTM_BLE_BATCH_SCAN_MODE scan_mode, + UINT32 scan_interval, UINT32 scan_window, tBLE_ADDR_TYPE addr_type, + tBTM_BLE_DISCARD_RULE discard_rule) +{ + tBTM_STATUS status = BTM_NO_RESOURCES; + UINT8 scan_param[BTM_BLE_BATCH_SCAN_PARAM_CONFIG_LEN], *pp_scan; + + pp_scan = scan_param; + memset(scan_param, 0, BTM_BLE_BATCH_SCAN_PARAM_CONFIG_LEN); + + // Override param and decide addr_type based on own addr type + // TODO: Remove upper layer parameter? + addr_type = btm_cb.ble_ctr_cb.addr_mgnt_cb.own_addr_type; + + UINT8_TO_STREAM (pp_scan, BTM_BLE_BATCH_SCAN_SET_PARAMS); + UINT8_TO_STREAM (pp_scan, scan_mode); + UINT32_TO_STREAM (pp_scan, scan_window); + UINT32_TO_STREAM (pp_scan, scan_interval); + UINT8_TO_STREAM (pp_scan, addr_type); + UINT8_TO_STREAM (pp_scan, discard_rule); + + if ((status = BTM_VendorSpecificCommand (HCI_BLE_BATCH_SCAN_OCF, + BTM_BLE_BATCH_SCAN_PARAM_CONFIG_LEN, + scan_param, btm_ble_batchscan_vsc_cmpl_cback))!= BTM_CMD_STARTED) + { + BTM_TRACE_ERROR("btm_ble_set_batchscan_param %d", status); + return BTM_ILLEGAL_VALUE; + } + + return status; +} + +/******************************************************************************* +** +** Function btm_ble_enable_disable_batchscan +** +** Description This function enables the customer specific feature in controller +** +** Parameters enable_disable: true - enable, false - disable +** +** Returns status +** +*******************************************************************************/ +tBTM_STATUS btm_ble_enable_disable_batchscan(BOOLEAN should_enable) +{ + tBTM_STATUS status = BTM_NO_RESOURCES; + UINT8 shld_enable = 0x01; + UINT8 enable_param[BTM_BLE_BATCH_SCAN_ENB_DISB_LEN], *pp_enable; + + if (!should_enable) + shld_enable = 0x00; + + if (should_enable) + { + pp_enable = enable_param; + memset(enable_param, 0, BTM_BLE_BATCH_SCAN_ENB_DISB_LEN); + + UINT8_TO_STREAM (pp_enable, BTM_BLE_BATCH_SCAN_ENB_DISAB_CUST_FEATURE); + UINT8_TO_STREAM (pp_enable, shld_enable); + + if ((status = BTM_VendorSpecificCommand(HCI_BLE_BATCH_SCAN_OCF, + BTM_BLE_BATCH_SCAN_ENB_DISB_LEN, enable_param, + btm_ble_batchscan_vsc_cmpl_cback)) != BTM_CMD_STARTED) + { + status = BTM_MODE_UNSUPPORTED; + BTM_TRACE_ERROR("btm_ble_enable_disable_batchscan %d", status); + return BTM_ILLEGAL_VALUE; + } + } + else + if ((status = btm_ble_set_batchscan_param(BTM_BLE_BATCH_SCAN_MODE_DISABLE, + ble_batchscan_cb.scan_interval, ble_batchscan_cb.scan_window, + ble_batchscan_cb.addr_type, ble_batchscan_cb.discard_rule)) != BTM_CMD_STARTED) + { + status = BTM_MODE_UNSUPPORTED; + BTM_TRACE_ERROR("btm_ble_enable_disable_batchscan %d", status); + return BTM_ILLEGAL_VALUE; + } + + if (should_enable) + ble_batchscan_cb.cur_state = BTM_BLE_SCAN_ENABLE_CALLED; + else + ble_batchscan_cb.cur_state = BTM_BLE_SCAN_DISABLE_CALLED; + return status; +} + +/******************************************************************************* +** +** Function BTM_BleSetStorageConfig +** +** Description This function is called to write storage config params. +** +** Parameters: batch_scan_full_max - Max storage space (in %) allocated to full style +** batch_scan_trunc_max - Max storage space (in %) allocated to trunc style +** batch_scan_notify_threshold - Setup notification level based on total space +** p_setup_cback - Setup callback pointer +** p_thres_cback - Threshold callback pointer +** p_rep_cback - Reports callback pointer +** ref_value - Reference value +** +** Returns tBTM_STATUS +** +*******************************************************************************/ +tBTM_STATUS BTM_BleSetStorageConfig(UINT8 batch_scan_full_max, UINT8 batch_scan_trunc_max, + UINT8 batch_scan_notify_threshold, + tBTM_BLE_SCAN_SETUP_CBACK *p_setup_cback, + tBTM_BLE_SCAN_THRESHOLD_CBACK *p_thres_cback, + tBTM_BLE_SCAN_REP_CBACK* p_rep_cback, + tBTM_BLE_REF_VALUE ref_value) +{ + tBTM_STATUS status = BTM_NO_RESOURCES; + tBTM_BLE_VSC_CB cmn_ble_vsc_cb; + + BTM_TRACE_EVENT (" BTM_BleSetStorageConfig: %d, %d, %d, %d, %d", + ble_batchscan_cb.cur_state, ref_value, batch_scan_full_max, batch_scan_trunc_max, + batch_scan_notify_threshold); + + if (!controller_get_interface()->supports_ble()) + return BTM_ILLEGAL_VALUE; + + BTM_BleGetVendorCapabilities(&cmn_ble_vsc_cb); + + if (0 == cmn_ble_vsc_cb.tot_scan_results_strg) + { + BTM_TRACE_ERROR("Controller does not support batch scan"); + return BTM_ERR_PROCESSING; + } + + ble_batchscan_cb.p_setup_cback = p_setup_cback; + ble_batchscan_cb.p_thres_cback = p_thres_cback; + ble_batchscan_cb.p_scan_rep_cback = p_rep_cback; + ble_batchscan_cb.ref_value = ref_value; + + if (batch_scan_full_max > BTM_BLE_ADV_SCAN_FULL_MAX || + batch_scan_trunc_max > BTM_BLE_ADV_SCAN_TRUNC_MAX || + batch_scan_notify_threshold > BTM_BLE_ADV_SCAN_THR_MAX) + { + BTM_TRACE_ERROR("Illegal set storage config params"); + return BTM_ILLEGAL_VALUE; + } + + if (BTM_BLE_SCAN_INVALID_STATE == ble_batchscan_cb.cur_state || + BTM_BLE_SCAN_DISABLED_STATE == ble_batchscan_cb.cur_state || + BTM_BLE_SCAN_DISABLE_CALLED == ble_batchscan_cb.cur_state) + { + status = btm_ble_enable_disable_batchscan(TRUE); + if (BTM_CMD_STARTED != status) + return status; + + ble_batchscan_cb.cur_state = BTM_BLE_SCAN_ENABLE_CALLED; + btm_ble_batchscan_enq_op_q(BTM_BLE_BATCH_SCAN_ENB_DISAB_CUST_FEATURE, + BTM_BLE_SCAN_ENABLE_CALLED, 0, ref_value); + } + + status = btm_ble_set_storage_config(batch_scan_full_max, batch_scan_trunc_max, + batch_scan_notify_threshold); + if (BTM_CMD_STARTED != status) + return status; + /* The user needs to be provided scan config storage event */ + btm_ble_batchscan_enq_op_q(BTM_BLE_BATCH_SCAN_SET_STORAGE_PARAM, ble_batchscan_cb.cur_state, + BTM_BLE_BATCH_SCAN_CFG_STRG_EVT, ref_value); + + return status; +} + + +/******************************************************************************* +** +** Function BTM_BleEnableBatchScan +** +** Description This function is called to configure and enable batch scanning +** +** Parameters: scan_mode -Batch scan mode +** scan_interval - Scan interval value +** scan_window - Scan window value +** discard_rule - Data discard rule +** ref_value - Reference value +** +** Returns tBTM_STATUS +** +*******************************************************************************/ +tBTM_STATUS BTM_BleEnableBatchScan(tBTM_BLE_BATCH_SCAN_MODE scan_mode, + UINT32 scan_interval, UINT32 scan_window, tBLE_ADDR_TYPE addr_type, + tBTM_BLE_DISCARD_RULE discard_rule, tBTM_BLE_REF_VALUE ref_value) +{ + tBTM_STATUS status = BTM_NO_RESOURCES; + tBTM_BLE_VSC_CB cmn_ble_vsc_cb; + BTM_TRACE_EVENT (" BTM_BleEnableBatchScan: %d, %d, %d, %d, %d, %d", + scan_mode, scan_interval, scan_window, addr_type, discard_rule, ref_value); + + if (!controller_get_interface()->supports_ble()) + return BTM_ILLEGAL_VALUE; + + BTM_BleGetVendorCapabilities(&cmn_ble_vsc_cb); + + if (0 == cmn_ble_vsc_cb.tot_scan_results_strg) + { + BTM_TRACE_ERROR("Controller does not support batch scan"); + return BTM_ERR_PROCESSING; + } + + BTM_TRACE_DEBUG("BTM_BleEnableBatchScan: %d, %x, %x, %d, %d", scan_mode, scan_interval, + scan_window, discard_rule, ble_batchscan_cb.cur_state); + + /* Only 16 bits will be used for scan interval and scan window as per agreement with Google */ + /* So the standard LE range would suffice for scan interval and scan window */ + if ((BTM_BLE_ISVALID_PARAM(scan_interval, BTM_BLE_SCAN_INT_MIN, BTM_BLE_SCAN_INT_MAX) || + BTM_BLE_ISVALID_PARAM(scan_window, BTM_BLE_SCAN_WIN_MIN, BTM_BLE_SCAN_WIN_MAX)) + && (BTM_BLE_BATCH_SCAN_MODE_PASS == scan_mode || BTM_BLE_BATCH_SCAN_MODE_ACTI == scan_mode + || BTM_BLE_BATCH_SCAN_MODE_PASS_ACTI == scan_mode) + && (BTM_BLE_DISCARD_OLD_ITEMS == discard_rule || + BTM_BLE_DISCARD_LOWER_RSSI_ITEMS == discard_rule)) + { + if (BTM_BLE_SCAN_INVALID_STATE == ble_batchscan_cb.cur_state || + BTM_BLE_SCAN_DISABLED_STATE == ble_batchscan_cb.cur_state || + BTM_BLE_SCAN_DISABLE_CALLED == ble_batchscan_cb.cur_state) + { + status = btm_ble_enable_disable_batchscan(TRUE); + if (BTM_CMD_STARTED != status) + return status; + btm_ble_batchscan_enq_op_q(BTM_BLE_BATCH_SCAN_ENB_DISAB_CUST_FEATURE, + BTM_BLE_SCAN_ENABLE_CALLED, 0, ref_value); + } + + ble_batchscan_cb.scan_mode = scan_mode; + ble_batchscan_cb.scan_interval = scan_interval; + ble_batchscan_cb.scan_window = scan_window; + ble_batchscan_cb.addr_type = addr_type; + ble_batchscan_cb.discard_rule = discard_rule; + /* This command starts batch scanning, if enabled */ + status = btm_ble_set_batchscan_param(scan_mode, scan_interval, scan_window, addr_type, + discard_rule); + if (BTM_CMD_STARTED != status) + return status; + + /* The user needs to be provided scan enable event */ + btm_ble_batchscan_enq_op_q(BTM_BLE_BATCH_SCAN_SET_PARAMS, ble_batchscan_cb.cur_state, + BTM_BLE_BATCH_SCAN_ENABLE_EVT, ref_value); + } + else + { + BTM_TRACE_ERROR("Illegal enable scan params"); + return BTM_ILLEGAL_VALUE; + } + return status; +} + +/******************************************************************************* +** +** Function BTM_BleDisableBatchScan +** +** Description This function is called to disable batch scanning +** +** Parameters: ref_value - Reference value +** +** Returns tBTM_STATUS +** +*******************************************************************************/ +tBTM_STATUS BTM_BleDisableBatchScan(tBTM_BLE_REF_VALUE ref_value) +{ + tBTM_STATUS status = BTM_NO_RESOURCES; + tBTM_BLE_VSC_CB cmn_ble_vsc_cb; + BTM_TRACE_EVENT (" BTM_BleDisableBatchScan"); + + if (!controller_get_interface()->supports_ble()) + return BTM_ILLEGAL_VALUE; + + BTM_BleGetVendorCapabilities(&cmn_ble_vsc_cb); + + if (0 == cmn_ble_vsc_cb.tot_scan_results_strg) + { + BTM_TRACE_ERROR("Controller does not support batch scan"); + return BTM_ERR_PROCESSING; + } + + status = btm_ble_enable_disable_batchscan(FALSE); + if (BTM_CMD_STARTED == status) + { + /* The user needs to be provided scan disable event */ + btm_ble_batchscan_enq_op_q(BTM_BLE_BATCH_SCAN_SET_PARAMS, + BTM_BLE_SCAN_DISABLE_CALLED, BTM_BLE_BATCH_SCAN_DISABLE_EVT, + ref_value); + } + + return status; +} + +/******************************************************************************* +** +** Function BTM_BleReadScanReports +** +** Description This function is called to start reading batch scan reports +** +** Parameters: scan_mode - Batch scan mode +** ref_value - Reference value +** +** Returns tBTM_STATUS +** +*******************************************************************************/ +tBTM_STATUS BTM_BleReadScanReports(tBTM_BLE_BATCH_SCAN_MODE scan_mode, + tBTM_BLE_REF_VALUE ref_value) +{ + tBTM_STATUS status = BTM_NO_RESOURCES; + tBTM_BLE_VSC_CB cmn_ble_vsc_cb; + UINT8 read_scan_mode = 0; + UINT8 *p_data = NULL, num_records = 0; + UINT16 data_len = 0; + + BTM_TRACE_EVENT (" BTM_BleReadScanReports; %d, %d", scan_mode, ref_value); + + if (!controller_get_interface()->supports_ble()) + return BTM_ILLEGAL_VALUE; + + BTM_BleGetVendorCapabilities(&cmn_ble_vsc_cb); + + if (0 == cmn_ble_vsc_cb.tot_scan_results_strg) + { + BTM_TRACE_ERROR("Controller does not support batch scan"); + return BTM_ERR_PROCESSING; + } + + /* Check if the requested scan mode has already been setup by the user */ + read_scan_mode = ble_batchscan_cb.scan_mode & BTM_BLE_BATCH_SCAN_MODE_ACTI; + if (0 == read_scan_mode) + read_scan_mode = ble_batchscan_cb.scan_mode & BTM_BLE_BATCH_SCAN_MODE_PASS; + + /* Check only for modes, as scan reports can be called after disabling batch scan */ + if (read_scan_mode > 0 && (BTM_BLE_BATCH_SCAN_MODE_PASS == scan_mode || + BTM_BLE_BATCH_SCAN_MODE_ACTI == scan_mode)) + { + status = btm_ble_batchscan_enq_rep_q(scan_mode, ref_value); + if (BTM_SUCCESS == status) + { + status = btm_ble_read_batchscan_reports(scan_mode, ref_value); + if (BTM_CMD_STARTED != status) + { + btm_ble_batchscan_deq_rep_data(scan_mode, &ref_value, + &num_records, &p_data, &data_len); + } + } + } + else + { + BTM_TRACE_ERROR("Illegal read scan params: %d, %d, %d", read_scan_mode, scan_mode, + ble_batchscan_cb.cur_state); + return BTM_ILLEGAL_VALUE; + } + return status; +} + + +/******************************************************************************* +** +** Function BTM_BleTrackAdvertiser +** +** Description This function is called to setup the callback for tracking advertisers +** +** Parameters: p_track_cback - Tracking callback pointer +** ref_value - Reference value +** +** Returns tBTM_STATUS +** +*******************************************************************************/ +tBTM_STATUS BTM_BleTrackAdvertiser(tBTM_BLE_TRACK_ADV_CBACK *p_track_cback, + tBTM_BLE_REF_VALUE ref_value) +{ + tBTM_BLE_VSC_CB cmn_ble_vsc_cb; + BTM_TRACE_EVENT (" BTM_BleTrackAdvertiser"); + if (!controller_get_interface()->supports_ble()) + return BTM_ILLEGAL_VALUE; + + BTM_BleGetVendorCapabilities(&cmn_ble_vsc_cb); + + if (0 == cmn_ble_vsc_cb.tot_scan_results_strg) + { + BTM_TRACE_ERROR("Controller does not support scan storage"); + return BTM_ERR_PROCESSING; + } + + ble_advtrack_cb.p_track_cback = p_track_cback; + ble_advtrack_cb.ref_value = ref_value; + return BTM_CMD_STARTED; +} + +/******************************************************************************* +** +** Function btm_ble_batchscan_init +** +** Description This function initialize the batch scan control block. +** +** Parameters None +** +** Returns status +** +*******************************************************************************/ +void btm_ble_batchscan_init(void) +{ + BTM_TRACE_EVENT (" btm_ble_batchscan_init"); + memset(&ble_batchscan_cb, 0, sizeof(tBTM_BLE_BATCH_SCAN_CB)); + memset(&ble_advtrack_cb, 0, sizeof(tBTM_BLE_ADV_TRACK_CB)); + BTM_RegisterForVSEvents(btm_ble_batchscan_filter_track_adv_vse_cback, TRUE); +} + +/******************************************************************************* +** +** Function btm_ble_batchscan_cleanup +** +** Description This function cleans the batch scan control block. +** +** Parameters None +** +** Returns void +** +*******************************************************************************/ +void btm_ble_batchscan_cleanup(void) +{ + int index = 0; + BTM_TRACE_EVENT (" btm_ble_batchscan_cleanup"); + + for (index = 0; index < BTM_BLE_BATCH_REP_MAIN_Q_SIZE; index++) + { + if (NULL != ble_batchscan_cb.main_rep_q.p_data[index]) + GKI_freebuf(ble_batchscan_cb.main_rep_q.p_data[index]); + ble_batchscan_cb.main_rep_q.p_data[index] = NULL; + } + + memset(&ble_batchscan_cb, 0, sizeof(tBTM_BLE_BATCH_SCAN_CB)); + memset(&ble_advtrack_cb, 0, sizeof(tBTM_BLE_ADV_TRACK_CB)); +} + +#endif diff --git a/components/bt/bluedroid/stack/btm/btm_ble_bgconn.c b/components/bt/bluedroid/stack/btm/btm_ble_bgconn.c new file mode 100755 index 0000000000..b24eee4735 --- /dev/null +++ b/components/bt/bluedroid/stack/btm/btm_ble_bgconn.c @@ -0,0 +1,742 @@ +/****************************************************************************** + * + * Copyright (C) 1999-2012 Broadcom Corporation + * + * 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 functions for BLE whitelist operation. + * + ******************************************************************************/ + +#include +#include "bt_trace.h" +#include "controller.h" +#include "allocator.h" +#include "hash_map.h" +#include "bt_types.h" +#include "btu.h" +#include "btm_int.h" +#include "l2c_int.h" +#include "hcimsgs.h" +//#include "bt_utils.h" + +#ifndef BTM_BLE_SCAN_PARAM_TOUT +#define BTM_BLE_SCAN_PARAM_TOUT 50 /* 50 seconds */ +#endif + +#if (BLE_INCLUDED == TRUE) + +static void btm_suspend_wl_activity(tBTM_BLE_WL_STATE wl_state); +static void btm_resume_wl_activity(tBTM_BLE_WL_STATE wl_state); + +// Unfortunately (for now?) we have to maintain a copy of the device whitelist +// on the host to determine if a device is pending to be connected or not. This +// controls whether the host should keep trying to scan for whitelisted +// peripherals or not. +// TODO: Move all of this to controller/le/background_list or similar? +static const size_t background_connection_buckets = 42; +static hash_map_t *background_connections = NULL; + +typedef struct background_connection_t { + bt_bdaddr_t address; +} background_connection_t; + +static bool bdaddr_equality_fn(const void *x, const void *y) { + return bdaddr_equals((bt_bdaddr_t *)x, (bt_bdaddr_t *)y); +} + +static void background_connections_lazy_init() +{ + if (!background_connections) { + background_connections = hash_map_new(background_connection_buckets, + hash_function_bdaddr, NULL, osi_free, bdaddr_equality_fn); + assert(background_connections); + } +} + +static void background_connection_add(bt_bdaddr_t *address) { + assert(address); + background_connections_lazy_init(); + background_connection_t *connection = hash_map_get(background_connections, address); + if (!connection) { + connection = osi_calloc(sizeof(background_connection_t)); + connection->address = *address; + hash_map_set(background_connections, &(connection->address), connection); + } +} + +static void background_connection_remove(bt_bdaddr_t *address) { + if (address && background_connections) + hash_map_erase(background_connections, address); +} + +static void background_connections_clear() { + if (background_connections) + hash_map_clear(background_connections); +} + +static bool background_connections_pending_cb(hash_map_entry_t *hash_entry, void *context) { + bool *pending_connections = context; + background_connection_t *connection = hash_entry->data; + const bool connected = BTM_IsAclConnectionUp(connection->address.address, BT_TRANSPORT_LE); + if (!connected) { + *pending_connections = true; + return false; + } + return true; +} + +static bool background_connections_pending() { + bool pending_connections = false; + if (background_connections) + hash_map_foreach(background_connections, background_connections_pending_cb, &pending_connections); + return pending_connections; +} + +/******************************************************************************* +** +** Function btm_update_scanner_filter_policy +** +** Description This function updates the filter policy of scanner +*******************************************************************************/ +void btm_update_scanner_filter_policy(tBTM_BLE_SFP scan_policy) +{ + tBTM_BLE_INQ_CB *p_inq = &btm_cb.ble_ctr_cb.inq_var; + + UINT32 scan_interval = !p_inq->scan_interval ? BTM_BLE_GAP_DISC_SCAN_INT : p_inq->scan_interval; + UINT32 scan_window = !p_inq->scan_window ? BTM_BLE_GAP_DISC_SCAN_WIN : p_inq->scan_window; + + BTM_TRACE_EVENT ("%s", __func__); + + p_inq->sfp = scan_policy; + p_inq->scan_type = p_inq->scan_type == BTM_BLE_SCAN_MODE_NONE ? BTM_BLE_SCAN_MODE_ACTI : p_inq->scan_type; + + if (btm_cb.cmn_ble_vsc_cb.extended_scan_support == 0) + { + btsnd_hcic_ble_set_scan_params(p_inq->scan_type, (UINT16)scan_interval, + (UINT16)scan_window, + btm_cb.ble_ctr_cb.addr_mgnt_cb.own_addr_type, + scan_policy); + } + else + { + btm_ble_send_extended_scan_params(p_inq->scan_type, scan_interval, scan_window, + btm_cb.ble_ctr_cb.addr_mgnt_cb.own_addr_type, + scan_policy); + } +} +/******************************************************************************* +** +** Function btm_add_dev_to_controller +** +** Description This function load the device into controller white list +*******************************************************************************/ +BOOLEAN btm_add_dev_to_controller (BOOLEAN to_add, BD_ADDR bd_addr) +{ + tBTM_SEC_DEV_REC *p_dev_rec = btm_find_dev (bd_addr); + tBLE_ADDR_TYPE addr_type = BLE_ADDR_PUBLIC; + BOOLEAN started = FALSE; + BD_ADDR dummy_bda = {0}; + tBT_DEVICE_TYPE dev_type; + + if (p_dev_rec != NULL && + p_dev_rec->device_type & BT_DEVICE_TYPE_BLE) + { + if (to_add) + { + if (p_dev_rec->ble.ble_addr_type == BLE_ADDR_PUBLIC || !BTM_BLE_IS_RESOLVE_BDA(bd_addr)) + { + started = btsnd_hcic_ble_add_white_list (p_dev_rec->ble.ble_addr_type, bd_addr); + p_dev_rec->ble.in_controller_list |= BTM_WHITE_LIST_BIT; + } + else if (memcmp(p_dev_rec->ble.static_addr, bd_addr, BD_ADDR_LEN) != 0 && + memcmp(p_dev_rec->ble.static_addr, dummy_bda, BD_ADDR_LEN) != 0) + { + started = btsnd_hcic_ble_add_white_list (p_dev_rec->ble.static_addr_type, + p_dev_rec->ble.static_addr); + p_dev_rec->ble.in_controller_list |= BTM_WHITE_LIST_BIT; + } + } + else + { + if (p_dev_rec->ble.ble_addr_type == BLE_ADDR_PUBLIC || !BTM_BLE_IS_RESOLVE_BDA(bd_addr)) + { + started = btsnd_hcic_ble_remove_from_white_list (p_dev_rec->ble.ble_addr_type, bd_addr); + } + if (memcmp(p_dev_rec->ble.static_addr, dummy_bda, BD_ADDR_LEN) != 0 && + memcmp(p_dev_rec->ble.static_addr, bd_addr, BD_ADDR_LEN) != 0) + { + started = btsnd_hcic_ble_remove_from_white_list (p_dev_rec->ble.static_addr_type, p_dev_rec->ble.static_addr); + } + p_dev_rec->ble.in_controller_list &= ~BTM_WHITE_LIST_BIT; + } + } /* if not a known device, shall we add it? */ + else + { + BTM_ReadDevInfo(bd_addr, &dev_type, &addr_type); + + started = btsnd_hcic_ble_remove_from_white_list (addr_type, bd_addr); + if (to_add) + started = btsnd_hcic_ble_add_white_list (addr_type, bd_addr); + } + + return started; + +} +/******************************************************************************* +** +** Function btm_execute_wl_dev_operation +** +** Description execute the pending whitelist device operation(loading or removing) +*******************************************************************************/ +BOOLEAN btm_execute_wl_dev_operation(void) +{ + tBTM_BLE_WL_OP *p_dev_op = btm_cb.ble_ctr_cb.wl_op_q; + UINT8 i = 0; + BOOLEAN rt = TRUE; + + for (i = 0; i < BTM_BLE_MAX_BG_CONN_DEV_NUM && rt; i ++, p_dev_op ++) + { + if (p_dev_op->in_use) + { + rt = btm_add_dev_to_controller(p_dev_op->to_add, p_dev_op->bd_addr); + memset(p_dev_op, 0, sizeof(tBTM_BLE_WL_OP)); + } + else + break; + } + return rt; +} +/******************************************************************************* +** +** Function btm_enq_wl_dev_operation +** +** Description enqueue the pending whitelist device operation(loading or removing). +*******************************************************************************/ +void btm_enq_wl_dev_operation(BOOLEAN to_add, BD_ADDR bd_addr) +{ + tBTM_BLE_WL_OP *p_dev_op = btm_cb.ble_ctr_cb.wl_op_q; + UINT8 i = 0; + + for (i = 0; i < BTM_BLE_MAX_BG_CONN_DEV_NUM; i ++, p_dev_op ++) + { + if (p_dev_op->in_use && !memcmp(p_dev_op->bd_addr, bd_addr, BD_ADDR_LEN)) + { + p_dev_op->to_add = to_add; + return; + } + else if (!p_dev_op->in_use) + break; + } + if (i != BTM_BLE_MAX_BG_CONN_DEV_NUM) + { + p_dev_op->in_use = TRUE; + p_dev_op->to_add = to_add; + memcpy(p_dev_op->bd_addr, bd_addr, BD_ADDR_LEN); + } + else + { + BTM_TRACE_ERROR("max pending WL operation reached, discard"); + } + return; +} + +/******************************************************************************* +** +** Function btm_update_dev_to_white_list +** +** Description This function adds or removes a device into/from +** the white list. +** +*******************************************************************************/ +BOOLEAN btm_update_dev_to_white_list(BOOLEAN to_add, BD_ADDR bd_addr) +{ + tBTM_BLE_CB *p_cb = &btm_cb.ble_ctr_cb; + + if (to_add && p_cb->white_list_avail_size == 0) + { + BTM_TRACE_ERROR("%s Whitelist full, unable to add device", __func__); + return FALSE; + } + + if (to_add) + background_connection_add((bt_bdaddr_t*)bd_addr); + else + background_connection_remove((bt_bdaddr_t*)bd_addr); + + btm_suspend_wl_activity(p_cb->wl_state); + btm_enq_wl_dev_operation(to_add, bd_addr); + btm_resume_wl_activity(p_cb->wl_state); + return TRUE; +} + +/******************************************************************************* +** +** Function btm_ble_clear_white_list +** +** Description This function clears the white list. +** +*******************************************************************************/ +void btm_ble_clear_white_list (void) +{ + BTM_TRACE_EVENT ("btm_ble_clear_white_list"); + btsnd_hcic_ble_clear_white_list(); + background_connections_clear(); +} + +/******************************************************************************* +** +** Function btm_ble_clear_white_list_complete +** +** Description Indicates white list cleared. +** +*******************************************************************************/ +void btm_ble_clear_white_list_complete(UINT8 *p_data, UINT16 evt_len) +{ + tBTM_BLE_CB *p_cb = &btm_cb.ble_ctr_cb; + UINT8 status; + UNUSED(evt_len); + + BTM_TRACE_EVENT ("btm_ble_clear_white_list_complete"); + STREAM_TO_UINT8 (status, p_data); + + if (status == HCI_SUCCESS) + p_cb->white_list_avail_size = controller_get_interface()->get_ble_white_list_size(); +} + +/******************************************************************************* +** +** Function btm_ble_white_list_init +** +** Description Initialize white list size +** +*******************************************************************************/ +void btm_ble_white_list_init(UINT8 white_list_size) +{ + BTM_TRACE_DEBUG("%s white_list_size = %d", __func__, white_list_size); + btm_cb.ble_ctr_cb.white_list_avail_size = white_list_size; +} + +/******************************************************************************* +** +** Function btm_ble_add_2_white_list_complete +** +** Description White list element added +** +*******************************************************************************/ +void btm_ble_add_2_white_list_complete(UINT8 status) +{ + BTM_TRACE_EVENT("%s status=%d", __func__, status); + if (status == HCI_SUCCESS) + --btm_cb.ble_ctr_cb.white_list_avail_size; +} + +/******************************************************************************* +** +** Function btm_ble_remove_from_white_list_complete +** +** Description White list element removal complete +** +*******************************************************************************/ +void btm_ble_remove_from_white_list_complete(UINT8 *p, UINT16 evt_len) +{ + UNUSED(evt_len); + BTM_TRACE_EVENT ("%s status=%d", __func__, *p); + if (*p == HCI_SUCCESS) + ++btm_cb.ble_ctr_cb.white_list_avail_size; +} + +/******************************************************************************* +** +** Function btm_ble_start_auto_conn +** +** Description This function is to start/stop auto connection procedure. +** +** Parameters start: TRUE to start; FALSE to stop. +** +** Returns void +** +*******************************************************************************/ +BOOLEAN btm_ble_start_auto_conn(BOOLEAN start) +{ + tBTM_BLE_CB *p_cb = &btm_cb.ble_ctr_cb; + BD_ADDR dummy_bda = {0}; + BOOLEAN exec = TRUE; + UINT16 scan_int; + UINT16 scan_win; + UINT8 own_addr_type = p_cb->addr_mgnt_cb.own_addr_type; + UINT8 peer_addr_type = BLE_ADDR_PUBLIC; + + if (start) + { + if (p_cb->conn_state == BLE_CONN_IDLE && background_connections_pending() + && btm_ble_topology_check(BTM_BLE_STATE_INIT)) + { + p_cb->wl_state |= BTM_BLE_WL_INIT; + + btm_execute_wl_dev_operation(); + +#if BLE_PRIVACY_SPT == TRUE + btm_ble_enable_resolving_list_for_platform(BTM_BLE_RL_INIT); +#endif + scan_int = (p_cb->scan_int == BTM_BLE_SCAN_PARAM_UNDEF) ? + BTM_BLE_SCAN_SLOW_INT_1 : p_cb->scan_int; + scan_win = (p_cb->scan_win == BTM_BLE_SCAN_PARAM_UNDEF) ? + BTM_BLE_SCAN_SLOW_WIN_1 : p_cb->scan_win; + +#if BLE_PRIVACY_SPT == TRUE + if (btm_cb.ble_ctr_cb.rl_state != BTM_BLE_RL_IDLE + && controller_get_interface()->supports_ble_privacy()) + { + own_addr_type |= BLE_ADDR_TYPE_ID_BIT; + peer_addr_type |= BLE_ADDR_TYPE_ID_BIT; + } +#endif + + if (!btsnd_hcic_ble_create_ll_conn (scan_int, /* UINT16 scan_int */ + scan_win, /* UINT16 scan_win */ + 0x01, /* UINT8 white_list */ + peer_addr_type, /* UINT8 addr_type_peer */ + dummy_bda, /* BD_ADDR bda_peer */ + own_addr_type, /* UINT8 addr_type_own */ + BTM_BLE_CONN_INT_MIN_DEF, /* UINT16 conn_int_min */ + BTM_BLE_CONN_INT_MAX_DEF, /* UINT16 conn_int_max */ + BTM_BLE_CONN_SLAVE_LATENCY_DEF, /* UINT16 conn_latency */ + BTM_BLE_CONN_TIMEOUT_DEF, /* UINT16 conn_timeout */ + 0, /* UINT16 min_len */ + 0)) /* UINT16 max_len */ + { + /* start auto connection failed */ + exec = FALSE; + p_cb->wl_state &= ~BTM_BLE_WL_INIT; + } + else + { + btm_ble_set_conn_st (BLE_BG_CONN); + } + } + else + { + exec = FALSE; + } + } + else + { + if (p_cb->conn_state == BLE_BG_CONN) + { + btsnd_hcic_ble_create_conn_cancel(); + btm_ble_set_conn_st (BLE_CONN_CANCEL); + p_cb->wl_state &= ~BTM_BLE_WL_INIT; + } + else + { + BTM_TRACE_DEBUG("conn_st = %d, not in auto conn state, cannot stop", p_cb->conn_state); + exec = FALSE; + } + } + return exec; +} + +/******************************************************************************* +** +** Function btm_ble_start_select_conn +** +** Description This function is to start/stop selective connection procedure. +** +** Parameters start: TRUE to start; FALSE to stop. +** p_select_cback: callback function to return application +** selection. +** +** Returns BOOLEAN: selective connectino procedure is started. +** +*******************************************************************************/ +BOOLEAN btm_ble_start_select_conn(BOOLEAN start, tBTM_BLE_SEL_CBACK *p_select_cback) +{ + tBTM_BLE_CB *p_cb = &btm_cb.ble_ctr_cb; + UINT32 scan_int = p_cb->scan_int == BTM_BLE_SCAN_PARAM_UNDEF ? BTM_BLE_SCAN_FAST_INT : p_cb->scan_int; + UINT32 scan_win = p_cb->scan_win == BTM_BLE_SCAN_PARAM_UNDEF ? BTM_BLE_SCAN_FAST_WIN : p_cb->scan_win; + + BTM_TRACE_EVENT ("%s", __func__); + + if (start) + { + if (!BTM_BLE_IS_SCAN_ACTIVE(p_cb->scan_activity)) + { + if (p_select_cback != NULL) + btm_cb.ble_ctr_cb.p_select_cback = p_select_cback; + + btm_execute_wl_dev_operation(); + + btm_update_scanner_filter_policy(SP_ADV_WL); + btm_cb.ble_ctr_cb.inq_var.scan_type = BTM_BLE_SCAN_MODE_PASS; + + /* Process advertising packets only from devices in the white list */ + if (btm_cb.cmn_ble_vsc_cb.extended_scan_support == 0) + { + /* use passive scan by default */ + if (!btsnd_hcic_ble_set_scan_params(BTM_BLE_SCAN_MODE_PASS, + scan_int, + scan_win, + p_cb->addr_mgnt_cb.own_addr_type, + SP_ADV_WL)) + { + return FALSE; + } + } + else + { + if (!btm_ble_send_extended_scan_params(BTM_BLE_SCAN_MODE_PASS, + scan_int, + scan_win, + p_cb->addr_mgnt_cb.own_addr_type, + SP_ADV_WL)) + { + return FALSE; + } + } + + if (!btm_ble_topology_check(BTM_BLE_STATE_PASSIVE_SCAN)) + { + BTM_TRACE_ERROR("peripheral device cannot initiate passive scan for a selective connection"); + return FALSE; + } + else if (background_connections_pending()) + { +#if BLE_PRIVACY_SPT == TRUE + btm_ble_enable_resolving_list_for_platform(BTM_BLE_RL_SCAN); +#endif + if (!btsnd_hcic_ble_set_scan_enable(TRUE, TRUE)) /* duplicate filtering enabled */ + return FALSE; + /* mark up inquiry status flag */ + p_cb->scan_activity |= BTM_LE_SELECT_CONN_ACTIVE; + p_cb->wl_state |= BTM_BLE_WL_SCAN; + } + } + else + { + BTM_TRACE_ERROR("scan active, can not start selective connection procedure"); + return FALSE; + } + } + else /* disable selective connection mode */ + { + p_cb->scan_activity &= ~BTM_LE_SELECT_CONN_ACTIVE; + p_cb->p_select_cback = NULL; + p_cb->wl_state &= ~BTM_BLE_WL_SCAN; + + /* stop scanning */ + if (!BTM_BLE_IS_SCAN_ACTIVE(p_cb->scan_activity)) + btm_ble_stop_scan(); /* duplicate filtering enabled */ + } + return TRUE; +} +/******************************************************************************* +** +** Function btm_ble_initiate_select_conn +** +** Description This function is to start/stop selective connection procedure. +** +** Parameters start: TRUE to start; FALSE to stop. +** p_select_cback: callback function to return application +** selection. +** +** Returns BOOLEAN: selective connectino procedure is started. +** +*******************************************************************************/ +void btm_ble_initiate_select_conn(BD_ADDR bda) +{ + BTM_TRACE_EVENT ("btm_ble_initiate_select_conn"); + + /* use direct connection procedure to initiate connection */ + if (!L2CA_ConnectFixedChnl(L2CAP_ATT_CID, bda)) + { + BTM_TRACE_ERROR("btm_ble_initiate_select_conn failed"); + } +} +/******************************************************************************* +** +** Function btm_ble_suspend_bg_conn +** +** Description This function is to suspend an active background connection +** procedure. +** +** Parameters none. +** +** Returns none. +** +*******************************************************************************/ +BOOLEAN btm_ble_suspend_bg_conn(void) +{ + BTM_TRACE_EVENT ("%s", __func__); + + if (btm_cb.ble_ctr_cb.bg_conn_type == BTM_BLE_CONN_AUTO) + return btm_ble_start_auto_conn(FALSE); + else if (btm_cb.ble_ctr_cb.bg_conn_type == BTM_BLE_CONN_SELECTIVE) + return btm_ble_start_select_conn(FALSE, NULL); + + return FALSE; +} +/******************************************************************************* +** +** Function btm_suspend_wl_activity +** +** Description This function is to suspend white list related activity +** +** Returns none. +** +*******************************************************************************/ +static void btm_suspend_wl_activity(tBTM_BLE_WL_STATE wl_state) +{ + if (wl_state & BTM_BLE_WL_INIT) + { + btm_ble_start_auto_conn(FALSE); + } + if (wl_state & BTM_BLE_WL_SCAN) + { + btm_ble_start_select_conn(FALSE, NULL); + } + if (wl_state & BTM_BLE_WL_ADV) + { + btm_ble_stop_adv(); + } + +} +/******************************************************************************* +** +** Function btm_resume_wl_activity +** +** Description This function is to resume white list related activity +** +** Returns none. +** +*******************************************************************************/ +static void btm_resume_wl_activity(tBTM_BLE_WL_STATE wl_state) +{ + btm_ble_resume_bg_conn(); + + if (wl_state & BTM_BLE_WL_ADV) + { + btm_ble_start_adv(); + } + +} +/******************************************************************************* +** +** Function btm_ble_resume_bg_conn +** +** Description This function is to resume a background auto connection +** procedure. +** +** Parameters none. +** +** Returns none. +** +*******************************************************************************/ +BOOLEAN btm_ble_resume_bg_conn(void) +{ + tBTM_BLE_CB *p_cb = &btm_cb.ble_ctr_cb; + BOOLEAN ret = FALSE; + + if (p_cb->bg_conn_type != BTM_BLE_CONN_NONE) + { + if (p_cb->bg_conn_type == BTM_BLE_CONN_AUTO) + ret = btm_ble_start_auto_conn(TRUE); + + if (p_cb->bg_conn_type == BTM_BLE_CONN_SELECTIVE) + ret = btm_ble_start_select_conn(TRUE, btm_cb.ble_ctr_cb.p_select_cback); + } + + return ret; +} +/******************************************************************************* +** +** Function btm_ble_get_conn_st +** +** Description This function get BLE connection state +** +** Returns connection state +** +*******************************************************************************/ +tBTM_BLE_CONN_ST btm_ble_get_conn_st(void) +{ + return btm_cb.ble_ctr_cb.conn_state; +} +/******************************************************************************* +** +** Function btm_ble_set_conn_st +** +** Description This function set BLE connection state +** +** Returns None. +** +*******************************************************************************/ +void btm_ble_set_conn_st(tBTM_BLE_CONN_ST new_st) +{ + btm_cb.ble_ctr_cb.conn_state = new_st; + + if (new_st == BLE_BG_CONN || new_st == BLE_DIR_CONN) + btm_ble_set_topology_mask(BTM_BLE_STATE_INIT_BIT); + else + btm_ble_clear_topology_mask(BTM_BLE_STATE_INIT_BIT); +} + +/******************************************************************************* +** +** Function btm_ble_enqueue_direct_conn_req +** +** Description This function enqueue the direct connection request +** +** Returns None. +** +*******************************************************************************/ +void btm_ble_enqueue_direct_conn_req(void *p_param) +{ + tBTM_BLE_CONN_REQ *p = (tBTM_BLE_CONN_REQ *)GKI_getbuf(sizeof(tBTM_BLE_CONN_REQ)); + + p->p_param = p_param; + + GKI_enqueue (&btm_cb.ble_ctr_cb.conn_pending_q, p); +} +/******************************************************************************* +** +** Function btm_send_pending_direct_conn +** +** Description This function send the pending direct connection request in queue +** +** Returns TRUE if started, FALSE otherwise +** +*******************************************************************************/ +BOOLEAN btm_send_pending_direct_conn(void) +{ + tBTM_BLE_CONN_REQ *p_req; + BOOLEAN rt = FALSE; + + if (!GKI_queue_is_empty(&btm_cb.ble_ctr_cb.conn_pending_q)) + { + p_req = (tBTM_BLE_CONN_REQ*)GKI_dequeue (&btm_cb.ble_ctr_cb.conn_pending_q); + + rt = l2cble_init_direct_conn((tL2C_LCB *)(p_req->p_param)); + + GKI_freebuf((void *)p_req); + } + + return rt; +} + +#endif + + diff --git a/components/bt/bluedroid/stack/btm/btm_ble_cont_energy.c b/components/bt/bluedroid/stack/btm/btm_ble_cont_energy.c new file mode 100755 index 0000000000..7116582b42 --- /dev/null +++ b/components/bt/bluedroid/stack/btm/btm_ble_cont_energy.c @@ -0,0 +1,111 @@ +/****************************************************************************** + * + * Copyright (C) 2014 Broadcom Corporation + * + * 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. + * + ******************************************************************************/ + +#include +#include "bt_target.h" + +#if (BLE_INCLUDED == TRUE) +#include "bt_types.h" +#include "hcimsgs.h" +#include "btu.h" +#include "btm_int.h" +//#include "bt_utils.h" +#include "hcidefs.h" +#include "btm_ble_api.h" + +tBTM_BLE_ENERGY_INFO_CB ble_energy_info_cb; + +/******************************************************************************* +** +** Function btm_ble_cont_energy_cmpl_cback +** +** Description Controller VSC complete callback +** +** Parameters +** +** Returns void +** +*******************************************************************************/ +void btm_ble_cont_energy_cmpl_cback (tBTM_VSC_CMPL *p_params) +{ + UINT8 *p = p_params->p_param_buf; + UINT16 len = p_params->param_len; + UINT8 status = 0; + UINT32 total_tx_time = 0, total_rx_time = 0, total_idle_time = 0, total_energy_used = 0; + + if (len < 17) + { + BTM_TRACE_ERROR("wrong length for btm_ble_cont_energy_cmpl_cback"); + return; + } + + STREAM_TO_UINT8(status, p); + STREAM_TO_UINT32(total_tx_time, p); + STREAM_TO_UINT32(total_rx_time, p); + STREAM_TO_UINT32(total_idle_time, p); + STREAM_TO_UINT32(total_energy_used, p); + + BTM_TRACE_DEBUG("energy_info status=%d,tx_t=%ld, rx_t=%ld, ener_used=%ld, idle_t=%ld", + status, total_tx_time, total_rx_time, total_energy_used, total_idle_time); + + if (NULL != ble_energy_info_cb.p_ener_cback) + ble_energy_info_cb.p_ener_cback(total_tx_time, total_rx_time, total_idle_time, + total_energy_used, status); + + return; +} + +/******************************************************************************* +** +** Function BTM_BleGetEnergyInfo +** +** Description This function obtains the energy info +** +** Parameters p_ener_cback - Callback pointer +** +** Returns status +** +*******************************************************************************/ +tBTM_STATUS BTM_BleGetEnergyInfo(tBTM_BLE_ENERGY_INFO_CBACK *p_ener_cback) +{ + tBTM_STATUS status = BTM_ILLEGAL_VALUE; + tBTM_BLE_VSC_CB cmn_ble_vsc_cb; + + BTM_BleGetVendorCapabilities(&cmn_ble_vsc_cb); + + BTM_TRACE_EVENT("BTM_BleGetEnergyInfo"); + + if (0 == cmn_ble_vsc_cb.energy_support) + { + BTM_TRACE_ERROR("Controller does not support get energy info"); + return BTM_ERR_PROCESSING; + } + + ble_energy_info_cb.p_ener_cback = p_ener_cback; + if ((status = BTM_VendorSpecificCommand (HCI_BLE_ENERGY_INFO_OCF, 0, NULL, + btm_ble_cont_energy_cmpl_cback)) != BTM_CMD_STARTED) + { + BTM_TRACE_ERROR("BTM_BleGetEnergyInfo status: %d", status); + return BTM_ILLEGAL_VALUE; + } + + return status; +} + +#endif + diff --git a/components/bt/bluedroid/stack/btm/btm_ble_gap.c b/components/bt/bluedroid/stack/btm/btm_ble_gap.c new file mode 100755 index 0000000000..a12e074bac --- /dev/null +++ b/components/bt/bluedroid/stack/btm/btm_ble_gap.c @@ -0,0 +1,3514 @@ +/****************************************************************************** + * + * Copyright (C) 2008-2014 Broadcom Corporation + * + * 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 functions for BLE GAP. + * + ******************************************************************************/ + +#include +//#include +#include + +#include "bt_types.h" +//#include "bt_utils.h" +#include "btm_int.h" +#include "btm_ble_api.h" +#include "btu.h" +#include "controller.h" +#include "hcimsgs.h" +#include "gap_api.h" + +#if BLE_INCLUDED == TRUE +#include "l2c_int.h" + +#include "gattdefs.h" +#include "gatt_int.h" + +#include "btm_ble_int.h" +//#define LOG_TAG "bt_btm_ble" +//#include "osi/include/log.h" + +#define BTM_BLE_NAME_SHORT 0x01 +#define BTM_BLE_NAME_CMPL 0x02 + +#define BTM_BLE_FILTER_TARGET_UNKNOWN 0xff +#define BTM_BLE_POLICY_UNKNOWN 0xff + +#define BTM_EXT_BLE_RMT_NAME_TIMEOUT 30 +#define MIN_ADV_LENGTH 2 +#define BTM_VSC_CHIP_CAPABILITY_RSP_LEN_L_RELEASE 9 + +static tBTM_BLE_VSC_CB cmn_ble_vsc_cb; + +#if BLE_VND_INCLUDED == TRUE +static tBTM_BLE_CTRL_FEATURES_CBACK *p_ctrl_le_feature_rd_cmpl_cback = NULL; +#endif + +/******************************************************************************* +** Local functions +*******************************************************************************/ +static void btm_ble_update_adv_flag(UINT8 flag); +static void btm_ble_process_adv_pkt_cont(BD_ADDR bda, UINT8 addr_type, UINT8 evt_type, UINT8 *p); +UINT8 *btm_ble_build_adv_data(tBTM_BLE_AD_MASK *p_data_mask, UINT8 **p_dst, + tBTM_BLE_ADV_DATA *p_data); +static UINT8 btm_set_conn_mode_adv_init_addr(tBTM_BLE_INQ_CB *p_cb, + BD_ADDR_PTR p_peer_addr_ptr, + tBLE_ADDR_TYPE *p_peer_addr_type, + tBLE_ADDR_TYPE *p_own_addr_type); +static void btm_ble_stop_observe(void); + +#define BTM_BLE_INQ_RESULT 0x01 +#define BTM_BLE_OBS_RESULT 0x02 +#define BTM_BLE_SEL_CONN_RESULT 0x04 + +/* LE states combo bit to check */ +const UINT8 btm_le_state_combo_tbl[BTM_BLE_STATE_MAX][BTM_BLE_STATE_MAX][2] = +{ + {/* single state support */ + {HCI_SUPP_LE_STATES_CONN_ADV_MASK, HCI_SUPP_LE_STATES_CONN_ADV_OFF}, /* conn_adv */ + {HCI_SUPP_LE_STATES_INIT_MASK, HCI_SUPP_LE_STATES_INIT_OFF}, /* init */ + {HCI_SUPP_LE_STATES_INIT_MASK, HCI_SUPP_LE_STATES_INIT_OFF}, /* master */ + {HCI_SUPP_LE_STATES_SLAVE_MASK, HCI_SUPP_LE_STATES_SLAVE_OFF}, /* slave */ + {0, 0}, /* todo: lo du dir adv, not covered ? */ + {HCI_SUPP_LE_STATES_HI_DUTY_DIR_ADV_MASK, HCI_SUPP_LE_STATES_HI_DUTY_DIR_ADV_OFF}, /* hi duty dir adv */ + {HCI_SUPP_LE_STATES_NON_CONN_ADV_MASK, HCI_SUPP_LE_STATES_NON_CONN_ADV_OFF}, /* non connectable adv */ + {HCI_SUPP_LE_STATES_PASS_SCAN_MASK, HCI_SUPP_LE_STATES_PASS_SCAN_OFF}, /* passive scan */ + {HCI_SUPP_LE_STATES_ACTIVE_SCAN_MASK, HCI_SUPP_LE_STATES_ACTIVE_SCAN_OFF}, /* active scan */ + {HCI_SUPP_LE_STATES_SCAN_ADV_MASK, HCI_SUPP_LE_STATESSCAN_ADV_OFF} /* scanable adv */ + }, + { /* conn_adv =0 */ + {0, 0}, /* conn_adv */ + {HCI_SUPP_LE_STATES_CONN_ADV_INIT_MASK, HCI_SUPP_LE_STATES_CONN_ADV_INIT_OFF}, /* init: 32 */ + {HCI_SUPP_LE_STATES_CONN_ADV_MASTER_MASK, HCI_SUPP_LE_STATES_CONN_ADV_MASTER_OFF}, /* master: 35 */ + {HCI_SUPP_LE_STATES_CONN_ADV_SLAVE_MASK, HCI_SUPP_LE_STATES_CONN_ADV_SLAVE_OFF}, /* slave: 38,*/ + {0, 0}, /* lo du dir adv */ + {0, 0}, /* hi duty dir adv */ + {0, 0}, /* non connectable adv */ + {HCI_SUPP_LE_STATES_CONN_ADV_PASS_SCAN_MASK, HCI_SUPP_LE_STATES_CONN_ADV_PASS_SCAN_OFF}, /* passive scan */ + {HCI_SUPP_LE_STATES_CONN_ADV_ACTIVE_SCAN_MASK, HCI_SUPP_LE_STATES_CONN_ADV_ACTIVE_SCAN_OFF}, /* active scan */ + {0, 0} /* scanable adv */ + }, + { /* init */ + {HCI_SUPP_LE_STATES_CONN_ADV_INIT_MASK, HCI_SUPP_LE_STATES_CONN_ADV_INIT_OFF}, /* conn_adv: 32 */ + {0, 0}, /* init */ + {HCI_SUPP_LE_STATES_INIT_MASTER_MASK, HCI_SUPP_LE_STATES_INIT_MASTER_OFF}, /* master 28 */ + {HCI_SUPP_LE_STATES_INIT_MASTER_SLAVE_MASK, HCI_SUPP_LE_STATES_INIT_MASTER_SLAVE_OFF}, /* slave 41 */ + {HCI_SUPP_LE_STATES_LO_DUTY_DIR_ADV_INIT_MASK, HCI_SUPP_LE_STATES_LO_DUTY_DIR_ADV_INIT_OFF} ,/* lo du dir adv 34 */ + {HCI_SUPP_LE_STATES_HI_DUTY_DIR_ADV_INIT_MASK, HCI_SUPP_LE_STATES_HI_DUTY_DIR_ADV_INIT_OFF}, /* hi duty dir adv 33 */ + {HCI_SUPP_LE_STATES_NON_CONN_INIT_MASK, HCI_SUPP_LE_STATES_NON_CONN_INIT_OFF}, /* non connectable adv */ + {HCI_SUPP_LE_STATES_PASS_SCAN_INIT_MASK, HCI_SUPP_LE_STATES_PASS_SCAN_INIT_OFF}, /* passive scan */ + {HCI_SUPP_LE_STATES_ACTIVE_SCAN_INIT_MASK, HCI_SUPP_LE_STATES_ACTIVE_SCAN_INIT_OFF}, /* active scan */ + {HCI_SUPP_LE_STATES_SCAN_ADV_INIT_MASK, HCI_SUPP_LE_STATES_SCAN_ADV_INIT_OFF} /* scanable adv */ + + }, + { /* master */ + {HCI_SUPP_LE_STATES_CONN_ADV_MASTER_MASK, HCI_SUPP_LE_STATES_CONN_ADV_MASTER_OFF}, /* conn_adv: 35 */ + {HCI_SUPP_LE_STATES_INIT_MASTER_MASK, HCI_SUPP_LE_STATES_INIT_MASTER_OFF}, /* init 28 */ + {HCI_SUPP_LE_STATES_INIT_MASTER_MASK, HCI_SUPP_LE_STATES_INIT_MASTER_OFF}, /* master 28 */ + {HCI_SUPP_LE_STATES_CONN_ADV_INIT_MASK, HCI_SUPP_LE_STATES_CONN_ADV_INIT_OFF}, /* slave: 32 */ + {HCI_SUPP_LE_STATES_LO_DUTY_DIR_ADV_MASTER_MASK, HCI_SUPP_LE_STATES_LO_DUTY_DIR_ADV_MASTER_OFF}, /* lo duty cycle adv 37 */ + {HCI_SUPP_LE_STATES_HI_DUTY_DIR_ADV_MASTER_MASK, HCI_SUPP_LE_STATES_HI_DUTY_DIR_ADV_MASTER_OFF}, /* hi duty cycle adv 36 */ + {HCI_SUPP_LE_STATES_NON_CONN_ADV_MASTER_MASK, HCI_SUPP_LE_STATES_NON_CONN_ADV_MASTER_OFF}, /* non connectable adv */ + {HCI_SUPP_LE_STATES_PASS_SCAN_MASTER_MASK, HCI_SUPP_LE_STATES_PASS_SCAN_MASTER_OFF}, /* passive scan */ + {HCI_SUPP_LE_STATES_ACTIVE_SCAN_MASTER_MASK, HCI_SUPP_LE_STATES_ACTIVE_SCAN_MASTER_OFF}, /* active scan */ + {HCI_SUPP_LE_STATES_SCAN_ADV_MASTER_MASK, HCI_SUPP_LE_STATES_SCAN_ADV_MASTER_OFF} /* scanable adv */ + + }, + { /* slave */ + {HCI_SUPP_LE_STATES_CONN_ADV_SLAVE_MASK, HCI_SUPP_LE_STATES_CONN_ADV_SLAVE_OFF}, /* conn_adv: 38,*/ + {HCI_SUPP_LE_STATES_INIT_MASTER_SLAVE_MASK, HCI_SUPP_LE_STATES_INIT_MASTER_SLAVE_OFF}, /* init 41 */ + {HCI_SUPP_LE_STATES_INIT_MASTER_SLAVE_MASK, HCI_SUPP_LE_STATES_INIT_MASTER_SLAVE_OFF}, /* master 41 */ + {HCI_SUPP_LE_STATES_CONN_ADV_SLAVE_MASK, HCI_SUPP_LE_STATES_CONN_ADV_SLAVE_OFF}, /* slave: 38,*/ + {HCI_SUPP_LE_STATES_LO_DUTY_DIR_ADV_SLAVE_MASK, HCI_SUPP_LE_STATES_LO_DUTY_DIR_ADV_SLAVE_OFF}, /* lo duty cycle adv 40 */ + {HCI_SUPP_LE_STATES_HI_DUTY_DIR_ADV_SLAVE_MASK, HCI_SUPP_LE_STATES_HI_DUTY_DIR_ADV_SLAVE_OFF}, /* hi duty cycle adv 39 */ + {HCI_SUPP_LE_STATES_NON_CONN_ADV_SLAVE_MASK, HCI_SUPP_LE_STATES_NON_CONN_ADV_SLAVE_OFF}, /* non connectable adv */ + {HCI_SUPP_LE_STATES_PASS_SCAN_SLAVE_MASK, HCI_SUPP_LE_STATES_PASS_SCAN_SLAVE_OFF}, /* passive scan */ + {HCI_SUPP_LE_STATES_ACTIVE_SCAN_SLAVE_MASK, HCI_SUPP_LE_STATES_ACTIVE_SCAN_SLAVE_OFF}, /* active scan */ + {HCI_SUPP_LE_STATES_SCAN_ADV_SLAVE_MASK, HCI_SUPP_LE_STATES_SCAN_ADV_SLAVE_OFF} /* scanable adv */ + + }, + { /* lo duty cycle adv */ + {0, 0}, /* conn_adv: 38,*/ + {HCI_SUPP_LE_STATES_LO_DUTY_DIR_ADV_INIT_MASK, HCI_SUPP_LE_STATES_LO_DUTY_DIR_ADV_INIT_OFF} ,/* init 34 */ + {HCI_SUPP_LE_STATES_LO_DUTY_DIR_ADV_MASTER_MASK, HCI_SUPP_LE_STATES_LO_DUTY_DIR_ADV_MASTER_OFF}, /* master 37 */ + {HCI_SUPP_LE_STATES_LO_DUTY_DIR_ADV_SLAVE_MASK, HCI_SUPP_LE_STATES_LO_DUTY_DIR_ADV_SLAVE_OFF}, /* slave: 40 */ + {0, 0}, /* lo duty cycle adv 40 */ + {0, 0}, /* hi duty cycle adv 39 */ + {0, 0}, /* non connectable adv */ + {0, 0}, /* TODO: passive scan, not covered? */ + {0, 0}, /* TODO: active scan, not covered? */ + {0, 0} /* scanable adv */ + }, + { /* hi duty cycle adv */ + {0, 0}, /* conn_adv: 38,*/ + {HCI_SUPP_LE_STATES_HI_DUTY_DIR_ADV_INIT_MASK, HCI_SUPP_LE_STATES_HI_DUTY_DIR_ADV_INIT_OFF}, /* init 33 */ + {HCI_SUPP_LE_STATES_HI_DUTY_DIR_ADV_MASTER_MASK, HCI_SUPP_LE_STATES_HI_DUTY_DIR_ADV_MASTER_OFF}, /* master 36 */ + {HCI_SUPP_LE_STATES_HI_DUTY_DIR_ADV_SLAVE_MASK, HCI_SUPP_LE_STATES_HI_DUTY_DIR_ADV_SLAVE_OFF}, /* slave: 39*/ + {0, 0}, /* lo duty cycle adv 40 */ + {0, 0}, /* hi duty cycle adv 39 */ + {0, 0}, /* non connectable adv */ + {HCI_SUPP_LE_STATES_HI_DUTY_DIR_ADV_PASS_SCAN_MASK, HCI_SUPP_LE_STATES_HI_DUTY_DIR_ADV_PASS_SCAN_OFF}, /* passive scan */ + {HCI_SUPP_LE_STATES_HI_DUTY_DIR_ADV_ACTIVE_SCAN_MASK, HCI_SUPP_LE_STATES_HI_DUTY_DIR_ADV_ACTIVE_SCAN_OFF}, /* active scan */ + {0, 0} /* scanable adv */ + }, + { /* non connectable adv */ + {0, 0}, /* conn_adv: */ + {HCI_SUPP_LE_STATES_NON_CONN_INIT_MASK, HCI_SUPP_LE_STATES_NON_CONN_INIT_OFF}, /* init */ + {HCI_SUPP_LE_STATES_NON_CONN_ADV_MASTER_MASK, HCI_SUPP_LE_STATES_NON_CONN_ADV_MASTER_OFF}, /* master */ + {HCI_SUPP_LE_STATES_NON_CONN_ADV_SLAVE_MASK, HCI_SUPP_LE_STATES_NON_CONN_ADV_SLAVE_OFF}, /* slave: */ + {0, 0}, /* lo duty cycle adv */ + {0, 0}, /* hi duty cycle adv */ + {0, 0}, /* non connectable adv */ + {HCI_SUPP_LE_STATES_NON_CONN_ADV_PASS_SCAN_MASK, HCI_SUPP_LE_STATES_NON_CONN_ADV_PASS_SCAN_OFF}, /* passive scan */ + {HCI_SUPP_LE_STATES_NON_CONN_ADV_ACTIVE_SCAN_MASK, HCI_SUPP_LE_STATES_NON_CONN_ADV_ACTIVE_SCAN_OFF}, /* active scan */ + {0, 0} /* scanable adv */ + }, + { /* passive scan */ + {HCI_SUPP_LE_STATES_CONN_ADV_PASS_SCAN_MASK, HCI_SUPP_LE_STATES_CONN_ADV_PASS_SCAN_OFF}, /* conn_adv: */ + {HCI_SUPP_LE_STATES_PASS_SCAN_INIT_MASK, HCI_SUPP_LE_STATES_PASS_SCAN_INIT_OFF}, /* init */ + {HCI_SUPP_LE_STATES_PASS_SCAN_MASTER_MASK, HCI_SUPP_LE_STATES_PASS_SCAN_MASTER_OFF}, /* master */ + {HCI_SUPP_LE_STATES_PASS_SCAN_SLAVE_MASK, HCI_SUPP_LE_STATES_PASS_SCAN_SLAVE_OFF}, /* slave: */ + {0, 0}, /* lo duty cycle adv */ + {HCI_SUPP_LE_STATES_HI_DUTY_DIR_ADV_PASS_SCAN_MASK, HCI_SUPP_LE_STATES_HI_DUTY_DIR_ADV_PASS_SCAN_OFF}, /* hi duty cycle adv */ + {HCI_SUPP_LE_STATES_NON_CONN_ADV_PASS_SCAN_MASK, HCI_SUPP_LE_STATES_NON_CONN_ADV_PASS_SCAN_OFF}, /* non connectable adv */ + {0, 0}, /* passive scan */ + {0, 0}, /* active scan */ + {HCI_SUPP_LE_STATES_SCAN_ADV_PASS_SCAN_MASK, HCI_SUPP_LE_STATES_SCAN_ADV_PASS_SCAN_OFF} /* scanable adv */ + }, + { /* active scan */ + {HCI_SUPP_LE_STATES_CONN_ADV_ACTIVE_SCAN_MASK, HCI_SUPP_LE_STATES_CONN_ADV_ACTIVE_SCAN_OFF}, /* conn_adv: */ + {HCI_SUPP_LE_STATES_ACTIVE_SCAN_INIT_MASK, HCI_SUPP_LE_STATES_ACTIVE_SCAN_INIT_OFF}, /* init */ + {HCI_SUPP_LE_STATES_ACTIVE_SCAN_MASTER_MASK, HCI_SUPP_LE_STATES_ACTIVE_SCAN_MASTER_OFF}, /* master */ + {HCI_SUPP_LE_STATES_ACTIVE_SCAN_SLAVE_MASK, HCI_SUPP_LE_STATES_ACTIVE_SCAN_SLAVE_OFF}, /* slave: */ + {0, 0}, /* lo duty cycle adv */ + {HCI_SUPP_LE_STATES_HI_DUTY_DIR_ADV_ACTIVE_SCAN_MASK, HCI_SUPP_LE_STATES_HI_DUTY_DIR_ADV_ACTIVE_SCAN_OFF}, /* hi duty cycle adv */ + {HCI_SUPP_LE_STATES_NON_CONN_ADV_ACTIVE_SCAN_MASK, HCI_SUPP_LE_STATES_NON_CONN_ADV_ACTIVE_SCAN_OFF}, /* non connectable adv */ + {0, 0}, /* TODO: passive scan */ + {0, 0}, /* TODO: active scan */ + {HCI_SUPP_LE_STATES_SCAN_ADV_ACTIVE_SCAN_MASK, HCI_SUPP_LE_STATES_SCAN_ADV_ACTIVE_SCAN_OFF} /* scanable adv */ + }, + { /* scanable adv */ + {0, 0}, /* conn_adv: */ + {HCI_SUPP_LE_STATES_SCAN_ADV_INIT_MASK, HCI_SUPP_LE_STATES_SCAN_ADV_INIT_OFF}, /* init */ + {HCI_SUPP_LE_STATES_SCAN_ADV_MASTER_MASK, HCI_SUPP_LE_STATES_SCAN_ADV_MASTER_OFF}, /* master */ + {HCI_SUPP_LE_STATES_SCAN_ADV_SLAVE_MASK, HCI_SUPP_LE_STATES_SCAN_ADV_SLAVE_OFF}, /* slave: */ + {0, 0}, /* lo duty cycle adv */ + {0, 0}, /* hi duty cycle adv */ + {0, 0}, /* non connectable adv */ + {HCI_SUPP_LE_STATES_SCAN_ADV_PASS_SCAN_MASK, HCI_SUPP_LE_STATES_SCAN_ADV_PASS_SCAN_OFF}, /* passive scan */ + {HCI_SUPP_LE_STATES_SCAN_ADV_ACTIVE_SCAN_MASK, HCI_SUPP_LE_STATES_SCAN_ADV_ACTIVE_SCAN_OFF}, /* active scan */ + {0, 0} /* scanable adv */ + } + +}; +/* check LE combo state supported */ +#define BTM_LE_STATES_SUPPORTED(x, y, z) ((x)[(z)] & (y)) + + +/******************************************************************************* +** +** Function BTM_BleUpdateAdvWhitelist +** +** Description Add or remove device from advertising white list +** +** Returns void +** +*******************************************************************************/ +BOOLEAN BTM_BleUpdateAdvWhitelist(BOOLEAN add_remove, BD_ADDR remote_bda) +{ + UNUSED(add_remove); + UNUSED(remote_bda); + + return FALSE; +} + +/******************************************************************************* +** +** Function BTM_BleUpdateAdvFilterPolicy +** +** Description This function update the filter policy of advertiser. +** +** Parameter adv_policy: advertising filter policy +** +** Return void +*******************************************************************************/ +void BTM_BleUpdateAdvFilterPolicy(tBTM_BLE_AFP adv_policy) +{ + tBTM_BLE_INQ_CB *p_cb = &btm_cb.ble_ctr_cb.inq_var; + tBLE_ADDR_TYPE init_addr_type = BLE_ADDR_PUBLIC; + BD_ADDR p_addr_ptr= {0}; + UINT8 adv_mode = p_cb->adv_mode; + + BTM_TRACE_EVENT ("BTM_BleUpdateAdvFilterPolicy"); + + if (!controller_get_interface()->supports_ble()) + return; + + if (p_cb->afp != adv_policy) + { + p_cb->afp = adv_policy; + + /* if adv active, stop and restart */ + btm_ble_stop_adv (); + + if (p_cb->connectable_mode & BTM_BLE_CONNECTABLE) + p_cb->evt_type = btm_set_conn_mode_adv_init_addr(p_cb, p_addr_ptr, &init_addr_type, + &p_cb->adv_addr_type); + + btsnd_hcic_ble_write_adv_params ((UINT16)(p_cb->adv_interval_min ? p_cb->adv_interval_min : + BTM_BLE_GAP_ADV_SLOW_INT), + (UINT16)(p_cb->adv_interval_max ? p_cb->adv_interval_max : + BTM_BLE_GAP_ADV_SLOW_INT), + p_cb->evt_type, + p_cb->adv_addr_type, + init_addr_type, + p_addr_ptr, + p_cb->adv_chnl_map, + p_cb->afp); + + if (adv_mode == BTM_BLE_ADV_ENABLE) + btm_ble_start_adv (); + + } +} + +/******************************************************************************* +** +** Function btm_ble_send_extended_scan_params +** +** Description This function sends out the extended scan parameters command to the controller +** +** Parameters scan_type - Scan type +** scan_int - Scan interval +** scan_win - Scan window +** addr_type_own - Own address type +** scan_filter_policy - Scan filter policy +** +** Returns TRUE or FALSE +** +*******************************************************************************/ +BOOLEAN btm_ble_send_extended_scan_params(UINT8 scan_type, UINT32 scan_int, + UINT32 scan_win, UINT8 addr_type_own, + UINT8 scan_filter_policy) +{ + UINT8 scan_param[HCIC_PARAM_SIZE_BLE_WRITE_EXTENDED_SCAN_PARAM]; + UINT8 *pp_scan = scan_param; + + memset(scan_param, 0, HCIC_PARAM_SIZE_BLE_WRITE_EXTENDED_SCAN_PARAM); + + UINT8_TO_STREAM(pp_scan, scan_type); + UINT32_TO_STREAM(pp_scan, scan_int); + UINT32_TO_STREAM(pp_scan, scan_win); + UINT8_TO_STREAM(pp_scan, addr_type_own); + UINT8_TO_STREAM(pp_scan, scan_filter_policy); + + BTM_TRACE_DEBUG("%s, %d, %d", __func__, scan_int, scan_win); + if ((BTM_VendorSpecificCommand(HCI_BLE_EXTENDED_SCAN_PARAMS_OCF, + HCIC_PARAM_SIZE_BLE_WRITE_EXTENDED_SCAN_PARAM, scan_param, NULL)) != BTM_SUCCESS) + { + BTM_TRACE_ERROR("%s error sending extended scan parameters", __func__); + return FALSE; + } + return TRUE; +} + +/******************************************************************************* +** +** Function BTM_BleObserve +** +** Description This procedure keep the device listening for advertising +** events from a broadcast device. +** +** Parameters start: start or stop observe. +** white_list: use white list in observer mode or not. +** +** Returns void +** +*******************************************************************************/ +tBTM_STATUS BTM_BleObserve(BOOLEAN start, UINT8 duration, + tBTM_INQ_RESULTS_CB *p_results_cb, tBTM_CMPL_CB *p_cmpl_cb) +{ + tBTM_BLE_INQ_CB *p_inq = &btm_cb.ble_ctr_cb.inq_var; + tBTM_STATUS status = BTM_WRONG_MODE; + + UINT32 scan_interval = !p_inq->scan_interval ? BTM_BLE_GAP_DISC_SCAN_INT : p_inq->scan_interval; + UINT32 scan_window = !p_inq->scan_window ? BTM_BLE_GAP_DISC_SCAN_WIN : p_inq->scan_window; + + BTM_TRACE_EVENT ("%s : scan_type:%d, %d, %d", __func__, btm_cb.btm_inq_vars.scan_type, + p_inq->scan_interval, p_inq->scan_window); + + if (!controller_get_interface()->supports_ble()) + return BTM_ILLEGAL_VALUE; + + if (start) + { + /* shared inquiry database, do not allow observe if any inquiry is active */ + if (BTM_BLE_IS_OBS_ACTIVE(btm_cb.ble_ctr_cb.scan_activity)) + { + BTM_TRACE_ERROR("%s Observe Already Active", __func__); + return status; + } + + btm_cb.ble_ctr_cb.p_obs_results_cb = p_results_cb; + btm_cb.ble_ctr_cb.p_obs_cmpl_cb = p_cmpl_cb; + status = BTM_CMD_STARTED; + + /* scan is not started */ + if (!BTM_BLE_IS_SCAN_ACTIVE(btm_cb.ble_ctr_cb.scan_activity)) + { + /* allow config of scan type */ + p_inq->scan_type = (p_inq->scan_type == BTM_BLE_SCAN_MODE_NONE) ? + BTM_BLE_SCAN_MODE_ACTI: p_inq->scan_type; + /* assume observe always not using white list */ + #if (defined BLE_PRIVACY_SPT && BLE_PRIVACY_SPT == TRUE) + /* enable resolving list */ + btm_ble_enable_resolving_list_for_platform(BTM_BLE_RL_SCAN); + #endif + + if (cmn_ble_vsc_cb.extended_scan_support == 0) + { + btsnd_hcic_ble_set_scan_params(p_inq->scan_type, (UINT16)scan_interval, + (UINT16)scan_window, + btm_cb.ble_ctr_cb.addr_mgnt_cb.own_addr_type, + BTM_BLE_DEFAULT_SFP); + } + else + { + btm_ble_send_extended_scan_params(p_inq->scan_type, scan_interval, scan_window, + btm_cb.ble_ctr_cb.addr_mgnt_cb.own_addr_type, + BTM_BLE_DEFAULT_SFP); + } + + p_inq->scan_duplicate_filter = BTM_BLE_DUPLICATE_DISABLE; + status = btm_ble_start_scan(); + } + + if (status == BTM_CMD_STARTED) + { + btm_cb.ble_ctr_cb.scan_activity |= BTM_LE_OBSERVE_ACTIVE; + if (duration != 0) + /* start observer timer */ + btu_start_timer (&btm_cb.ble_ctr_cb.obs_timer_ent, BTU_TTYPE_BLE_OBSERVE, duration); + } + } + else if (BTM_BLE_IS_OBS_ACTIVE(btm_cb.ble_ctr_cb.scan_activity)) + { + status = BTM_CMD_STARTED; + btm_ble_stop_observe(); + } + else + { + BTM_TRACE_ERROR("%s Observe not active", __func__); + } + + return status; + +} + +/******************************************************************************* +** +** Function BTM_BleBroadcast +** +** Description This function is to start or stop broadcasting. +** +** Parameters start: start or stop broadcasting. +** +** Returns status. +** +*******************************************************************************/ +tBTM_STATUS BTM_BleBroadcast(BOOLEAN start) +{ + tBTM_STATUS status = BTM_NO_RESOURCES; + tBTM_LE_RANDOM_CB *p_addr_cb = &btm_cb.ble_ctr_cb.addr_mgnt_cb; + tBTM_BLE_INQ_CB *p_cb = &btm_cb.ble_ctr_cb.inq_var; + UINT8 evt_type = p_cb->scan_rsp ? BTM_BLE_DISCOVER_EVT: BTM_BLE_NON_CONNECT_EVT; + + if (!controller_get_interface()->supports_ble()) + return BTM_ILLEGAL_VALUE; + +#ifdef BTM_BLE_PC_ADV_TEST_MODE + if (BTM_BLE_PC_ADV_TEST_MODE) + { + evt_type = p_cb->scan_rsp ? BTM_BLE_CONNECT_EVT: BTM_BLE_NON_CONNECT_EVT; + } +#endif + + if (start && p_cb->adv_mode == BTM_BLE_ADV_DISABLE) + { + /* update adv params */ + if (!btsnd_hcic_ble_write_adv_params ((UINT16)(p_cb->adv_interval_min ? p_cb->adv_interval_min : + BTM_BLE_GAP_ADV_INT), + (UINT16)(p_cb->adv_interval_max ? p_cb->adv_interval_max : + BTM_BLE_GAP_ADV_INT), + evt_type, + p_addr_cb->own_addr_type, + p_cb->direct_bda.type, + p_cb->direct_bda.bda, + p_cb->adv_chnl_map, + p_cb->afp)) + + status = BTM_NO_RESOURCES; + else + p_cb->evt_type = evt_type; + + status = btm_ble_start_adv (); + } + else if (!start) + { + status = btm_ble_stop_adv(); +#if BLE_PRIVACY_SPT == TRUE + btm_ble_disable_resolving_list(BTM_BLE_RL_ADV, TRUE); +#endif + } + else + { + status = BTM_WRONG_MODE; + BTM_TRACE_ERROR("Can not %s Broadcast, device %s in Broadcast mode", + (start ? "Start" : "Stop"), (start ? "already" :"not")); + } + return status; +} + +/******************************************************************************* +** +** Function btm_vsc_brcm_features_complete +** +** Description Command Complete callback for HCI_BLE_VENDOR_CAP_OCF +** +** Returns void +** +*******************************************************************************/ +static void btm_ble_vendor_capability_vsc_cmpl_cback (tBTM_VSC_CMPL *p_vcs_cplt_params) +{ +#if BLE_VND_INCLUDED == TRUE + UINT8 status = 0xFF; + UINT8 *p; + + BTM_TRACE_DEBUG("%s", __func__); + + /* Check status of command complete event */ + if ((p_vcs_cplt_params->opcode == HCI_BLE_VENDOR_CAP_OCF) && + (p_vcs_cplt_params->param_len > 0)) + { + p = p_vcs_cplt_params->p_param_buf; + STREAM_TO_UINT8(status, p); + } + + if (status == HCI_SUCCESS) + { + STREAM_TO_UINT8(btm_cb.cmn_ble_vsc_cb.adv_inst_max, p); + STREAM_TO_UINT8(btm_cb.cmn_ble_vsc_cb.rpa_offloading, p); + STREAM_TO_UINT16(btm_cb.cmn_ble_vsc_cb.tot_scan_results_strg, p); + STREAM_TO_UINT8(btm_cb.cmn_ble_vsc_cb.max_irk_list_sz, p); + STREAM_TO_UINT8(btm_cb.cmn_ble_vsc_cb.filter_support, p); + STREAM_TO_UINT8(btm_cb.cmn_ble_vsc_cb.max_filter, p); + STREAM_TO_UINT8(btm_cb.cmn_ble_vsc_cb.energy_support, p); + + if (p_vcs_cplt_params->param_len > BTM_VSC_CHIP_CAPABILITY_RSP_LEN_L_RELEASE) + { + STREAM_TO_UINT16(btm_cb.cmn_ble_vsc_cb.version_supported, p); + } + else + { + btm_cb.cmn_ble_vsc_cb.version_supported = BTM_VSC_CHIP_CAPABILITY_L_VERSION; + } + + if (btm_cb.cmn_ble_vsc_cb.version_supported >= BTM_VSC_CHIP_CAPABILITY_M_VERSION) + { + STREAM_TO_UINT16(btm_cb.cmn_ble_vsc_cb.total_trackable_advertisers, p); + STREAM_TO_UINT16(btm_cb.cmn_ble_vsc_cb.extended_scan_support, p); + STREAM_TO_UINT16(btm_cb.cmn_ble_vsc_cb.debug_logging_supported, p); + } + btm_cb.cmn_ble_vsc_cb.values_read = TRUE; + } + + BTM_TRACE_DEBUG("%s: stat=%d, irk=%d, ADV ins:%d, rpa=%d, ener=%d, ext_scan=%d", + __func__, status, btm_cb.cmn_ble_vsc_cb.max_irk_list_sz, + btm_cb.cmn_ble_vsc_cb.adv_inst_max, btm_cb.cmn_ble_vsc_cb.rpa_offloading, + btm_cb.cmn_ble_vsc_cb.energy_support, btm_cb.cmn_ble_vsc_cb.extended_scan_support); + + if (BTM_BleMaxMultiAdvInstanceCount() > 0) + btm_ble_multi_adv_init(); + + if (btm_cb.cmn_ble_vsc_cb.max_filter > 0) + btm_ble_adv_filter_init(); + +#if (defined BLE_PRIVACY_SPT && BLE_PRIVACY_SPT == TRUE) + /* VS capability included and non-4.2 device */ + if (btm_cb.cmn_ble_vsc_cb.max_irk_list_sz > 0 && + controller_get_interface()->get_ble_resolving_list_max_size() == 0) + btm_ble_resolving_list_init(btm_cb.cmn_ble_vsc_cb.max_irk_list_sz); +#endif + + if (btm_cb.cmn_ble_vsc_cb.tot_scan_results_strg > 0) + btm_ble_batchscan_init(); + + if (p_ctrl_le_feature_rd_cmpl_cback != NULL) + p_ctrl_le_feature_rd_cmpl_cback(status); +#endif +} + +/******************************************************************************* +** +** Function BTM_BleGetVendorCapabilities +** +** Description This function reads local LE features +** +** Parameters p_cmn_vsc_cb : Locala LE capability structure +** +** Returns void +** +*******************************************************************************/ +extern void BTM_BleGetVendorCapabilities(tBTM_BLE_VSC_CB *p_cmn_vsc_cb) +{ + BTM_TRACE_DEBUG("BTM_BleGetVendorCapabilities"); + + if (NULL != p_cmn_vsc_cb) + { + *p_cmn_vsc_cb = btm_cb.cmn_ble_vsc_cb; + } +} + +/****************************************************************************** +** +** Function BTM_BleReadControllerFeatures +** +** Description Reads BLE specific controller features +** +** Parameters: tBTM_BLE_CTRL_FEATURES_CBACK : Callback to notify when features are read +** +** Returns void +** +*******************************************************************************/ +extern void BTM_BleReadControllerFeatures(tBTM_BLE_CTRL_FEATURES_CBACK *p_vsc_cback) +{ + if (TRUE == btm_cb.cmn_ble_vsc_cb.values_read) + return; + +#if BLE_VND_INCLUDED == TRUE + BTM_TRACE_DEBUG("BTM_BleReadControllerFeatures"); + + p_ctrl_le_feature_rd_cmpl_cback = p_vsc_cback; + if ( BTM_VendorSpecificCommand (HCI_BLE_VENDOR_CAP_OCF, + 0, + NULL, + btm_ble_vendor_capability_vsc_cmpl_cback) + != BTM_CMD_STARTED) + { + BTM_TRACE_ERROR("LE Get_Vendor Capabilities Command Failed."); + } +#else + UNUSED(p_vsc_cback); +#endif + return ; +} + +/******************************************************************************* +** +** Function BTM_BleEnableMixedPrivacyMode +** +** Description This function is called to enabled Mixed mode if privacy 1.2 +** is applicable in controller. +** +** Parameters mixed_on: mixed mode to be used or not. +** +** Returns void +** +*******************************************************************************/ +void BTM_BleEnableMixedPrivacyMode(BOOLEAN mixed_on) +{ + +#if BLE_PRIVACY_SPT == TRUE + btm_cb.ble_ctr_cb.mixed_mode = mixed_on; + + /* TODO: send VSC to enabled mixed mode */ +#endif +} + +/******************************************************************************* +** +** Function BTM_BleConfigPrivacy +** +** Description This function is called to enable or disable the privacy in +** LE channel of the local device. +** +** Parameters privacy_mode: privacy mode on or off. +** +** Returns BOOLEAN privacy mode set success; otherwise failed. +** +*******************************************************************************/ +BOOLEAN BTM_BleConfigPrivacy(BOOLEAN privacy_mode) +{ +#if BLE_PRIVACY_SPT == TRUE + tBTM_BLE_CB *p_cb = &btm_cb.ble_ctr_cb; + + BTM_TRACE_EVENT ("%s", __func__); + + /* if LE is not supported, return error */ + if (!controller_get_interface()->supports_ble()) + return FALSE; + + uint8_t addr_resolution = 0; + if(!privacy_mode)/* if privacy disabled, always use public address */ + { + p_cb->addr_mgnt_cb.own_addr_type = BLE_ADDR_PUBLIC; + p_cb->privacy_mode = BTM_PRIVACY_NONE; + } + else /* privacy is turned on*/ + { + /* always set host random address, used when privacy 1.1 or priavcy 1.2 is disabled */ + p_cb->addr_mgnt_cb.own_addr_type = BLE_ADDR_RANDOM; + btm_gen_resolvable_private_addr((void *)btm_gen_resolve_paddr_low); + + if (BTM_BleMaxMultiAdvInstanceCount() > 0) + btm_ble_multi_adv_enb_privacy(privacy_mode); + + /* 4.2 controller only allow privacy 1.2 or mixed mode, resolvable private address in controller */ + if (controller_get_interface()->supports_ble_privacy()) + { + addr_resolution = 1; + /* check vendor specific capability */ + p_cb->privacy_mode = btm_cb.ble_ctr_cb.mixed_mode ? BTM_PRIVACY_MIXED : BTM_PRIVACY_1_2; + } + else /* 4.1/4.0 controller */ + p_cb->privacy_mode = BTM_PRIVACY_1_1; + } + +#if (defined(GAP_INCLUDED) && GAP_INCLUDED == TRUE) + GAP_BleAttrDBUpdate (GATT_UUID_GAP_CENTRAL_ADDR_RESOL, (tGAP_BLE_ATTR_VALUE *)&addr_resolution); +#endif + + return TRUE; +#else + return FALSE; +#endif +} + +/******************************************************************************* +** +** Function BTM_BleMaxMultiAdvInstanceCount +** +** Description Returns max number of multi adv instances supported by controller +** +** Returns Max multi adv instance count +** +*******************************************************************************/ +extern UINT8 BTM_BleMaxMultiAdvInstanceCount(void) +{ + return btm_cb.cmn_ble_vsc_cb.adv_inst_max < BTM_BLE_MULTI_ADV_MAX ? + btm_cb.cmn_ble_vsc_cb.adv_inst_max : BTM_BLE_MULTI_ADV_MAX; +} + +#if BLE_PRIVACY_SPT == TRUE +/******************************************************************************* +** +** Function btm_ble_resolve_random_addr_on_adv +** +** Description resolve random address complete callback. +** +** Returns void +** +*******************************************************************************/ +static void btm_ble_resolve_random_addr_on_adv(void * p_rec, void *p) +{ + tBTM_SEC_DEV_REC *match_rec = (tBTM_SEC_DEV_REC *) p_rec; + UINT8 addr_type = BLE_ADDR_RANDOM; + BD_ADDR bda; + UINT8 *pp = (UINT8 *)p + 1; + UINT8 evt_type; + + BTM_TRACE_EVENT ("btm_ble_resolve_random_addr_on_adv "); + + STREAM_TO_UINT8 (evt_type, pp); + STREAM_TO_UINT8 (addr_type, pp); + STREAM_TO_BDADDR (bda, pp); + + if (match_rec) + { + BTM_TRACE_DEBUG("Random match"); + match_rec->ble.active_addr_type = BTM_BLE_ADDR_RRA; + memcpy(match_rec->ble.cur_rand_addr, bda, BD_ADDR_LEN); + + if (btm_ble_init_pseudo_addr(match_rec, bda)) + { + memcpy(bda, match_rec->bd_addr, BD_ADDR_LEN); + } else { + // Assign the original address to be the current report address + memcpy(bda, match_rec->ble.pseudo_addr, BD_ADDR_LEN); + } + } + + btm_ble_process_adv_pkt_cont(bda, addr_type, evt_type, pp); + + return; +} +#endif + +/******************************************************************************* +** +** Function BTM_BleLocalPrivacyEnabled +** +** Description Checks if local device supports private address +** +** Returns Return TRUE if local privacy is enabled else FALSE +** +*******************************************************************************/ +BOOLEAN BTM_BleLocalPrivacyEnabled(void) +{ +#if BLE_PRIVACY_SPT == TRUE + return (btm_cb.ble_ctr_cb.privacy_mode != BTM_PRIVACY_NONE); +#else + return false; +#endif +} + +/******************************************************************************* +** +** Function BTM_BleSetBgConnType +** +** Description This function is called to set BLE connectable mode for a +** peripheral device. +** +** Parameters bg_conn_type: it can be auto connection, or selective connection. +** p_select_cback: callback function when selective connection procedure +** is being used. +** +** Returns void +** +*******************************************************************************/ +BOOLEAN BTM_BleSetBgConnType(tBTM_BLE_CONN_TYPE bg_conn_type, + tBTM_BLE_SEL_CBACK *p_select_cback) +{ + BOOLEAN started = TRUE; + + BTM_TRACE_EVENT ("BTM_BleSetBgConnType "); + if (!controller_get_interface()->supports_ble()) + return FALSE; + + if (btm_cb.ble_ctr_cb.bg_conn_type != bg_conn_type) + { + switch (bg_conn_type) + { + case BTM_BLE_CONN_AUTO: + btm_ble_start_auto_conn(TRUE); + break; + + case BTM_BLE_CONN_SELECTIVE: + if (btm_cb.ble_ctr_cb.bg_conn_type == BTM_BLE_CONN_AUTO) + { + btm_ble_start_auto_conn(FALSE); + } + btm_ble_start_select_conn(TRUE, p_select_cback); + break; + + case BTM_BLE_CONN_NONE: + if (btm_cb.ble_ctr_cb.bg_conn_type == BTM_BLE_CONN_AUTO) + { + btm_ble_start_auto_conn(FALSE); + } + else if (btm_cb.ble_ctr_cb.bg_conn_type == BTM_BLE_CONN_SELECTIVE) + { + btm_ble_start_select_conn(FALSE, NULL); + } + started = TRUE; + break; + + default: + BTM_TRACE_ERROR("invalid bg connection type : %d ", bg_conn_type); + started = FALSE; + break; + } + + if (started) + btm_cb.ble_ctr_cb.bg_conn_type = bg_conn_type; + } + return started; +} + +/******************************************************************************* +** +** Function BTM_BleClearBgConnDev +** +** Description This function is called to clear the whitelist, +** end any pending whitelist connections, +* and reset the local bg device list. +** +** Parameters void +** +** Returns void +** +*******************************************************************************/ +void BTM_BleClearBgConnDev(void) +{ + btm_ble_start_auto_conn(FALSE); + btm_ble_clear_white_list(); + gatt_reset_bgdev_list(); +} + +/******************************************************************************* +** +** Function BTM_BleUpdateBgConnDev +** +** Description This function is called to add or remove a device into/from +** background connection procedure. The background connection +* procedure is decided by the background connection type, it can be +* auto connection, or selective connection. +** +** Parameters add_remove: TRUE to add; FALSE to remove. +** remote_bda: device address to add/remove. +** +** Returns void +** +*******************************************************************************/ +BOOLEAN BTM_BleUpdateBgConnDev(BOOLEAN add_remove, BD_ADDR remote_bda) +{ + BTM_TRACE_EVENT("%s() add=%d", __func__, add_remove); + return btm_update_dev_to_white_list(add_remove, remote_bda); +} + +/******************************************************************************* +** +** Function BTM_BleSetConnectableMode +** +** Description This function is called to set BLE connectable mode for a +** peripheral device. +** +** Parameters conn_mode: directed connectable mode, or non-directed.It can +** be BTM_BLE_CONNECT_EVT, BTM_BLE_CONNECT_DIR_EVT or +** BTM_BLE_CONNECT_LO_DUTY_DIR_EVT +** +** Returns BTM_ILLEGAL_VALUE if controller does not support BLE. +** BTM_SUCCESS is status set successfully; otherwise failure. +** +*******************************************************************************/ +tBTM_STATUS BTM_BleSetConnectableMode(tBTM_BLE_CONN_MODE connectable_mode) +{ + tBTM_BLE_INQ_CB *p_cb = &btm_cb.ble_ctr_cb.inq_var; + + BTM_TRACE_EVENT ("%s connectable_mode = %d ", __func__, connectable_mode); + if (!controller_get_interface()->supports_ble()) + return BTM_ILLEGAL_VALUE; + + p_cb->directed_conn = connectable_mode; + return btm_ble_set_connectability( p_cb->connectable_mode); +} + +/******************************************************************************* +** +** Function btm_set_conn_mode_adv_init_addr +** +** Description set initator address type and local address type based on adv +** mode. +** +** +*******************************************************************************/ +static UINT8 btm_set_conn_mode_adv_init_addr(tBTM_BLE_INQ_CB *p_cb, + BD_ADDR_PTR p_peer_addr_ptr, + tBLE_ADDR_TYPE *p_peer_addr_type, + tBLE_ADDR_TYPE *p_own_addr_type) +{ + UINT8 evt_type, i = BTM_SEC_MAX_DEVICE_RECORDS; + tBTM_SEC_DEV_REC *p_dev_rec; + + evt_type = (p_cb->connectable_mode == BTM_BLE_NON_CONNECTABLE) ? \ + ((p_cb->scan_rsp) ? BTM_BLE_DISCOVER_EVT : BTM_BLE_NON_CONNECT_EVT )\ + : BTM_BLE_CONNECT_EVT; + + if (evt_type == BTM_BLE_CONNECT_EVT) + { + evt_type = p_cb->directed_conn; + + if ( p_cb->directed_conn == BTM_BLE_CONNECT_DIR_EVT || + p_cb->directed_conn == BTM_BLE_CONNECT_LO_DUTY_DIR_EVT) + { + +#if BLE_PRIVACY_SPT == TRUE + /* for privacy 1.2, convert peer address as static, own address set as ID addr */ + if (btm_cb.ble_ctr_cb.privacy_mode == BTM_PRIVACY_1_2 || + btm_cb.ble_ctr_cb.privacy_mode == BTM_PRIVACY_MIXED) + { + /* only do so for bonded device */ + if ((p_dev_rec = btm_find_or_alloc_dev (p_cb->direct_bda.bda)) != NULL && + p_dev_rec->ble.in_controller_list & BTM_RESOLVING_LIST_BIT) + { + btm_ble_enable_resolving_list(BTM_BLE_RL_ADV); + memcpy(p_peer_addr_ptr, p_dev_rec->ble.static_addr, BD_ADDR_LEN); + *p_peer_addr_type = p_dev_rec->ble.static_addr_type; + *p_own_addr_type = BLE_ADDR_RANDOM_ID; + return evt_type; + } + /* otherwise fall though as normal directed adv */ + else + { + btm_ble_disable_resolving_list(BTM_BLE_RL_ADV, TRUE); + } + } +#endif + /* direct adv mode does not have privacy, if privacy is not enabled */ + *p_peer_addr_type = p_cb->direct_bda.type; + memcpy(p_peer_addr_ptr, p_cb->direct_bda.bda, BD_ADDR_LEN); + return evt_type; + } + } + + /* undirect adv mode or non-connectable mode*/ +#if BLE_PRIVACY_SPT == TRUE + /* when privacy 1.2 privacy only mode is used, or mixed mode */ + if ((btm_cb.ble_ctr_cb.privacy_mode == BTM_PRIVACY_1_2 && p_cb->afp != AP_SCAN_CONN_ALL) || + btm_cb.ble_ctr_cb.privacy_mode == BTM_PRIVACY_MIXED) + { + /* if enhanced privacy is required, set Identity address and matching IRK peer */ + for (i = 0; i < BTM_SEC_MAX_DEVICE_RECORDS; i ++) + { + if ((btm_cb.sec_dev_rec[i].sec_flags & BTM_SEC_IN_USE) != 0 && + (btm_cb.sec_dev_rec[i].ble.in_controller_list & BTM_RESOLVING_LIST_BIT) != 0) + { + memcpy(p_peer_addr_ptr, btm_cb.sec_dev_rec[i].ble.static_addr, BD_ADDR_LEN); + *p_peer_addr_type = btm_cb.sec_dev_rec[i].ble.static_addr_type; + break; + } + } + + if (i != BTM_SEC_MAX_DEVICE_RECORDS) + *p_own_addr_type = BLE_ADDR_RANDOM_ID; + else + /* resolving list is empty, not enabled */ + *p_own_addr_type = BLE_ADDR_RANDOM; + } + /* privacy 1.1, or privacy 1.2, general discoverable/connectable mode, disable privacy in */ + /* controller fall back to host based privacy */ + else if (btm_cb.ble_ctr_cb.privacy_mode != BTM_PRIVACY_NONE) + { + *p_own_addr_type = BLE_ADDR_RANDOM; + } +#endif + + /* if no privacy,do not set any peer address,*/ + /* local address type go by global privacy setting */ + return evt_type; +} + +/******************************************************************************* +** +** Function BTM_BleSetAdvParams +** +** Description This function is called to set advertising parameters. +** +** Parameters adv_int_min: minimum advertising interval +** adv_int_max: maximum advertising interval +** p_dir_bda: connectable direct initiator's LE device address +** chnl_map: advertising channel map. +** +** Returns void +** +*******************************************************************************/ +tBTM_STATUS BTM_BleSetAdvParams(UINT16 adv_int_min, UINT16 adv_int_max, + tBLE_BD_ADDR *p_dir_bda, + tBTM_BLE_ADV_CHNL_MAP chnl_map) +{ + tBTM_LE_RANDOM_CB *p_addr_cb = &btm_cb.ble_ctr_cb.addr_mgnt_cb; + tBTM_BLE_INQ_CB *p_cb = &btm_cb.ble_ctr_cb.inq_var; + tBTM_STATUS status = BTM_SUCCESS; + BD_ADDR p_addr_ptr = {0}; + tBLE_ADDR_TYPE init_addr_type = BLE_ADDR_PUBLIC; + tBLE_ADDR_TYPE own_addr_type = p_addr_cb->own_addr_type; + UINT8 adv_mode = p_cb->adv_mode; + + BTM_TRACE_EVENT ("BTM_BleSetAdvParams"); + + if (!controller_get_interface()->supports_ble()) + return BTM_ILLEGAL_VALUE; + + if (!BTM_BLE_ISVALID_PARAM(adv_int_min, BTM_BLE_ADV_INT_MIN, BTM_BLE_ADV_INT_MAX) || + !BTM_BLE_ISVALID_PARAM(adv_int_max, BTM_BLE_ADV_INT_MIN, BTM_BLE_ADV_INT_MAX)) + { + return BTM_ILLEGAL_VALUE; + } + + p_cb->adv_interval_min = adv_int_min; + p_cb->adv_interval_max = adv_int_max; + p_cb->adv_chnl_map = chnl_map; + + if (p_dir_bda) + { + memcpy(&p_cb->direct_bda, p_dir_bda, sizeof(tBLE_BD_ADDR)); + } + + BTM_TRACE_EVENT ("update params for an active adv"); + + btm_ble_stop_adv(); + + p_cb->evt_type = btm_set_conn_mode_adv_init_addr(p_cb, p_addr_ptr, &init_addr_type, + &own_addr_type); + + /* update adv params */ + btsnd_hcic_ble_write_adv_params (p_cb->adv_interval_min, + p_cb->adv_interval_max, + p_cb->evt_type, + own_addr_type, + init_addr_type, + p_addr_ptr, + p_cb->adv_chnl_map, + p_cb->afp); + + if (adv_mode == BTM_BLE_ADV_ENABLE) + btm_ble_start_adv(); + + return status; +} + +/******************************************************************************* +** +** Function BTM_BleReadAdvParams +** +** Description This function is called to set advertising parameters. +** +** Parameters adv_int_min: minimum advertising interval +** adv_int_max: maximum advertising interval +** p_dir_bda: connectable direct initiator's LE device address +** chnl_map: advertising channel map. +** +** Returns void +** +*******************************************************************************/ +void BTM_BleReadAdvParams (UINT16 *adv_int_min, UINT16 *adv_int_max, + tBLE_BD_ADDR *p_dir_bda, tBTM_BLE_ADV_CHNL_MAP *p_chnl_map) +{ + tBTM_BLE_INQ_CB *p_cb = &btm_cb.ble_ctr_cb.inq_var; + + BTM_TRACE_EVENT ("BTM_BleReadAdvParams "); + if (!controller_get_interface()->supports_ble()) + return ; + + *adv_int_min = p_cb->adv_interval_min; + *adv_int_max = p_cb->adv_interval_max; + *p_chnl_map = p_cb->adv_chnl_map; + + if (p_dir_bda != NULL) + { + memcpy(p_dir_bda, &p_cb->direct_bda, sizeof(tBLE_BD_ADDR)); + } +} + +/******************************************************************************* +** +** Function BTM_BleSetScanParams +** +** Description This function is called to set scan parameters. +** +** Parameters client_if - Client IF +** scan_interval - Scan interval +** scan_window - Scan window +** scan_mode - Scan mode +** scan_setup_status_cback - Scan param setup status callback +** +** Returns void +** +*******************************************************************************/ +void BTM_BleSetScanParams(tGATT_IF client_if, UINT32 scan_interval, UINT32 scan_window, + tBLE_SCAN_MODE scan_mode, + tBLE_SCAN_PARAM_SETUP_CBACK scan_setup_status_cback) +{ + tBTM_BLE_INQ_CB *p_cb = &btm_cb.ble_ctr_cb.inq_var; + UINT32 max_scan_interval; + UINT32 max_scan_window; + + BTM_TRACE_EVENT ("%s", __func__); + if (!controller_get_interface()->supports_ble()) + return; + + /* If not supporting extended scan support, use the older range for checking */ + if (btm_cb.cmn_ble_vsc_cb.extended_scan_support == 0) + { + max_scan_interval = BTM_BLE_SCAN_INT_MAX; + max_scan_window = BTM_BLE_SCAN_WIN_MAX; + } + else + { + /* If supporting extended scan support, use the new extended range for checking */ + max_scan_interval = BTM_BLE_EXT_SCAN_INT_MAX; + max_scan_window = BTM_BLE_EXT_SCAN_WIN_MAX; + } + + if (BTM_BLE_ISVALID_PARAM(scan_interval, BTM_BLE_SCAN_INT_MIN, max_scan_interval) && + BTM_BLE_ISVALID_PARAM(scan_window, BTM_BLE_SCAN_WIN_MIN, max_scan_window) && + (scan_mode == BTM_BLE_SCAN_MODE_ACTI || scan_mode == BTM_BLE_SCAN_MODE_PASS)) + { + p_cb->scan_type = scan_mode; + p_cb->scan_interval = scan_interval; + p_cb->scan_window = scan_window; + + if (scan_setup_status_cback != NULL) + scan_setup_status_cback(client_if, BTM_SUCCESS); + } + else + { + if (scan_setup_status_cback != NULL) + scan_setup_status_cback(client_if, BTM_ILLEGAL_VALUE); + + BTM_TRACE_ERROR("Illegal params: scan_interval = %d scan_window = %d", + scan_interval, scan_window); + } + +} + +/******************************************************************************* +** +** Function BTM_BleWriteScanRsp +** +** Description This function is called to write LE scan response. +** +** Parameters: p_scan_rsp: scan response information. +** +** Returns void +** +*******************************************************************************/ +tBTM_STATUS BTM_BleWriteScanRsp(tBTM_BLE_AD_MASK data_mask, tBTM_BLE_ADV_DATA *p_data) +{ + tBTM_STATUS status = BTM_NO_RESOURCES; + UINT8 rsp_data[BTM_BLE_AD_DATA_LEN], + *p = rsp_data; + + BTM_TRACE_EVENT (" BTM_BleWriteScanRsp"); + + if (!controller_get_interface()->supports_ble()) + return BTM_ILLEGAL_VALUE; + + memset(rsp_data, 0, BTM_BLE_AD_DATA_LEN); + btm_ble_build_adv_data(&data_mask, &p, p_data); + + if (btsnd_hcic_ble_set_scan_rsp_data((UINT8)(p - rsp_data), rsp_data)) + { + status = BTM_SUCCESS; + + if (data_mask != 0) + btm_cb.ble_ctr_cb.inq_var.scan_rsp = TRUE; + else + btm_cb.ble_ctr_cb.inq_var.scan_rsp = FALSE; + } + else + status = BTM_ILLEGAL_VALUE; + + return status; +} + +/******************************************************************************* +** +** Function BTM_BleWriteAdvData +** +** Description This function is called to write advertising data. +** +** Parameters: None. +** +** Returns void +** +*******************************************************************************/ +tBTM_STATUS BTM_BleWriteAdvData(tBTM_BLE_AD_MASK data_mask, tBTM_BLE_ADV_DATA *p_data) +{ + tBTM_BLE_LOCAL_ADV_DATA *p_cb_data = &btm_cb.ble_ctr_cb.inq_var.adv_data; + UINT8 *p; + tBTM_BLE_AD_MASK mask = data_mask; + + BTM_TRACE_EVENT ("BTM_BleWriteAdvData "); + + if (!controller_get_interface()->supports_ble()) + return BTM_ILLEGAL_VALUE; + + memset(p_cb_data, 0, sizeof(tBTM_BLE_LOCAL_ADV_DATA)); + p = p_cb_data->ad_data; + p_cb_data->data_mask = data_mask; + + p_cb_data->p_flags = btm_ble_build_adv_data(&mask, &p, p_data); + + p_cb_data->p_pad = p; + + if (mask != 0) + { + BTM_TRACE_ERROR("Partial data write into ADV"); + } + + p_cb_data->data_mask &= ~mask; + + if (btsnd_hcic_ble_set_adv_data((UINT8)(p_cb_data->p_pad - p_cb_data->ad_data), + p_cb_data->ad_data)) + return BTM_SUCCESS; + else + return BTM_NO_RESOURCES; + +} + + +/******************************************************************************* +** +** Function BTM_BleSetRandAddress +** +** Description This function is called to set the LE random address. +** +** Parameters: None. +** +** Returns void +** +*******************************************************************************/ +BOOLEAN BTM_BleSetRandAddress(BD_ADDR rand_addr) +{ + BOOLEAN set_flag = false; + UINT8 len = sizeof(rand_addr); + if(len != BD_ADDR_LEN) + { + APPL_TRACE_ERROR("Invalid random adress"); + return false; + } + //send the set random address to the controller + set_flag = btsnd_hcic_ble_set_random_addr(rand_addr); + return set_flag; +} + +/******************************************************************************* +** +** Function BTM_CheckAdvData +** +** Description This function is called to get ADV data for a specific type. +** +** Parameters p_adv - pointer of ADV data +** type - finding ADV data type +** p_length - return the length of ADV data not including type +** +** Returns pointer of ADV data +** +*******************************************************************************/ +UINT8 *BTM_CheckAdvData( UINT8 *p_adv, UINT8 type, UINT8 *p_length) +{ + UINT8 *p = p_adv; + UINT8 length; + UINT8 adv_type; + BTM_TRACE_API("BTM_CheckAdvData type=0x%02X", type); + + STREAM_TO_UINT8(length, p); + + while ( length && (p - p_adv <= BTM_BLE_CACHE_ADV_DATA_MAX)) + { + STREAM_TO_UINT8(adv_type, p); + + if ( adv_type == type ) + { + /* length doesn't include itself */ + *p_length = length - 1; /* minus the length of type */ + return p; + } + p += length - 1; /* skip the length of data */ + STREAM_TO_UINT8(length, p); + } + + *p_length = 0; + return NULL; +} + +/******************************************************************************* +** +** Function BTM__BLEReadDiscoverability +** +** Description This function is called to read the current LE discoverability +** mode of the device. +** +** Returns BTM_BLE_NON_DISCOVERABLE ,BTM_BLE_LIMITED_DISCOVERABLE or +** BTM_BLE_GENRAL_DISCOVERABLE +** +*******************************************************************************/ +UINT16 BTM_BleReadDiscoverability() +{ + BTM_TRACE_API("%s", __FUNCTION__); + + return (btm_cb.ble_ctr_cb.inq_var.discoverable_mode); +} + +/******************************************************************************* +** +** Function BTM__BLEReadConnectability +** +** Description This function is called to read the current LE connectibility +** mode of the device. +** +** Returns BTM_BLE_NON_CONNECTABLE or BTM_BLE_CONNECTABLE +** +*******************************************************************************/ +UINT16 BTM_BleReadConnectability() +{ + BTM_TRACE_API ("%s", __FUNCTION__); + + return (btm_cb.ble_ctr_cb.inq_var.connectable_mode); +} + +/******************************************************************************* +** +** Function btm_ble_build_adv_data +** +** Description This function is called build the adv data and rsp data. +*******************************************************************************/ +UINT8 *btm_ble_build_adv_data(tBTM_BLE_AD_MASK *p_data_mask, UINT8 **p_dst, + tBTM_BLE_ADV_DATA *p_data) +{ + UINT32 data_mask = *p_data_mask; + UINT8 *p = *p_dst, + *p_flag = NULL; + UINT16 len = BTM_BLE_AD_DATA_LEN, cp_len = 0; + UINT8 i = 0; + tBTM_BLE_PROP_ELEM *p_elem; + + BTM_TRACE_EVENT (" btm_ble_build_adv_data"); + + /* build the adv data structure and build the data string */ + if (data_mask) + { + /* flags */ + if (data_mask & BTM_BLE_AD_BIT_FLAGS) + { + *p++ = MIN_ADV_LENGTH; + *p++ = BTM_BLE_AD_TYPE_FLAG; + p_flag = p; + if (p_data) + *p++ = p_data->flag; + else + *p++ = 0; + + len -= 3; + + data_mask &= ~BTM_BLE_AD_BIT_FLAGS; + } + /* appearance data */ + if (len > 3 && data_mask & BTM_BLE_AD_BIT_APPEARANCE) + { + *p++ = 3; /* length */ + *p++ = BTM_BLE_AD_TYPE_APPEARANCE; + UINT16_TO_STREAM(p, p_data->appearance); + len -= 4; + + data_mask &= ~BTM_BLE_AD_BIT_APPEARANCE; + } + /* device name */ +#if BTM_MAX_LOC_BD_NAME_LEN > 0 + if (len > MIN_ADV_LENGTH && data_mask & BTM_BLE_AD_BIT_DEV_NAME) + { + if (strlen(btm_cb.cfg.bd_name) > (UINT16)(len - MIN_ADV_LENGTH)) + { + *p++ = len - MIN_ADV_LENGTH + 1; + *p++ = BTM_BLE_AD_TYPE_NAME_SHORT; + ARRAY_TO_STREAM(p, btm_cb.cfg.bd_name, len - MIN_ADV_LENGTH); + } + else + { + cp_len = (UINT16)strlen(btm_cb.cfg.bd_name); + *p++ = cp_len + 1; + *p++ = BTM_BLE_AD_TYPE_NAME_CMPL; + ARRAY_TO_STREAM(p, btm_cb.cfg.bd_name, cp_len); + } + len -= (cp_len + MIN_ADV_LENGTH); + data_mask &= ~BTM_BLE_AD_BIT_DEV_NAME; + } +#endif + /* manufacturer data */ + if (len > MIN_ADV_LENGTH && data_mask & BTM_BLE_AD_BIT_MANU && + p_data && p_data->p_manu && + p_data->p_manu->len != 0 && p_data->p_manu->p_val) + { + if (p_data->p_manu->len > (len - MIN_ADV_LENGTH)) + cp_len = len - MIN_ADV_LENGTH; + else + cp_len = p_data->p_manu->len; + LOG_ERROR("cp_len = %d\n,p_data->p_manu->len=%d\n",cp_len,p_data->p_manu->len); + for(int i = 0; i < p_data->p_manu->len; i++) + { + LOG_ERROR("p_data->p_manu->p_val[%d] = %x\n",i,p_data->p_manu->p_val[i]); + } + *p++ = cp_len + 1; + *p++ = BTM_BLE_AD_TYPE_MANU; + ARRAY_TO_STREAM(p, p_data->p_manu->p_val, cp_len); + LOG_ERROR("p_addr = %p\n,p_data->p_manu->p_val = %p\n",p,p_data->p_manu->p_val); + len -= (cp_len + MIN_ADV_LENGTH); + data_mask &= ~BTM_BLE_AD_BIT_MANU; + } + /* TX power */ + if (len > MIN_ADV_LENGTH && data_mask & BTM_BLE_AD_BIT_TX_PWR) + { + *p++ = MIN_ADV_LENGTH; + *p++ = BTM_BLE_AD_TYPE_TX_PWR; + if (p_data->tx_power > BTM_BLE_ADV_TX_POWER_MAX) + p_data->tx_power = BTM_BLE_ADV_TX_POWER_MAX; + *p++ = btm_ble_map_adv_tx_power(p_data->tx_power); + len -= 3; + data_mask &= ~BTM_BLE_AD_BIT_TX_PWR; + } + /* 16 bits services */ + if (len > MIN_ADV_LENGTH && data_mask & BTM_BLE_AD_BIT_SERVICE && + p_data && p_data->p_services && + p_data->p_services->num_service != 0 && + p_data->p_services->p_uuid) + { + if (p_data->p_services->num_service * LEN_UUID_16 > (len - MIN_ADV_LENGTH)) + { + cp_len = (len - MIN_ADV_LENGTH)/LEN_UUID_16; + *p ++ = 1 + cp_len * LEN_UUID_16; + *p++ = BTM_BLE_AD_TYPE_16SRV_PART; + } + else + { + cp_len = p_data->p_services->num_service; + *p++ = 1 + cp_len * LEN_UUID_16; + *p++ = BTM_BLE_AD_TYPE_16SRV_CMPL; + } + for (i = 0; i < cp_len; i ++) + { + UINT16_TO_STREAM(p, *(p_data->p_services->p_uuid + i)); + } + + len -= (cp_len * MIN_ADV_LENGTH + MIN_ADV_LENGTH); + data_mask &= ~BTM_BLE_AD_BIT_SERVICE; + } + /* 32 bits service uuid */ + if (len > MIN_ADV_LENGTH && data_mask & BTM_BLE_AD_BIT_SERVICE_32 && + p_data && p_data->p_service_32b && + p_data->p_service_32b->num_service != 0 && + p_data->p_service_32b->p_uuid) + { + if ((p_data->p_service_32b->num_service * LEN_UUID_32) > (len - MIN_ADV_LENGTH)) + { + cp_len = (len - MIN_ADV_LENGTH)/LEN_UUID_32; + *p ++ = 1 + cp_len * LEN_UUID_32; + *p++ = BTM_BLE_AD_TYPE_32SRV_PART; + } + else + { + cp_len = p_data->p_service_32b->num_service; + *p++ = 1 + cp_len * LEN_UUID_32; + *p++ = BTM_BLE_AD_TYPE_32SRV_CMPL; + } + for (i = 0; i < cp_len; i ++) + { + UINT32_TO_STREAM(p, *(p_data->p_service_32b->p_uuid + i)); + } + + len -= (cp_len * LEN_UUID_32 + MIN_ADV_LENGTH); + data_mask &= ~BTM_BLE_AD_BIT_SERVICE_32; + } + /* 128 bits services */ + if (len >= (MAX_UUID_SIZE + 2) && data_mask & BTM_BLE_AD_BIT_SERVICE_128 && + p_data && p_data->p_services_128b) + { + *p ++ = 1 + MAX_UUID_SIZE; + if (!p_data->p_services_128b->list_cmpl) + *p++ = BTM_BLE_AD_TYPE_128SRV_PART; + else + *p++ = BTM_BLE_AD_TYPE_128SRV_CMPL; + + ARRAY_TO_STREAM(p, p_data->p_services_128b->uuid128, MAX_UUID_SIZE); + + len -= (MAX_UUID_SIZE + MIN_ADV_LENGTH); + data_mask &= ~BTM_BLE_AD_BIT_SERVICE_128; + } + /* 32 bits Service Solicitation UUIDs */ + if (len > MIN_ADV_LENGTH && data_mask & BTM_BLE_AD_BIT_SERVICE_32SOL && + p_data && p_data->p_sol_service_32b && + p_data->p_sol_service_32b->num_service != 0 && + p_data->p_sol_service_32b->p_uuid) + { + if ((p_data->p_sol_service_32b->num_service * LEN_UUID_32) > (len - MIN_ADV_LENGTH)) + { + cp_len = (len - MIN_ADV_LENGTH)/LEN_UUID_32; + *p ++ = 1 + cp_len * LEN_UUID_32; + } + else + { + cp_len = p_data->p_sol_service_32b->num_service; + *p++ = 1 + cp_len * LEN_UUID_32; + } + + *p++ = BTM_BLE_AD_TYPE_32SOL_SRV_UUID; + for (i = 0; i < cp_len; i ++) + { + UINT32_TO_STREAM(p, *(p_data->p_sol_service_32b->p_uuid + i)); + } + + len -= (cp_len * LEN_UUID_32 + MIN_ADV_LENGTH); + data_mask &= ~BTM_BLE_AD_BIT_SERVICE_32SOL; + } + /* 128 bits Solicitation services UUID */ + if (len >= (MAX_UUID_SIZE + MIN_ADV_LENGTH) && data_mask & BTM_BLE_AD_BIT_SERVICE_128SOL && + p_data && p_data->p_sol_service_128b) + { + *p ++ = 1 + MAX_UUID_SIZE; + *p++ = BTM_BLE_AD_TYPE_128SOL_SRV_UUID; + ARRAY_TO_STREAM(p, p_data->p_sol_service_128b->uuid128, MAX_UUID_SIZE); + len -= (MAX_UUID_SIZE + MIN_ADV_LENGTH); + data_mask &= ~BTM_BLE_AD_BIT_SERVICE_128SOL; + } + /* 16bits/32bits/128bits Service Data */ + if (len > MIN_ADV_LENGTH && data_mask & BTM_BLE_AD_BIT_SERVICE_DATA && + p_data && p_data->p_service_data->len != 0 && p_data->p_service_data->p_val) + { + if (len > (p_data->p_service_data->service_uuid.len + MIN_ADV_LENGTH)) + { + if (p_data->p_service_data->len > (len - MIN_ADV_LENGTH)) + cp_len = len - MIN_ADV_LENGTH- p_data->p_service_data->service_uuid.len; + else + cp_len = p_data->p_service_data->len; + + *p++ = cp_len + 1 + p_data->p_service_data->service_uuid.len; + if (p_data->p_service_data->service_uuid.len == LEN_UUID_16) + { + *p++ = BTM_BLE_AD_TYPE_SERVICE_DATA; + UINT16_TO_STREAM(p, p_data->p_service_data->service_uuid.uu.uuid16); + } + else if (p_data->p_service_data->service_uuid.len == LEN_UUID_32) + { + *p++ = BTM_BLE_AD_TYPE_32SERVICE_DATA; + UINT32_TO_STREAM(p, p_data->p_service_data->service_uuid.uu.uuid32); + } + else + { + *p++ = BTM_BLE_AD_TYPE_128SERVICE_DATA; + ARRAY_TO_STREAM(p, p_data->p_service_data->service_uuid.uu.uuid128, + LEN_UUID_128); + } + + ARRAY_TO_STREAM(p, p_data->p_service_data->p_val, cp_len); + + len -= (cp_len + MIN_ADV_LENGTH + p_data->p_service_data->service_uuid.len); + data_mask &= ~BTM_BLE_AD_BIT_SERVICE_DATA; + } + else + { + BTM_TRACE_WARNING("service data does not fit"); + } + } + + if (len >= 6 && data_mask & BTM_BLE_AD_BIT_INT_RANGE && + p_data) + { + *p++ = 5; + *p++ = BTM_BLE_AD_TYPE_INT_RANGE; + UINT16_TO_STREAM(p, p_data->int_range.low); + UINT16_TO_STREAM(p, p_data->int_range.hi); + len -= 6; + data_mask &= ~BTM_BLE_AD_BIT_INT_RANGE; + } + if (data_mask & BTM_BLE_AD_BIT_PROPRIETARY && p_data && p_data->p_proprietary) + { + for (i = 0; i < p_data->p_proprietary->num_elem ; i ++) + { + p_elem = p_data->p_proprietary->p_elem + i; + + if (len >= (MIN_ADV_LENGTH + p_elem->len))/* len byte(1) + ATTR type(1) + Uuid len(2) + + value length */ + { + *p ++ = p_elem->len + 1; /* Uuid len + value length */ + *p ++ = p_elem->adv_type; + ARRAY_TO_STREAM(p, p_elem->p_val, p_elem->len); + + len -= (MIN_ADV_LENGTH + p_elem->len); + } + else + { + BTM_TRACE_WARNING("data exceed max adv packet length"); + break; + } + } + data_mask &= ~BTM_BLE_AD_BIT_PROPRIETARY; + } + } + + *p_data_mask = data_mask; + *p_dst = p; + + return p_flag; +} +/******************************************************************************* +** +** Function btm_ble_select_adv_interval +** +** Description select adv interval based on device mode +** +** Returns void +** +*******************************************************************************/ +void btm_ble_select_adv_interval(tBTM_BLE_INQ_CB *p_cb, UINT8 evt_type, UINT16 *p_adv_int_min, UINT16 *p_adv_int_max) +{ + if (p_cb->adv_interval_min && p_cb->adv_interval_max) + { + *p_adv_int_min = p_cb->adv_interval_min; + *p_adv_int_max = p_cb->adv_interval_max; + } + else + { + switch (evt_type) + { + case BTM_BLE_CONNECT_EVT: + case BTM_BLE_CONNECT_LO_DUTY_DIR_EVT: + *p_adv_int_min = *p_adv_int_max = BTM_BLE_GAP_ADV_FAST_INT_1; + break; + + case BTM_BLE_NON_CONNECT_EVT: + case BTM_BLE_DISCOVER_EVT: + *p_adv_int_min = *p_adv_int_max = BTM_BLE_GAP_ADV_FAST_INT_2; + break; + + /* connectable directed event */ + case BTM_BLE_CONNECT_DIR_EVT: + *p_adv_int_min = BTM_BLE_GAP_ADV_DIR_MIN_INT; + *p_adv_int_max = BTM_BLE_GAP_ADV_DIR_MAX_INT; + break; + + default: + *p_adv_int_min = *p_adv_int_max = BTM_BLE_GAP_ADV_SLOW_INT; + break; + } + } + return; +} + +/******************************************************************************* +** +** Function btm_ble_update_dmt_flag_bits +** +** Description Obtain updated adv flag value based on connect and discoverability mode. +** Also, setup DMT support value in the flag based on whether the controller +** supports both LE and BR/EDR. +** +** Parameters: flag_value (Input / Output) - flag value +** connect_mode (Input) - Connect mode value +** disc_mode (Input) - discoverability mode +** +** Returns void +** +*******************************************************************************/ +void btm_ble_update_dmt_flag_bits(UINT8 *adv_flag_value, const UINT16 connect_mode, + const UINT16 disc_mode) +{ + /* BR/EDR non-discoverable , non-connectable */ + if ((disc_mode & BTM_DISCOVERABLE_MASK) == 0 && + (connect_mode & BTM_CONNECTABLE_MASK) == 0) + *adv_flag_value |= BTM_BLE_BREDR_NOT_SPT; + else + *adv_flag_value &= ~BTM_BLE_BREDR_NOT_SPT; + + /* if local controller support, mark both controller and host support in flag */ + if (controller_get_interface()->supports_simultaneous_le_bredr()) + *adv_flag_value |= (BTM_BLE_DMT_CONTROLLER_SPT|BTM_BLE_DMT_HOST_SPT); + else + *adv_flag_value &= ~(BTM_BLE_DMT_CONTROLLER_SPT|BTM_BLE_DMT_HOST_SPT); +} + +/******************************************************************************* +** +** Function btm_ble_set_adv_flag +** +** Description Set adv flag in adv data. +** +** Parameters: connect_mode (Input)- Connect mode value +** disc_mode (Input) - discoverability mode +** +** Returns void +** +*******************************************************************************/ +void btm_ble_set_adv_flag(UINT16 connect_mode, UINT16 disc_mode) +{ + UINT8 flag = 0, old_flag = 0; + tBTM_BLE_LOCAL_ADV_DATA *p_adv_data = &btm_cb.ble_ctr_cb.inq_var.adv_data; + + if (p_adv_data->p_flags != NULL) + flag = old_flag = *(p_adv_data->p_flags); + + btm_ble_update_dmt_flag_bits (&flag, connect_mode, disc_mode); + + LOG_DEBUG("disc_mode %04x", disc_mode); + /* update discoverable flag */ + if (disc_mode & BTM_BLE_LIMITED_DISCOVERABLE) + { + flag &= ~BTM_BLE_GEN_DISC_FLAG; + flag |= BTM_BLE_LIMIT_DISC_FLAG; + } + else if (disc_mode & BTM_BLE_GENERAL_DISCOVERABLE) + { + flag |= BTM_BLE_GEN_DISC_FLAG; + flag &= ~BTM_BLE_LIMIT_DISC_FLAG; + } + else /* remove all discoverable flags */ + { + flag &= ~(BTM_BLE_LIMIT_DISC_FLAG|BTM_BLE_GEN_DISC_FLAG); + } + + if (flag != old_flag) + { + LOG_ERROR("flag = 0x%x,old_flag = 0x%x", flag, old_flag); + btm_ble_update_adv_flag(flag); + } +} +/******************************************************************************* +** +** Function btm_ble_set_discoverability +** +** Description This function is called to set BLE discoverable mode. +** +** Parameters: combined_mode: discoverability mode. +** +** Returns BTM_SUCCESS is status set successfully; otherwise failure. +** +*******************************************************************************/ +tBTM_STATUS btm_ble_set_discoverability(UINT16 combined_mode) +{ + tBTM_LE_RANDOM_CB *p_addr_cb = &btm_cb.ble_ctr_cb.addr_mgnt_cb; + tBTM_BLE_INQ_CB *p_cb = &btm_cb.ble_ctr_cb.inq_var; + UINT16 mode = (combined_mode & BTM_BLE_DISCOVERABLE_MASK); + UINT8 new_mode = BTM_BLE_ADV_ENABLE; + UINT8 evt_type; + tBTM_STATUS status = BTM_SUCCESS; + BD_ADDR p_addr_ptr= {0}; + tBLE_ADDR_TYPE init_addr_type = BLE_ADDR_PUBLIC, + own_addr_type = p_addr_cb->own_addr_type; + UINT16 adv_int_min, adv_int_max; + + BTM_TRACE_EVENT ("%s mode=0x%0x combined_mode=0x%x", __FUNCTION__, mode, combined_mode); + + /*** Check mode parameter ***/ + if (mode > BTM_BLE_MAX_DISCOVERABLE) + return(BTM_ILLEGAL_VALUE); + + p_cb->discoverable_mode = mode; + + evt_type = btm_set_conn_mode_adv_init_addr(p_cb, p_addr_ptr, &init_addr_type, &own_addr_type); + + if (p_cb->connectable_mode == BTM_BLE_NON_CONNECTABLE && mode == BTM_BLE_NON_DISCOVERABLE) + new_mode = BTM_BLE_ADV_DISABLE; + + btm_ble_select_adv_interval(p_cb, evt_type, &adv_int_min, &adv_int_max); + + btu_stop_timer(&p_cb->fast_adv_timer); + + /* update adv params if start advertising */ + BTM_TRACE_EVENT ("evt_type=0x%x p-cb->evt_type=0x%x ", evt_type, p_cb->evt_type); + + if (new_mode == BTM_BLE_ADV_ENABLE) + { + btm_ble_set_adv_flag (btm_cb.btm_inq_vars.connectable_mode, combined_mode); + + if (evt_type != p_cb->evt_type ||p_cb->adv_addr_type != own_addr_type + || !p_cb->fast_adv_on) + { + btm_ble_stop_adv(); + + /* update adv params */ + if (!btsnd_hcic_ble_write_adv_params (adv_int_min, + adv_int_max, + evt_type, + own_addr_type, + init_addr_type, + p_addr_ptr, + p_cb->adv_chnl_map, + p_cb->afp)) + { + status = BTM_NO_RESOURCES; + } + else + { + p_cb->evt_type = evt_type; + p_cb->adv_addr_type = own_addr_type; + } + } + } + + if (status == BTM_SUCCESS && p_cb->adv_mode != new_mode) + { + if (new_mode == BTM_BLE_ADV_ENABLE) + status = btm_ble_start_adv(); + else + status = btm_ble_stop_adv(); + } + + if (p_cb->adv_mode == BTM_BLE_ADV_ENABLE) + { + p_cb->fast_adv_on = TRUE; + /* start initial GAP mode adv timer */ + btu_start_timer (&p_cb->fast_adv_timer, BTU_TTYPE_BLE_GAP_FAST_ADV, + BTM_BLE_GAP_FAST_ADV_TOUT); + } + else + { +#if BLE_PRIVACY_SPT == TRUE + btm_ble_disable_resolving_list(BTM_BLE_RL_ADV, TRUE); +#endif + } + + /* set up stop advertising timer */ + if (status == BTM_SUCCESS && mode == BTM_BLE_LIMITED_DISCOVERABLE) + { + BTM_TRACE_EVENT ("start timer for limited disc mode duration=%d (180 secs)", BTM_BLE_GAP_LIM_TOUT); + /* start Tgap(lim_timeout) */ + btu_start_timer (&p_cb->inq_timer_ent, BTU_TTYPE_BLE_GAP_LIM_DISC, + BTM_BLE_GAP_LIM_TOUT); + } + return status; +} + +/******************************************************************************* +** +** Function btm_ble_set_connectability +** +** Description This function is called to set BLE connectability mode. +** +** Parameters: combined_mode: connectability mode. +** +** Returns BTM_SUCCESS is status set successfully; otherwise failure. +** +*******************************************************************************/ +tBTM_STATUS btm_ble_set_connectability(UINT16 combined_mode) +{ + tBTM_LE_RANDOM_CB *p_addr_cb = &btm_cb.ble_ctr_cb.addr_mgnt_cb; + tBTM_BLE_INQ_CB *p_cb = &btm_cb.ble_ctr_cb.inq_var; + UINT16 mode = (combined_mode & BTM_BLE_CONNECTABLE_MASK); + UINT8 new_mode = BTM_BLE_ADV_ENABLE; + UINT8 evt_type; + tBTM_STATUS status = BTM_SUCCESS; + BD_ADDR p_addr_ptr = {0}; + tBLE_ADDR_TYPE peer_addr_type = BLE_ADDR_PUBLIC, + own_addr_type = p_addr_cb->own_addr_type; + UINT16 adv_int_min, adv_int_max; + + BTM_TRACE_EVENT ("%s mode=0x%0x combined_mode=0x%x", __FUNCTION__, mode, combined_mode); + + /*** Check mode parameter ***/ + if (mode > BTM_BLE_MAX_CONNECTABLE) + return(BTM_ILLEGAL_VALUE); + + p_cb->connectable_mode = mode; + + evt_type = btm_set_conn_mode_adv_init_addr(p_cb, p_addr_ptr, &peer_addr_type, &own_addr_type); + + if (mode == BTM_BLE_NON_CONNECTABLE && p_cb->discoverable_mode == BTM_BLE_NON_DISCOVERABLE) + new_mode = BTM_BLE_ADV_DISABLE; + + btm_ble_select_adv_interval(p_cb, evt_type, &adv_int_min, &adv_int_max); + + btu_stop_timer(&p_cb->fast_adv_timer); + /* update adv params if needed */ + if (new_mode == BTM_BLE_ADV_ENABLE) + { + btm_ble_set_adv_flag (combined_mode, btm_cb.btm_inq_vars.discoverable_mode); + if (p_cb->evt_type != evt_type || p_cb->adv_addr_type != p_addr_cb->own_addr_type + || !p_cb->fast_adv_on) + { + btm_ble_stop_adv(); + + if (!btsnd_hcic_ble_write_adv_params (adv_int_min, + adv_int_max, + evt_type, + own_addr_type, + peer_addr_type, + p_addr_ptr, + p_cb->adv_chnl_map, + p_cb->afp)) + { + status = BTM_NO_RESOURCES; + } + else + { + p_cb->evt_type = evt_type; + p_cb->adv_addr_type = own_addr_type; + } + } + } + + /* update advertising mode */ + if (status == BTM_SUCCESS && new_mode != p_cb->adv_mode) + { + if (new_mode == BTM_BLE_ADV_ENABLE) + status = btm_ble_start_adv(); + else + status = btm_ble_stop_adv(); + } + + if (p_cb->adv_mode == BTM_BLE_ADV_ENABLE) + { + p_cb->fast_adv_on = TRUE; + /* start initial GAP mode adv timer */ + btu_start_timer (&p_cb->fast_adv_timer, BTU_TTYPE_BLE_GAP_FAST_ADV, + BTM_BLE_GAP_FAST_ADV_TOUT); + } + else + { +#if BLE_PRIVACY_SPT == TRUE + btm_ble_disable_resolving_list(BTM_BLE_RL_ADV, TRUE); +#endif + } + return status; +} + + +/******************************************************************************* +** +** Function btm_ble_start_inquiry +** +** Description This function is called to start BLE inquiry procedure. +** If the duration is zero, the periodic inquiry mode is cancelled. +** +** Parameters: mode - GENERAL or LIMITED inquiry +** p_inq_params - pointer to the BLE inquiry parameter. +** p_results_cb - callback returning pointer to results (tBTM_INQ_RESULTS) +** p_cmpl_cb - callback indicating the end of an inquiry +** +** +** +** Returns BTM_CMD_STARTED if successfully started +** BTM_NO_RESOURCES if could not allocate a message buffer +** BTM_BUSY - if an inquiry is already active +** +*******************************************************************************/ +tBTM_STATUS btm_ble_start_inquiry (UINT8 mode, UINT8 duration) +{ + tBTM_STATUS status = BTM_CMD_STARTED; + tBTM_BLE_CB *p_ble_cb = &btm_cb.ble_ctr_cb; + tBTM_INQUIRY_VAR_ST *p_inq = &btm_cb.btm_inq_vars; + + BTM_TRACE_DEBUG("btm_ble_start_inquiry: mode = %02x inq_active = 0x%02x", mode, btm_cb.btm_inq_vars.inq_active); + + /* if selective connection is active, or inquiry is already active, reject it */ + if (BTM_BLE_IS_INQ_ACTIVE(p_ble_cb->scan_activity) || + BTM_BLE_IS_SEL_CONN_ACTIVE (p_ble_cb->scan_activity)) + { + BTM_TRACE_ERROR("LE Inquiry is active, can not start inquiry"); + return(BTM_BUSY); + } + + if (!BTM_BLE_IS_SCAN_ACTIVE(p_ble_cb->scan_activity)) + { + btsnd_hcic_ble_set_scan_params(BTM_BLE_SCAN_MODE_ACTI, + BTM_BLE_LOW_LATENCY_SCAN_INT, + BTM_BLE_LOW_LATENCY_SCAN_WIN, + btm_cb.ble_ctr_cb.addr_mgnt_cb.own_addr_type, + SP_ADV_ALL); +#if (defined BLE_PRIVACY_SPT && BLE_PRIVACY_SPT == TRUE) + /* enable IRK list */ + btm_ble_enable_resolving_list_for_platform(BTM_BLE_RL_SCAN); +#endif + p_ble_cb->inq_var.scan_duplicate_filter = BTM_BLE_DUPLICATE_DISABLE; + status = btm_ble_start_scan(); + } + else if ((p_ble_cb->inq_var.scan_interval != BTM_BLE_LOW_LATENCY_SCAN_INT) || + (p_ble_cb->inq_var.scan_window != BTM_BLE_LOW_LATENCY_SCAN_WIN)) { + BTM_TRACE_DEBUG("%s, restart LE scan with low latency scan params", __FUNCTION__); + btsnd_hcic_ble_set_scan_enable(BTM_BLE_SCAN_DISABLE, BTM_BLE_DUPLICATE_ENABLE); + btsnd_hcic_ble_set_scan_params(BTM_BLE_SCAN_MODE_ACTI, + BTM_BLE_LOW_LATENCY_SCAN_INT, + BTM_BLE_LOW_LATENCY_SCAN_WIN, + btm_cb.ble_ctr_cb.addr_mgnt_cb.own_addr_type, + SP_ADV_ALL); + btsnd_hcic_ble_set_scan_enable(BTM_BLE_SCAN_ENABLE, BTM_BLE_DUPLICATE_DISABLE); + } + + if (status == BTM_CMD_STARTED) + { + p_inq->inq_active |= mode; + p_ble_cb->scan_activity |= mode; + + BTM_TRACE_DEBUG("btm_ble_start_inquiry inq_active = 0x%02x", p_inq->inq_active); + + if (duration != 0) + { + /* start inquiry timer */ + btu_start_timer (&p_ble_cb->inq_var.inq_timer_ent, BTU_TTYPE_BLE_INQUIRY, duration); + } + } + + return status; + +} + +/******************************************************************************* +** +** Function btm_ble_read_remote_name_cmpl +** +** Description This function is called when BLE remote name is received. +** +** Returns void +** +*******************************************************************************/ +void btm_ble_read_remote_name_cmpl(BOOLEAN status, BD_ADDR bda, UINT16 length, char *p_name) +{ + UINT8 hci_status = HCI_SUCCESS; + BD_NAME bd_name; + + memset(bd_name, 0, (BD_NAME_LEN + 1)); + if (length > BD_NAME_LEN) + { + length = BD_NAME_LEN; + } + memcpy((UINT8*)bd_name, p_name, length); + + if ((!status) || (length==0)) + { + hci_status = HCI_ERR_HOST_TIMEOUT; + } + + btm_process_remote_name(bda, bd_name, length +1, hci_status); + btm_sec_rmt_name_request_complete (bda, (UINT8 *)p_name, hci_status); +} + +/******************************************************************************* +** +** Function btm_ble_read_remote_name +** +** Description This function read remote LE device name using GATT read +** procedure. +** +** Parameters: None. +** +** Returns void +** +*******************************************************************************/ +tBTM_STATUS btm_ble_read_remote_name(BD_ADDR remote_bda, tBTM_INQ_INFO *p_cur, tBTM_CMPL_CB *p_cb) +{ + tBTM_INQUIRY_VAR_ST *p_inq = &btm_cb.btm_inq_vars; + + if (!controller_get_interface()->supports_ble()) + return BTM_ERR_PROCESSING; + + if (p_cur && + p_cur->results.ble_evt_type != BTM_BLE_EVT_CONN_ADV && + p_cur->results.ble_evt_type != BTM_BLE_EVT_CONN_DIR_ADV) + { + BTM_TRACE_DEBUG("name request to non-connectable device failed."); + return BTM_ERR_PROCESSING; + } + + /* read remote device name using GATT procedure */ + if (p_inq->remname_active) + return BTM_BUSY; + +#if (defined(GAP_INCLUDED) && GAP_INCLUDED == TRUE) + if (!GAP_BleReadPeerDevName(remote_bda, btm_ble_read_remote_name_cmpl)) + return BTM_BUSY; +#endif + + p_inq->p_remname_cmpl_cb = p_cb; + p_inq->remname_active = TRUE; + + memcpy(p_inq->remname_bda, remote_bda, BD_ADDR_LEN); + + btu_start_timer (&p_inq->rmt_name_timer_ent, + BTU_TTYPE_BTM_RMT_NAME, + BTM_EXT_BLE_RMT_NAME_TIMEOUT); + + return BTM_CMD_STARTED; +} + +/******************************************************************************* +** +** Function btm_ble_cancel_remote_name +** +** Description This function cancel read remote LE device name. +** +** Parameters: None. +** +** Returns void +** +*******************************************************************************/ +BOOLEAN btm_ble_cancel_remote_name(BD_ADDR remote_bda) +{ + tBTM_INQUIRY_VAR_ST *p_inq = &btm_cb.btm_inq_vars; + BOOLEAN status = TRUE; + +#if (defined(GAP_INCLUDED) && GAP_INCLUDED == TRUE) + status = GAP_BleCancelReadPeerDevName(remote_bda); +#endif + + p_inq->remname_active = FALSE; + memset(p_inq->remname_bda, 0, BD_ADDR_LEN); + btu_stop_timer(&p_inq->rmt_name_timer_ent); + + return status; +} + +/******************************************************************************* +** +** Function btm_ble_update_adv_flag +** +** Description This function update the limited discoverable flag in the adv +** data. +** +** Parameters: None. +** +** Returns void +** +*******************************************************************************/ +static void btm_ble_update_adv_flag(UINT8 flag) +{ + tBTM_BLE_LOCAL_ADV_DATA *p_adv_data = &btm_cb.ble_ctr_cb.inq_var.adv_data; + UINT8 *p; + + BTM_TRACE_DEBUG ("btm_ble_update_adv_flag new=0x%x", flag); + + if (p_adv_data->p_flags != NULL) + { + BTM_TRACE_DEBUG ("btm_ble_update_adv_flag old=0x%x", *p_adv_data->p_flags); + *p_adv_data->p_flags = flag; + } + else /* no FLAGS in ADV data*/ + { + p = (p_adv_data->p_pad == NULL) ? p_adv_data->ad_data : p_adv_data->p_pad; + /* need 3 bytes space to stuff in the flags, if not */ + /* erase all written data, just for flags */ + if ((BTM_BLE_AD_DATA_LEN - (p - p_adv_data->ad_data)) < 3) + { + p = p_adv_data->p_pad = p_adv_data->ad_data; + memset(p_adv_data->ad_data, 0, BTM_BLE_AD_DATA_LEN); + } + + *p++ = 2; + *p++ = BTM_BLE_AD_TYPE_FLAG; + p_adv_data->p_flags = p; + *p++ = flag; + p_adv_data->p_pad = p; + } + + if (btsnd_hcic_ble_set_adv_data((UINT8)(p_adv_data->p_pad - p_adv_data->ad_data), + p_adv_data->ad_data)) + p_adv_data->data_mask |= BTM_BLE_AD_BIT_FLAGS; + +} + +#if 0 +/******************************************************************************* +** +** Function btm_ble_parse_adv_data +** +** Description This function parse the adv data into a structure. +** +** Returns pointer to entry, or NULL if not found +** +*******************************************************************************/ +static void btm_ble_parse_adv_data(tBTM_INQ_INFO *p_info, UINT8 *p_data, + UINT8 len, tBTM_BLE_INQ_DATA *p_adv_data, UINT8 *p_buf) +{ + UINT8 *p_cur = p_data; + UINT8 ad_len, ad_type, ad_flag; + + BTM_TRACE_EVENT (" btm_ble_parse_adv_data"); + + while (len > 0) + { + BTM_TRACE_DEBUG("btm_ble_parse_adv_data: len = %d", len); + if ((ad_len = *p_cur ++) == 0) + break; + + ad_type = *p_cur ++; + + BTM_TRACE_DEBUG(" ad_type = %02x ad_len = %d", ad_type, ad_len); + + switch (ad_type) + { + case BTM_BLE_AD_TYPE_NAME_SHORT: + + case BTM_BLE_AD_TYPE_NAME_CMPL: + p_adv_data->ad_mask |= BTM_BLE_AD_BIT_DEV_NAME; + if (p_info) + { + p_info->remote_name_type =(ad_type == BTM_BLE_AD_TYPE_NAME_SHORT) ? + BTM_BLE_NAME_SHORT: BTM_BLE_NAME_CMPL; + memcpy(p_info->remote_name, p_cur, ad_len -1); + p_info->remote_name[ad_len] = 0; + p_adv_data->p_remote_name = p_info->remote_name; + p_info->remote_name_len = p_adv_data->remote_name_len = ad_len - 1; + BTM_TRACE_DEBUG("BTM_BLE_AD_TYPE_NAME name = %s",p_adv_data->p_remote_name); + } + p_cur += (ad_len -1); + + break; + + case BTM_BLE_AD_TYPE_FLAG: + p_adv_data->ad_mask |= BTM_BLE_AD_BIT_FLAGS; + ad_flag = *p_cur ++; + p_adv_data->flag = (UINT8)(ad_flag & BTM_BLE_ADV_FLAG_MASK) ; + BTM_TRACE_DEBUG("BTM_BLE_AD_TYPE_FLAG flag = %s | %s | %s", + (p_adv_data->flag & BTM_BLE_LIMIT_DISC_FLAG)? "LE_LIMIT_DISC" : "", + (p_adv_data->flag & BTM_BLE_GEN_DISC_FLAG)? "LE_GENERAL_DISC" : "", + (p_adv_data->flag & BTM_BLE_BREDR_NOT_SPT)? "LE Only device" : ""); + break; + + case BTM_BLE_AD_TYPE_TX_PWR: + p_adv_data->ad_mask |= BTM_BLE_AD_BIT_TX_PWR; + p_adv_data->tx_power_level = (INT8)*p_cur ++; + BTM_TRACE_DEBUG("BTM_BLE_AD_TYPE_TX_PWR tx_level = %d", p_adv_data->tx_power_level); + break; + + case BTM_BLE_AD_TYPE_MANU: + + case BTM_BLE_AD_TYPE_16SRV_PART: + case BTM_BLE_AD_TYPE_16SRV_CMPL: + p_adv_data->ad_mask |= BTM_BLE_AD_BIT_SERVICE; + /* need allocate memory to store UUID list */ + p_adv_data->service.num_service = (ad_len - 1)/2; + BTM_TRACE_DEBUG("service UUID list, num = %d", p_adv_data->service.num_service); + p_cur += (ad_len - 1); + break; + + case BTM_BLE_AD_TYPE_SOL_SRV_UUID: + p_adv_data->ad_mask |= BTM_BLE_AD_BIT_SERVICE_SOL; + /* need allocate memory to store UUID list */ + p_adv_data->service.num_service = (ad_len - 1)/2; + BTM_TRACE_DEBUG("service UUID list, num = %d", p_adv_data->service.num_service); + p_cur += (ad_len - 1); + break; + + case BTM_BLE_AD_TYPE_128SOL_SRV_UUID: + p_adv_data->ad_mask |= BTM_BLE_AD_BIT_SERVICE_128SOL; + /* need allocate memory to store UUID list */ + p_adv_data->service.num_service = (ad_len - 1)/16; + BTM_TRACE_DEBUG("service UUID list, num = %d", p_adv_data->service.num_service); + p_cur += (ad_len - 1); + break; + + case BTM_BLE_AD_TYPE_APPEARANCE: + case BTM_BLE_AD_TYPE_PUBLIC_TARGET: + case BTM_BLE_AD_TYPE_RANDOM_TARGET: + default: + break; + } + len -= (ad_len + 1); + } +} +#endif + +/******************************************************************************* +** +** Function btm_ble_cache_adv_data +** +** Description Update advertising cache data. +** +** Returns void +** +*******************************************************************************/ +void btm_ble_cache_adv_data(tBTM_INQ_RESULTS *p_cur, UINT8 data_len, UINT8 *p, UINT8 evt_type) +{ + tBTM_BLE_INQ_CB *p_le_inq_cb = &btm_cb.ble_ctr_cb.inq_var; + UINT8 *p_cache; + UINT8 length; + UNUSED(p_cur); + + /* cache adv report/scan response data */ + if (evt_type != BTM_BLE_SCAN_RSP_EVT) + { + p_le_inq_cb->adv_len = 0; + memset(p_le_inq_cb->adv_data_cache, 0, BTM_BLE_CACHE_ADV_DATA_MAX); + } + + if (data_len > 0) + { + p_cache = &p_le_inq_cb->adv_data_cache[p_le_inq_cb->adv_len]; + STREAM_TO_UINT8(length, p); + while ( length && ((p_le_inq_cb->adv_len + length + 1) <= BTM_BLE_CACHE_ADV_DATA_MAX)) + { + /* copy from the length byte & data into cache */ + memcpy(p_cache, p-1, length+1); + /* advance the cache pointer past data */ + p_cache += length+1; + /* increment cache length */ + p_le_inq_cb->adv_len += length+1; + /* skip the length of data */ + p += length; + STREAM_TO_UINT8(length, p); + } + } + + /* parse service UUID from adv packet and save it in inq db eir_uuid */ + /* TODO */ +} + +/******************************************************************************* +** +** Function btm_ble_is_discoverable +** +** Description check ADV flag to make sure device is discoverable and match +** the search condition +** +** Parameters +** +** Returns void +** +*******************************************************************************/ +UINT8 btm_ble_is_discoverable(BD_ADDR bda, UINT8 evt_type, UINT8 *p) +{ + UINT8 *p_flag, flag = 0, rt = 0; + UINT8 data_len; + tBTM_INQ_PARMS *p_cond = &btm_cb.btm_inq_vars.inqparms; + tBTM_BLE_INQ_CB *p_le_inq_cb = &btm_cb.ble_ctr_cb.inq_var; + + UNUSED(p); + + /* for observer, always "discoverable */ + if (BTM_BLE_IS_OBS_ACTIVE(btm_cb.ble_ctr_cb.scan_activity)) + rt |= BTM_BLE_OBS_RESULT; + + if (BTM_BLE_IS_SEL_CONN_ACTIVE(btm_cb.ble_ctr_cb.scan_activity) && + (evt_type == BTM_BLE_CONNECT_EVT || evt_type == BTM_BLE_CONNECT_DIR_EVT)) + rt |= BTM_BLE_SEL_CONN_RESULT; + + /* does not match filter condition */ + if (p_cond->filter_cond_type == BTM_FILTER_COND_BD_ADDR && + memcmp(bda, p_cond->filter_cond.bdaddr_cond, BD_ADDR_LEN) != 0) + { + BTM_TRACE_DEBUG("BD ADDR does not meet filter condition"); + return rt; + } + + if (p_le_inq_cb->adv_len != 0) + { + if ((p_flag = BTM_CheckAdvData(p_le_inq_cb->adv_data_cache, + BTM_BLE_AD_TYPE_FLAG, &data_len)) != NULL) + { + flag = * p_flag; + + if ((btm_cb.btm_inq_vars.inq_active & BTM_BLE_GENERAL_INQUIRY) && + (flag & (BTM_BLE_LIMIT_DISC_FLAG|BTM_BLE_GEN_DISC_FLAG)) != 0) + { + BTM_TRACE_DEBUG("Find Generable Discoverable device"); + rt |= BTM_BLE_INQ_RESULT; + } + + else if (btm_cb.btm_inq_vars.inq_active & BTM_BLE_LIMITED_INQUIRY && + (flag & BTM_BLE_LIMIT_DISC_FLAG) != 0) + { + BTM_TRACE_DEBUG("Find limited discoverable device"); + rt |= BTM_BLE_INQ_RESULT; + } + } + } + return rt; +} + +static void btm_ble_appearance_to_cod(UINT16 appearance, UINT8 *dev_class) +{ + dev_class[0] = 0; + + switch (appearance) + { + case BTM_BLE_APPEARANCE_GENERIC_PHONE: + dev_class[1] = BTM_COD_MAJOR_PHONE; + dev_class[2] = BTM_COD_MINOR_UNCLASSIFIED; + break; + case BTM_BLE_APPEARANCE_GENERIC_COMPUTER: + dev_class[1] = BTM_COD_MAJOR_COMPUTER; + dev_class[2] = BTM_COD_MINOR_UNCLASSIFIED; + break; + case BTM_BLE_APPEARANCE_GENERIC_REMOTE: + dev_class[1] = BTM_COD_MAJOR_PERIPHERAL; + dev_class[2] = BTM_COD_MINOR_REMOTE_CONTROL; + break; + case BTM_BLE_APPEARANCE_GENERIC_THERMOMETER: + case BTM_BLE_APPEARANCE_THERMOMETER_EAR: + dev_class[1] = BTM_COD_MAJOR_HEALTH; + dev_class[2] = BTM_COD_MINOR_THERMOMETER; + break; + case BTM_BLE_APPEARANCE_GENERIC_HEART_RATE: + case BTM_BLE_APPEARANCE_HEART_RATE_BELT: + dev_class[1] = BTM_COD_MAJOR_HEALTH; + dev_class[2] = BTM_COD_MINOR_HEART_PULSE_MONITOR; + break; + case BTM_BLE_APPEARANCE_GENERIC_BLOOD_PRESSURE: + case BTM_BLE_APPEARANCE_BLOOD_PRESSURE_ARM: + case BTM_BLE_APPEARANCE_BLOOD_PRESSURE_WRIST: + dev_class[1] = BTM_COD_MAJOR_HEALTH; + dev_class[2] = BTM_COD_MINOR_BLOOD_MONITOR; + break; + case BTM_BLE_APPEARANCE_GENERIC_PULSE_OXIMETER: + case BTM_BLE_APPEARANCE_PULSE_OXIMETER_FINGERTIP: + case BTM_BLE_APPEARANCE_PULSE_OXIMETER_WRIST: + dev_class[1] = BTM_COD_MAJOR_HEALTH; + dev_class[2] = BTM_COD_MINOR_PULSE_OXIMETER; + break; + case BTM_BLE_APPEARANCE_GENERIC_GLUCOSE: + dev_class[1] = BTM_COD_MAJOR_HEALTH; + dev_class[2] = BTM_COD_MINOR_GLUCOSE_METER; + break; + case BTM_BLE_APPEARANCE_GENERIC_WEIGHT: + dev_class[1] = BTM_COD_MAJOR_HEALTH; + dev_class[2] = BTM_COD_MINOR_WEIGHING_SCALE; + break; + case BTM_BLE_APPEARANCE_GENERIC_WALKING: + case BTM_BLE_APPEARANCE_WALKING_IN_SHOE: + case BTM_BLE_APPEARANCE_WALKING_ON_SHOE: + case BTM_BLE_APPEARANCE_WALKING_ON_HIP: + dev_class[1] = BTM_COD_MAJOR_HEALTH; + dev_class[2] = BTM_COD_MINOR_STEP_COUNTER; + break; + case BTM_BLE_APPEARANCE_GENERIC_WATCH: + case BTM_BLE_APPEARANCE_SPORTS_WATCH: + dev_class[1] = BTM_COD_MAJOR_WEARABLE; + dev_class[2] = BTM_COD_MINOR_WRIST_WATCH; + break; + case BTM_BLE_APPEARANCE_GENERIC_EYEGLASSES: + dev_class[1] = BTM_COD_MAJOR_WEARABLE; + dev_class[2] = BTM_COD_MINOR_GLASSES; + break; + case BTM_BLE_APPEARANCE_GENERIC_DISPLAY: + dev_class[1] = BTM_COD_MAJOR_IMAGING; + dev_class[2] = BTM_COD_MINOR_DISPLAY; + break; + case BTM_BLE_APPEARANCE_GENERIC_MEDIA_PLAYER: + dev_class[1] = BTM_COD_MAJOR_AUDIO; + dev_class[2] = BTM_COD_MINOR_UNCLASSIFIED; + break; + case BTM_BLE_APPEARANCE_GENERIC_BARCODE_SCANNER: + case BTM_BLE_APPEARANCE_HID_BARCODE_SCANNER: + case BTM_BLE_APPEARANCE_GENERIC_HID: + dev_class[1] = BTM_COD_MAJOR_PERIPHERAL; + dev_class[2] = BTM_COD_MINOR_UNCLASSIFIED; + break; + case BTM_BLE_APPEARANCE_HID_KEYBOARD: + dev_class[1] = BTM_COD_MAJOR_PERIPHERAL; + dev_class[2] = BTM_COD_MINOR_KEYBOARD; + break; + case BTM_BLE_APPEARANCE_HID_MOUSE: + dev_class[1] = BTM_COD_MAJOR_PERIPHERAL; + dev_class[2] = BTM_COD_MINOR_POINTING; + break; + case BTM_BLE_APPEARANCE_HID_JOYSTICK: + dev_class[1] = BTM_COD_MAJOR_PERIPHERAL; + dev_class[2] = BTM_COD_MINOR_JOYSTICK; + break; + case BTM_BLE_APPEARANCE_HID_GAMEPAD: + dev_class[1] = BTM_COD_MAJOR_PERIPHERAL; + dev_class[2] = BTM_COD_MINOR_GAMEPAD; + break; + case BTM_BLE_APPEARANCE_HID_DIGITIZER_TABLET: + dev_class[1] = BTM_COD_MAJOR_PERIPHERAL; + dev_class[2] = BTM_COD_MINOR_DIGITIZING_TABLET; + break; + case BTM_BLE_APPEARANCE_HID_CARD_READER: + dev_class[1] = BTM_COD_MAJOR_PERIPHERAL; + dev_class[2] = BTM_COD_MINOR_CARD_READER; + break; + case BTM_BLE_APPEARANCE_HID_DIGITAL_PEN: + dev_class[1] = BTM_COD_MAJOR_PERIPHERAL; + dev_class[2] = BTM_COD_MINOR_DIGITAL_PAN; + break; + case BTM_BLE_APPEARANCE_UKNOWN: + case BTM_BLE_APPEARANCE_GENERIC_CLOCK: + case BTM_BLE_APPEARANCE_GENERIC_TAG: + case BTM_BLE_APPEARANCE_GENERIC_KEYRING: + case BTM_BLE_APPEARANCE_GENERIC_CYCLING: + case BTM_BLE_APPEARANCE_CYCLING_COMPUTER: + case BTM_BLE_APPEARANCE_CYCLING_SPEED: + case BTM_BLE_APPEARANCE_CYCLING_CADENCE: + case BTM_BLE_APPEARANCE_CYCLING_POWER: + case BTM_BLE_APPEARANCE_CYCLING_SPEED_CADENCE: + case BTM_BLE_APPEARANCE_GENERIC_OUTDOOR_SPORTS: + case BTM_BLE_APPEARANCE_OUTDOOR_SPORTS_LOCATION: + case BTM_BLE_APPEARANCE_OUTDOOR_SPORTS_LOCATION_AND_NAV: + case BTM_BLE_APPEARANCE_OUTDOOR_SPORTS_LOCATION_POD: + case BTM_BLE_APPEARANCE_OUTDOOR_SPORTS_LOCATION_POD_AND_NAV: + default: + dev_class[1] = BTM_COD_MAJOR_UNCLASSIFIED; + dev_class[2] = BTM_COD_MINOR_UNCLASSIFIED; + }; +} + +/******************************************************************************* +** +** Function btm_ble_update_inq_result +** +** Description Update adv packet information into inquiry result. +** +** Parameters +** +** Returns void +** +*******************************************************************************/ +BOOLEAN btm_ble_update_inq_result(tINQ_DB_ENT *p_i, UINT8 addr_type, UINT8 evt_type, UINT8 *p) +{ + BOOLEAN to_report = TRUE; + tBTM_INQ_RESULTS *p_cur = &p_i->inq_info.results; + UINT8 len; + UINT8 *p_flag; + tBTM_INQUIRY_VAR_ST *p_inq = &btm_cb.btm_inq_vars; + UINT8 data_len, rssi; + tBTM_BLE_INQ_CB *p_le_inq_cb = &btm_cb.ble_ctr_cb.inq_var; + UINT8 *p1; + UINT8 *p_uuid16; + + STREAM_TO_UINT8 (data_len, p); + + if (data_len > BTM_BLE_ADV_DATA_LEN_MAX) + { + BTM_TRACE_WARNING("EIR data too long %d. discard", data_len); + return FALSE; + } + btm_ble_cache_adv_data(p_cur, data_len, p, evt_type); + + p1 = (p + data_len); + STREAM_TO_UINT8 (rssi, p1); + + /* Save the info */ + p_cur->inq_result_type = BTM_INQ_RESULT_BLE; + p_cur->ble_addr_type = addr_type; + p_cur->rssi = rssi; + + /* active scan, always wait until get scan_rsp to report the result */ + if ((btm_cb.ble_ctr_cb.inq_var.scan_type == BTM_BLE_SCAN_MODE_ACTI && + (evt_type == BTM_BLE_CONNECT_EVT || evt_type == BTM_BLE_DISCOVER_EVT))) + { + BTM_TRACE_DEBUG("btm_ble_update_inq_result scan_rsp=false, to_report=false,\ + scan_type_active=%d", btm_cb.ble_ctr_cb.inq_var.scan_type); + p_i->scan_rsp = FALSE; + to_report = FALSE; + } + else + p_i->scan_rsp = TRUE; + + if (p_i->inq_count != p_inq->inq_counter) + p_cur->device_type = BT_DEVICE_TYPE_BLE; + else + p_cur->device_type |= BT_DEVICE_TYPE_BLE; + + if (evt_type != BTM_BLE_SCAN_RSP_EVT) + p_cur->ble_evt_type = evt_type; + + p_i->inq_count = p_inq->inq_counter; /* Mark entry for current inquiry */ + + if (p_le_inq_cb->adv_len != 0) + { + if ((p_flag = BTM_CheckAdvData(p_le_inq_cb->adv_data_cache, BTM_BLE_AD_TYPE_FLAG, &len)) != NULL) + p_cur->flag = * p_flag; + } + + if (p_le_inq_cb->adv_len != 0) + { + /* Check to see the BLE device has the Appearance UUID in the advertising data. If it does + * then try to convert the appearance value to a class of device value Bluedroid can use. + * Otherwise fall back to trying to infer if it is a HID device based on the service class. + */ + p_uuid16 = BTM_CheckAdvData(p_le_inq_cb->adv_data_cache, BTM_BLE_AD_TYPE_APPEARANCE, &len); + if (p_uuid16 && len == 2) + { + btm_ble_appearance_to_cod((UINT16)p_uuid16[0] | (p_uuid16[1] << 8), p_cur->dev_class); + } + else + { + if ((p_uuid16 = BTM_CheckAdvData(p_le_inq_cb->adv_data_cache, + BTM_BLE_AD_TYPE_16SRV_CMPL, &len)) != NULL) + { + UINT8 i; + for (i = 0; i + 2 <= len; i = i + 2) + { + /* if this BLE device support HID over LE, set HID Major in class of device */ + if ((p_uuid16[i] | (p_uuid16[i+1] << 8)) == UUID_SERVCLASS_LE_HID) + { + p_cur->dev_class[0] = 0; + p_cur->dev_class[1] = BTM_COD_MAJOR_PERIPHERAL; + p_cur->dev_class[2] = 0; + break; + } + } + } + } + } + + /* if BR/EDR not supported is not set, assume is a DUMO device */ + if ((p_cur->flag & BTM_BLE_BREDR_NOT_SPT) == 0 && + evt_type != BTM_BLE_CONNECT_DIR_EVT) + { + if (p_cur->ble_addr_type != BLE_ADDR_RANDOM) + { + BTM_TRACE_DEBUG("BR/EDR NOT support bit not set, treat as DUMO"); + p_cur->device_type |= BT_DEVICE_TYPE_DUMO; + } else { + BTM_TRACE_DEBUG("Random address, treating device as LE only"); + } + } + else + { + BTM_TRACE_DEBUG("BR/EDR NOT SUPPORT bit set, LE only device"); + } + + return to_report; + +} + +/******************************************************************************* +** +** Function btm_clear_all_pending_le_entry +** +** Description This function is called to clear all LE pending entry in +** inquiry database. +** +** Returns void +** +*******************************************************************************/ +void btm_clear_all_pending_le_entry(void) +{ + UINT16 xx; + tINQ_DB_ENT *p_ent = btm_cb.btm_inq_vars.inq_db; + + for (xx = 0; xx < BTM_INQ_DB_SIZE; xx++, p_ent++) + { + /* mark all pending LE entry as unused if an LE only device has scan response outstanding */ + if ((p_ent->in_use) && + (p_ent->inq_info.results.device_type == BT_DEVICE_TYPE_BLE) && + !p_ent->scan_rsp) + p_ent->in_use = FALSE; + } +} + +/******************************************************************************* +** +** Function btm_send_sel_conn_callback +** +** Description send selection connection request callback. +** +** Parameters +** +** Returns void +** +*******************************************************************************/ +void btm_send_sel_conn_callback(BD_ADDR remote_bda, UINT8 evt_type, UINT8 *p_data, UINT8 addr_type) +{ + UINT8 data_len, len; + UINT8 *p_dev_name, remname[31] = {0}; + UNUSED(addr_type); + + if (btm_cb.ble_ctr_cb.p_select_cback == NULL || + /* non-connectable device */ + (evt_type != BTM_BLE_EVT_CONN_ADV && evt_type != BTM_BLE_EVT_CONN_DIR_ADV)) + return; + + STREAM_TO_UINT8 (data_len, p_data); + + /* get the device name if exist in ADV data */ + if (data_len != 0) + { + p_dev_name = BTM_CheckAdvData(p_data, BTM_BLE_AD_TYPE_NAME_CMPL, &len); + + if (p_dev_name == NULL) + p_dev_name = BTM_CheckAdvData(p_data, BTM_BLE_AD_TYPE_NAME_SHORT, &len); + + if (p_dev_name) + memcpy(remname, p_dev_name, len); + } + /* allow connection */ + if ((* btm_cb.ble_ctr_cb.p_select_cback)(remote_bda, remname)) + { + /* terminate selective connection, initiate connection */ + btm_ble_initiate_select_conn(remote_bda); + } +} + +/******************************************************************************* +** +** Function btm_ble_process_adv_pkt +** +** Description This function is called when adv packet report events are +** received from the device. It updates the inquiry database. +** If the inquiry database is full, the oldest entry is discarded. +** +** Parameters +** +** Returns void +** +*******************************************************************************/ +void btm_ble_process_adv_pkt (UINT8 *p_data) +{ + BD_ADDR bda; + UINT8 evt_type = 0, *p = p_data; + UINT8 addr_type = 0; + UINT8 num_reports; + UINT8 data_len; +#if (defined BLE_PRIVACY_SPT && BLE_PRIVACY_SPT == TRUE) + BOOLEAN match = FALSE; +#endif + + /* Only process the results if the inquiry is still active */ + if (!BTM_BLE_IS_SCAN_ACTIVE(btm_cb.ble_ctr_cb.scan_activity)) + return; + + /* Extract the number of reports in this event. */ + STREAM_TO_UINT8(num_reports, p); + + while (num_reports--) + { + /* Extract inquiry results */ + STREAM_TO_UINT8 (evt_type, p); + STREAM_TO_UINT8 (addr_type, p); + STREAM_TO_BDADDR (bda, p); + +#if (defined BLE_PRIVACY_SPT && BLE_PRIVACY_SPT == TRUE) + /* map address to security record */ + match = btm_identity_addr_to_random_pseudo(bda, &addr_type, FALSE); + + BTM_TRACE_DEBUG("btm_ble_process_adv_pkt:bda= %0x:%0x:%0x:%0x:%0x:%0x", + bda[0],bda[1],bda[2],bda[3],bda[4],bda[5]); + /* always do RRA resolution on host */ + if (!match && BTM_BLE_IS_RESOLVE_BDA(bda)) + { + btm_ble_resolve_random_addr(bda, btm_ble_resolve_random_addr_on_adv, p_data); + } + else +#endif + btm_ble_process_adv_pkt_cont(bda, addr_type, evt_type, p); + + STREAM_TO_UINT8(data_len, p); + + /* Advance to the next event data_len + rssi byte */ + p += data_len + 1; + } +} + +/******************************************************************************* +** +** Function btm_ble_process_adv_pkt_cont +** +** Description This function is called after random address resolution is +** done, and proceed to process adv packet. +** +** Parameters +** +** Returns void +** +*******************************************************************************/ +static void btm_ble_process_adv_pkt_cont(BD_ADDR bda, UINT8 addr_type, UINT8 evt_type, UINT8 *p) +{ + tINQ_DB_ENT *p_i; + tBTM_INQUIRY_VAR_ST *p_inq = &btm_cb.btm_inq_vars; + tBTM_INQ_RESULTS_CB *p_inq_results_cb = p_inq->p_inq_results_cb; + tBTM_INQ_RESULTS_CB *p_obs_results_cb = btm_cb.ble_ctr_cb.p_obs_results_cb; + tBTM_BLE_INQ_CB *p_le_inq_cb = &btm_cb.ble_ctr_cb.inq_var; + BOOLEAN update = TRUE; + UINT8 result = 0; + + p_i = btm_inq_db_find (bda); + + /* Check if this address has already been processed for this inquiry */ + if (btm_inq_find_bdaddr(bda)) + { + /* never been report as an LE device */ + if (p_i && + (!(p_i->inq_info.results.device_type & BT_DEVICE_TYPE_BLE) || + /* scan repsonse to be updated */ + (!p_i->scan_rsp))) + { + update = TRUE; + } + else if (BTM_BLE_IS_OBS_ACTIVE(btm_cb.ble_ctr_cb.scan_activity)) + { + update = FALSE; + } + else + { + /* if yes, skip it */ + return; /* assumption: one result per event */ + } + } + /* If existing entry, use that, else get a new one (possibly reusing the oldest) */ + if (p_i == NULL) + { + if ((p_i = btm_inq_db_new (bda)) != NULL) + { + p_inq->inq_cmpl_info.num_resp++; + } + else + return; + } + else if (p_i->inq_count != p_inq->inq_counter) /* first time seen in this inquiry */ + { + p_inq->inq_cmpl_info.num_resp++; + } + /* update the LE device information in inquiry database */ + if (!btm_ble_update_inq_result(p_i, addr_type, evt_type, p)) + return; + + if ((result = btm_ble_is_discoverable(bda, evt_type, p)) == 0) + { + LOG_WARN("%s device is no longer discoverable so discarding advertising packet pkt", + __func__); + return; + } + if (!update) + result &= ~BTM_BLE_INQ_RESULT; + /* If the number of responses found and limited, issue a cancel inquiry */ + if (p_inq->inqparms.max_resps && + p_inq->inq_cmpl_info.num_resp == p_inq->inqparms.max_resps) + { + /* new device */ + if (p_i == NULL || + /* assume a DUMO device, BR/EDR inquiry is always active */ + (p_i && + (p_i->inq_info.results.device_type & BT_DEVICE_TYPE_BLE) == BT_DEVICE_TYPE_BLE && + p_i->scan_rsp)) + { + BTM_TRACE_WARNING("INQ RES: Extra Response Received...cancelling inquiry.."); + + /* if is non-periodic inquiry active, cancel now */ + if ((p_inq->inq_active & BTM_BR_INQ_ACTIVE_MASK) != 0 && + (p_inq->inq_active & BTM_PERIODIC_INQUIRY_ACTIVE) == 0) + btsnd_hcic_inq_cancel(); + + btm_ble_stop_inquiry(); + + btm_acl_update_busy_level (BTM_BLI_INQ_DONE_EVT); + } + } + /* background connection in selective connection mode */ + if (btm_cb.ble_ctr_cb.bg_conn_type == BTM_BLE_CONN_SELECTIVE) + { + if (result & BTM_BLE_SEL_CONN_RESULT) + btm_send_sel_conn_callback(bda, evt_type, p, addr_type); + else + { + BTM_TRACE_DEBUG("None LE device, can not initiate selective connection"); + } + } + else + { + if (p_inq_results_cb && (result & BTM_BLE_INQ_RESULT)) + { + (p_inq_results_cb)((tBTM_INQ_RESULTS *) &p_i->inq_info.results, p_le_inq_cb->adv_data_cache); + } + if (p_obs_results_cb && (result & BTM_BLE_OBS_RESULT)) + { + (p_obs_results_cb)((tBTM_INQ_RESULTS *) &p_i->inq_info.results, p_le_inq_cb->adv_data_cache); + } + } +} + +/******************************************************************************* +** +** Function btm_ble_start_scan +** +** Description Start the BLE scan. +** +** Returns void +** +*******************************************************************************/ +tBTM_STATUS btm_ble_start_scan(void) +{ + tBTM_BLE_INQ_CB *p_inq = &btm_cb.ble_ctr_cb.inq_var; + tBTM_STATUS status = BTM_CMD_STARTED; + + /* start scan, disable duplicate filtering */ + if (!btsnd_hcic_ble_set_scan_enable (BTM_BLE_SCAN_ENABLE, p_inq->scan_duplicate_filter)) + { + status = BTM_NO_RESOURCES; + } + else + { + if (p_inq->scan_type == BTM_BLE_SCAN_MODE_ACTI) + btm_ble_set_topology_mask(BTM_BLE_STATE_ACTIVE_SCAN_BIT); + else + btm_ble_set_topology_mask(BTM_BLE_STATE_PASSIVE_SCAN_BIT); + } + return status; +} + +/******************************************************************************* +** +** Function btm_ble_stop_scan +** +** Description Stop the BLE scan. +** +** Returns void +** +*******************************************************************************/ +void btm_ble_stop_scan(void) +{ + BTM_TRACE_EVENT ("btm_ble_stop_scan "); + + /* Clear the inquiry callback if set */ + btm_cb.ble_ctr_cb.inq_var.scan_type = BTM_BLE_SCAN_MODE_NONE; + + /* stop discovery now */ + btsnd_hcic_ble_set_scan_enable (BTM_BLE_SCAN_DISABLE, BTM_BLE_DUPLICATE_ENABLE); + + btm_update_scanner_filter_policy(SP_ADV_ALL); + + btm_cb.ble_ctr_cb.wl_state &= ~BTM_BLE_WL_SCAN; +} +/******************************************************************************* +** +** Function btm_ble_stop_inquiry +** +** Description Stop the BLE Inquiry. +** +** Returns void +** +*******************************************************************************/ +void btm_ble_stop_inquiry(void) +{ + tBTM_INQUIRY_VAR_ST *p_inq = &btm_cb.btm_inq_vars; + tBTM_BLE_CB *p_ble_cb = &btm_cb.ble_ctr_cb; + + btu_stop_timer (&p_ble_cb->inq_var.inq_timer_ent); + + p_ble_cb->scan_activity &= ~BTM_BLE_INQUIRY_MASK; + + /* If no more scan activity, stop LE scan now */ + if (!BTM_BLE_IS_SCAN_ACTIVE(p_ble_cb->scan_activity)) + btm_ble_stop_scan(); + else if((p_ble_cb->inq_var.scan_interval != BTM_BLE_LOW_LATENCY_SCAN_INT) || + (p_ble_cb->inq_var.scan_window != BTM_BLE_LOW_LATENCY_SCAN_WIN)) + { + BTM_TRACE_DEBUG("%s: setting default params for ongoing observe", __FUNCTION__); + btm_ble_stop_scan(); + btm_ble_start_scan(); + } + + /* If we have a callback registered for inquiry complete, call it */ + BTM_TRACE_DEBUG ("BTM Inq Compl Callback: status 0x%02x, num results %d", + p_inq->inq_cmpl_info.status, p_inq->inq_cmpl_info.num_resp); + + btm_process_inq_complete(HCI_SUCCESS, (UINT8)(p_inq->inqparms.mode & BTM_BLE_INQUIRY_MASK)); +} + +/******************************************************************************* +** +** Function btm_ble_stop_observe +** +** Description Stop the BLE Observe. +** +** Returns void +** +*******************************************************************************/ +static void btm_ble_stop_observe(void) +{ + tBTM_BLE_CB *p_ble_cb = & btm_cb.ble_ctr_cb; + tBTM_CMPL_CB *p_obs_cb = p_ble_cb->p_obs_cmpl_cb; + + btu_stop_timer (&p_ble_cb->obs_timer_ent); + + p_ble_cb->scan_activity &= ~BTM_LE_OBSERVE_ACTIVE; + + p_ble_cb->p_obs_results_cb = NULL; + p_ble_cb->p_obs_cmpl_cb = NULL; + + if (!BTM_BLE_IS_SCAN_ACTIVE(p_ble_cb->scan_activity)) + btm_ble_stop_scan(); + + if (p_obs_cb) + (p_obs_cb)((tBTM_INQUIRY_CMPL *) &btm_cb.btm_inq_vars.inq_cmpl_info); +} +/******************************************************************************* +** +** Function btm_ble_adv_states_operation +** +** Description Set or clear adv states in topology mask +** +** Returns operation status. TRUE if sucessful, FALSE otherwise. +** +*******************************************************************************/ +typedef BOOLEAN (BTM_TOPOLOGY_FUNC_PTR)(tBTM_BLE_STATE_MASK); +static BOOLEAN btm_ble_adv_states_operation(BTM_TOPOLOGY_FUNC_PTR *p_handler, UINT8 adv_evt) +{ + BOOLEAN rt = FALSE; + + switch (adv_evt) + { + case BTM_BLE_CONNECT_EVT: + rt = (*p_handler)(BTM_BLE_STATE_CONN_ADV_BIT); + break; + + case BTM_BLE_NON_CONNECT_EVT: + rt = (*p_handler) (BTM_BLE_STATE_NON_CONN_ADV_BIT); + break; + case BTM_BLE_CONNECT_DIR_EVT: + rt = (*p_handler) (BTM_BLE_STATE_HI_DUTY_DIR_ADV_BIT); + break; + + case BTM_BLE_DISCOVER_EVT: + rt = (*p_handler) (BTM_BLE_STATE_SCAN_ADV_BIT); + break; + + case BTM_BLE_CONNECT_LO_DUTY_DIR_EVT: + rt = (*p_handler) (BTM_BLE_STATE_LO_DUTY_DIR_ADV_BIT); + break; + + default: + BTM_TRACE_ERROR("unknown adv event : %d", adv_evt); + break; + } + + return rt; +} + + +/******************************************************************************* +** +** Function btm_ble_start_adv +** +** Description start the BLE advertising. +** +** Returns void +** +*******************************************************************************/ +tBTM_STATUS btm_ble_start_adv(void) +{ + tBTM_BLE_INQ_CB *p_cb = &btm_cb.ble_ctr_cb.inq_var; + tBTM_STATUS rt = BTM_NO_RESOURCES; + + if (!btm_ble_adv_states_operation (btm_ble_topology_check, p_cb->evt_type)) + return BTM_WRONG_MODE; + +#if (defined BLE_PRIVACY_SPT && BLE_PRIVACY_SPT == TRUE) + /* To relax resolving list, always have resolving list enabled, unless directed adv */ + if (p_cb->evt_type != BTM_BLE_CONNECT_LO_DUTY_DIR_EVT && + p_cb->evt_type != BTM_BLE_CONNECT_DIR_EVT) + /* enable resolving list is desired */ + btm_ble_enable_resolving_list_for_platform(BTM_BLE_RL_ADV); +#endif + if (p_cb->afp != AP_SCAN_CONN_ALL) + { + btm_execute_wl_dev_operation(); + btm_cb.ble_ctr_cb.wl_state |= BTM_BLE_WL_ADV; + } + + if (btsnd_hcic_ble_set_adv_enable (BTM_BLE_ADV_ENABLE)) + { + p_cb->adv_mode = BTM_BLE_ADV_ENABLE; + btm_ble_adv_states_operation(btm_ble_set_topology_mask, p_cb->evt_type); + rt = BTM_SUCCESS; + } + else + { + p_cb->adv_mode = BTM_BLE_ADV_DISABLE; + btm_cb.ble_ctr_cb.wl_state &= ~BTM_BLE_WL_ADV; + } + return rt; +} + +/******************************************************************************* +** +** Function btm_ble_stop_adv +** +** Description Stop the BLE advertising. +** +** Returns void +** +*******************************************************************************/ +tBTM_STATUS btm_ble_stop_adv(void) +{ + tBTM_BLE_INQ_CB *p_cb = &btm_cb.ble_ctr_cb.inq_var; + tBTM_STATUS rt = BTM_SUCCESS; + + if (p_cb->adv_mode == BTM_BLE_ADV_ENABLE) + { + if (btsnd_hcic_ble_set_adv_enable (BTM_BLE_ADV_DISABLE)) + { + p_cb->fast_adv_on = FALSE; + p_cb->adv_mode = BTM_BLE_ADV_DISABLE; + btm_cb.ble_ctr_cb.wl_state &= ~BTM_BLE_WL_ADV; + + /* clear all adv states */ + btm_ble_clear_topology_mask (BTM_BLE_STATE_ALL_ADV_MASK); + } + else + rt = BTM_NO_RESOURCES; + } + return rt; +} + + +/******************************************************************************* +** +** Function btm_ble_start_slow_adv +** +** Description Restart adv with slow adv interval +** +** Returns void +** +*******************************************************************************/ +static void btm_ble_start_slow_adv (void) +{ + tBTM_BLE_INQ_CB *p_cb = &btm_cb.ble_ctr_cb.inq_var; + + if (p_cb->adv_mode == BTM_BLE_ADV_ENABLE) + { + tBTM_LE_RANDOM_CB *p_addr_cb = &btm_cb.ble_ctr_cb.addr_mgnt_cb; + BD_ADDR p_addr_ptr = {0}; + tBLE_ADDR_TYPE init_addr_type = BLE_ADDR_PUBLIC; + tBLE_ADDR_TYPE own_addr_type = p_addr_cb->own_addr_type; + + btm_ble_stop_adv(); + + p_cb->evt_type = btm_set_conn_mode_adv_init_addr(p_cb, p_addr_ptr, &init_addr_type, + &own_addr_type); + + /* slow adv mode never goes into directed adv */ + btsnd_hcic_ble_write_adv_params (BTM_BLE_GAP_ADV_SLOW_INT, BTM_BLE_GAP_ADV_SLOW_INT, + p_cb->evt_type, own_addr_type, + init_addr_type, p_addr_ptr, + p_cb->adv_chnl_map, p_cb->afp); + + btm_ble_start_adv(); + } +} +/******************************************************************************* +** +** Function btm_ble_timeout +** +** Description Called when BTM BLE inquiry timer expires +** +** Returns void +** +*******************************************************************************/ +void btm_ble_timeout(TIMER_LIST_ENT *p_tle) +{ + BTM_TRACE_EVENT ("btm_ble_timeout"); + + switch (p_tle->event) + { + case BTU_TTYPE_BLE_OBSERVE: + btm_ble_stop_observe(); + break; + + case BTU_TTYPE_BLE_INQUIRY: + btm_ble_stop_inquiry(); + break; + + case BTU_TTYPE_BLE_GAP_LIM_DISC: + /* lim_timeout expiried, limited discovery should exit now */ + btm_cb.btm_inq_vars.discoverable_mode &= ~BTM_BLE_LIMITED_DISCOVERABLE; + btm_ble_set_adv_flag(btm_cb.btm_inq_vars.connectable_mode, btm_cb.btm_inq_vars.discoverable_mode); + break; + + case BTU_TTYPE_BLE_RANDOM_ADDR: + if (btm_cb.ble_ctr_cb.addr_mgnt_cb.own_addr_type == BLE_ADDR_RANDOM) + { + if (NULL == (void *)(p_tle->param)) + { + /* refresh the random addr */ + btm_gen_resolvable_private_addr((void *)btm_gen_resolve_paddr_low); + } + else + { + if (BTM_BleMaxMultiAdvInstanceCount() > 0) + btm_ble_multi_adv_configure_rpa((tBTM_BLE_MULTI_ADV_INST*)p_tle->param); + } + } + break; + + case BTU_TTYPE_BLE_GAP_FAST_ADV: + /* fast adv is completed, fall back to slow adv interval */ + btm_ble_start_slow_adv(); + break; + + default: + break; + + } +} + + +/******************************************************************************* +** +** Function btm_ble_read_remote_features_complete +** +** Description This function is called when the command complete message +** is received from the HCI for the read LE remote feature supported +** complete event. +** +** Returns void +** +*******************************************************************************/ +void btm_ble_read_remote_features_complete(UINT8 *p) +{ + tACL_CONN *p_acl_cb = &btm_cb.acl_db[0]; + UINT16 handle; + UINT8 status; + int xx; + + BTM_TRACE_EVENT ("btm_ble_read_remote_features_complete "); + + STREAM_TO_UINT8(status, p); + + // if LE read remote feature failed for HCI_ERR_CONN_FAILED_ESTABLISHMENT, + // expect disconnect complete to be received + if (status != HCI_ERR_CONN_FAILED_ESTABLISHMENT) + { + STREAM_TO_UINT16 (handle, p); + + /* Look up the connection by handle and copy features */ + for (xx = 0; xx < MAX_L2CAP_LINKS; xx++, p_acl_cb++) + { + if ((p_acl_cb->in_use) && (p_acl_cb->hci_handle == handle)) + { + STREAM_TO_ARRAY(p_acl_cb->peer_le_features, p, BD_FEATURES_LEN); + btsnd_hcic_rmt_ver_req (p_acl_cb->hci_handle); + break; + } + } + } + +} + +/******************************************************************************* +** +** Function btm_ble_write_adv_enable_complete +** +** Description This function process the write adv enable command complete. +** +** Returns void +** +*******************************************************************************/ +void btm_ble_write_adv_enable_complete(UINT8 * p) +{ + tBTM_BLE_INQ_CB *p_cb = &btm_cb.ble_ctr_cb.inq_var; + + /* if write adv enable/disbale not succeed */ + if (*p != HCI_SUCCESS) + { + /* toggle back the adv mode */ + p_cb->adv_mode = !p_cb->adv_mode; + } +} + +/******************************************************************************* +** +** Function btm_ble_dir_adv_tout +** +** Description when directed adv time out +** +** Returns void +** +*******************************************************************************/ +void btm_ble_dir_adv_tout(void) +{ + btm_cb.ble_ctr_cb.inq_var.adv_mode = BTM_BLE_ADV_DISABLE; + + /* make device fall back into undirected adv mode by default */ + btm_cb.ble_ctr_cb.inq_var.directed_conn = FALSE; +} + +/******************************************************************************* +** +** Function btm_ble_set_topology_mask +** +** Description set BLE topology mask +** +** Returns TRUE is request is allowed, FALSE otherwise. +** +*******************************************************************************/ +BOOLEAN btm_ble_set_topology_mask(tBTM_BLE_STATE_MASK request_state_mask) +{ + request_state_mask &= BTM_BLE_STATE_ALL_MASK; + btm_cb.ble_ctr_cb.cur_states |= (request_state_mask & BTM_BLE_STATE_ALL_MASK); + return TRUE; +} + +/******************************************************************************* +** +** Function btm_ble_clear_topology_mask +** +** Description Clear BLE topology bit mask +** +** Returns TRUE is request is allowed, FALSE otherwise. +** +*******************************************************************************/ +BOOLEAN btm_ble_clear_topology_mask (tBTM_BLE_STATE_MASK request_state_mask) +{ + request_state_mask &= BTM_BLE_STATE_ALL_MASK; + btm_cb.ble_ctr_cb.cur_states &= ~request_state_mask; + return TRUE; +} + +/******************************************************************************* +** +** Function btm_ble_update_link_topology_mask +** +** Description This function update the link topology mask +** +** Returns void +** +*******************************************************************************/ +void btm_ble_update_link_topology_mask(UINT8 link_role, BOOLEAN increase) +{ + btm_ble_clear_topology_mask (BTM_BLE_STATE_ALL_CONN_MASK); + + if (increase) + btm_cb.ble_ctr_cb.link_count[link_role]++; + else if (btm_cb.ble_ctr_cb.link_count[link_role] > 0) + btm_cb.ble_ctr_cb.link_count[link_role]--; + + if (btm_cb.ble_ctr_cb.link_count[HCI_ROLE_MASTER]) + btm_ble_set_topology_mask (BTM_BLE_STATE_MASTER_BIT); + + if (btm_cb.ble_ctr_cb.link_count[HCI_ROLE_SLAVE]) + btm_ble_set_topology_mask(BTM_BLE_STATE_SLAVE_BIT); + + if (link_role == HCI_ROLE_SLAVE && increase) + { + btm_cb.ble_ctr_cb.inq_var.adv_mode = BTM_BLE_ADV_DISABLE; + /* make device fall back into undirected adv mode by default */ + btm_cb.ble_ctr_cb.inq_var.directed_conn = BTM_BLE_CONNECT_EVT; + /* clear all adv states */ + btm_ble_clear_topology_mask(BTM_BLE_STATE_ALL_ADV_MASK); + } +} + +/******************************************************************************* +** +** Function btm_ble_update_mode_operation +** +** Description This function update the GAP role operation when a link status +** is updated. +** +** Returns void +** +*******************************************************************************/ +void btm_ble_update_mode_operation(UINT8 link_role, BD_ADDR bd_addr, UINT8 status) +{ + if (status == HCI_ERR_DIRECTED_ADVERTISING_TIMEOUT) + { + btm_cb.ble_ctr_cb.inq_var.adv_mode = BTM_BLE_ADV_DISABLE; + /* make device fall back into undirected adv mode by default */ + btm_cb.ble_ctr_cb.inq_var.directed_conn = BTM_BLE_CONNECT_EVT; + /* clear all adv states */ + btm_ble_clear_topology_mask (BTM_BLE_STATE_ALL_ADV_MASK); + } + + if (btm_cb.ble_ctr_cb.inq_var.connectable_mode == BTM_BLE_CONNECTABLE) + { + btm_ble_set_connectability(btm_cb.btm_inq_vars.connectable_mode | + btm_cb.ble_ctr_cb.inq_var.connectable_mode); + } + + /* when no connection is attempted, and controller is not rejecting last request + due to resource limitation, start next direct connection or background connection + now in order */ + if (btm_ble_get_conn_st() == BLE_CONN_IDLE && status != HCI_ERR_HOST_REJECT_RESOURCES && + !btm_send_pending_direct_conn()) + { + btm_ble_resume_bg_conn(); + } +} + +/******************************************************************************* +** +** Function btm_ble_init +** +** Description Initialize the control block variable values. +** +** Returns void +** +*******************************************************************************/ +void btm_ble_init (void) +{ + tBTM_BLE_CB *p_cb = &btm_cb.ble_ctr_cb; + + BTM_TRACE_DEBUG("%s", __func__); + + memset(p_cb, 0, sizeof(tBTM_BLE_CB)); + memset(&(btm_cb.cmn_ble_vsc_cb), 0 , sizeof(tBTM_BLE_VSC_CB)); + btm_cb.cmn_ble_vsc_cb.values_read = FALSE; + p_cb->cur_states = 0; + + p_cb->inq_var.adv_mode = BTM_BLE_ADV_DISABLE; + p_cb->inq_var.scan_type = BTM_BLE_SCAN_MODE_NONE; + p_cb->inq_var.adv_chnl_map = BTM_BLE_DEFAULT_ADV_CHNL_MAP; + p_cb->inq_var.afp = BTM_BLE_DEFAULT_AFP; + p_cb->inq_var.sfp = BTM_BLE_DEFAULT_SFP; + p_cb->inq_var.connectable_mode = BTM_BLE_NON_CONNECTABLE; + p_cb->inq_var.discoverable_mode = BTM_BLE_NON_DISCOVERABLE; + + /* for background connection, reset connection params to be undefined */ + p_cb->scan_int = p_cb->scan_win = BTM_BLE_SCAN_PARAM_UNDEF; + + p_cb->inq_var.evt_type = BTM_BLE_NON_CONNECT_EVT; + +#if BLE_VND_INCLUDED == FALSE + btm_ble_adv_filter_init(); +#endif +} + +/******************************************************************************* +** +** Function btm_ble_topology_check +** +** Description check to see requested state is supported. One state check at +** a time is supported +** +** Returns TRUE is request is allowed, FALSE otherwise. +** +*******************************************************************************/ +BOOLEAN btm_ble_topology_check(tBTM_BLE_STATE_MASK request_state_mask) +{ + BOOLEAN rt = FALSE; + + UINT8 state_offset = 0; + UINT16 cur_states = btm_cb.ble_ctr_cb.cur_states; + UINT8 mask, offset; + UINT8 request_state = 0; + + /* check only one bit is set and within valid range */ + if (request_state_mask == BTM_BLE_STATE_INVALID || + request_state_mask > BTM_BLE_STATE_SCAN_ADV_BIT || + (request_state_mask & (request_state_mask -1 )) != 0) + { + BTM_TRACE_ERROR("illegal state requested: %d", request_state_mask); + return rt; + } + + while (request_state_mask) + { + request_state_mask >>= 1; + request_state ++; + } + + /* check if the requested state is supported or not */ + mask = btm_le_state_combo_tbl[0][request_state - 1][0]; + offset = btm_le_state_combo_tbl[0][request_state-1][1]; + + const uint8_t *ble_supported_states = controller_get_interface()->get_ble_supported_states(); + + if (!BTM_LE_STATES_SUPPORTED(ble_supported_states, mask, offset)) + { + BTM_TRACE_ERROR("state requested not supported: %d", request_state); + return rt; + } + + rt = TRUE; + /* make sure currently active states are all supported in conjunction with the requested + state. If the bit in table is not set, the combination is not supported */ + while (cur_states != 0) + { + if (cur_states & 0x01) + { + mask = btm_le_state_combo_tbl[request_state][state_offset][0]; + offset = btm_le_state_combo_tbl[request_state][state_offset][1]; + + if (mask != 0 && offset != 0) + { + if (!BTM_LE_STATES_SUPPORTED(ble_supported_states, mask, offset)) + { + rt = FALSE; + break; + } + } + } + cur_states >>= 1; + state_offset ++; + } + return rt; +} + + +#endif /* BLE_INCLUDED */ diff --git a/components/bt/bluedroid/stack/btm/btm_ble_multi_adv.c b/components/bt/bluedroid/stack/btm/btm_ble_multi_adv.c new file mode 100755 index 0000000000..dd7876bf53 --- /dev/null +++ b/components/bt/bluedroid/stack/btm/btm_ble_multi_adv.c @@ -0,0 +1,894 @@ +/****************************************************************************** + * + * Copyright (C) 2014 Broadcom Corporation + * + * 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. + * + ******************************************************************************/ + +#include + +#include "bt_target.h" +#include "controller.h" + +#if (BLE_INCLUDED == TRUE) +#include "bt_types.h" +#include "hcimsgs.h" +#include "btu.h" +#include "btm_int.h" +//#include "bt_utils.h" +#include "hcidefs.h" +#include "btm_ble_api.h" + +/************************************************************************************ +** Constants & Macros +************************************************************************************/ +/* length of each multi adv sub command */ +#define BTM_BLE_MULTI_ADV_ENB_LEN 3 +#define BTM_BLE_MULTI_ADV_SET_PARAM_LEN 24 +#define BTM_BLE_MULTI_ADV_WRITE_DATA_LEN (BTM_BLE_AD_DATA_LEN + 3) +#define BTM_BLE_MULTI_ADV_SET_RANDOM_ADDR_LEN 8 + +#define BTM_BLE_MULTI_ADV_CB_EVT_MASK 0xF0 +#define BTM_BLE_MULTI_ADV_SUBCODE_MASK 0x0F + +/************************************************************************************ +** Static variables +************************************************************************************/ +tBTM_BLE_MULTI_ADV_CB btm_multi_adv_cb; +tBTM_BLE_MULTI_ADV_INST_IDX_Q btm_multi_adv_idx_q; + +/************************************************************************************ +** Externs +************************************************************************************/ +extern void btm_ble_update_dmt_flag_bits(UINT8 *flag_value, + const UINT16 connect_mode, const UINT16 disc_mode); + +/******************************************************************************* +** +** Function btm_ble_multi_adv_enq_op_q +** +** Description enqueue a multi adv operation in q to check command complete +** status. +** +** Returns void +** +*******************************************************************************/ +void btm_ble_multi_adv_enq_op_q(UINT8 opcode, UINT8 inst_id, UINT8 cb_evt) +{ + tBTM_BLE_MULTI_ADV_OPQ *p_op_q = &btm_multi_adv_cb.op_q; + + p_op_q->p_inst_id[p_op_q->next_idx] = inst_id; + + p_op_q->p_sub_code[p_op_q->next_idx] = (opcode |(cb_evt << 4)); + + p_op_q->next_idx = (p_op_q->next_idx + 1) % BTM_BleMaxMultiAdvInstanceCount(); +} + +/******************************************************************************* +** +** Function btm_ble_multi_adv_deq_op_q +** +** Description dequeue a multi adv operation from q when command complete +** is received. +** +** Returns void +** +*******************************************************************************/ +void btm_ble_multi_adv_deq_op_q(UINT8 *p_opcode, UINT8 *p_inst_id, UINT8 *p_cb_evt) +{ + tBTM_BLE_MULTI_ADV_OPQ *p_op_q = &btm_multi_adv_cb.op_q; + + *p_inst_id = p_op_q->p_inst_id[p_op_q->pending_idx] & 0x7F; + *p_cb_evt = (p_op_q->p_sub_code[p_op_q->pending_idx] >> 4); + *p_opcode = (p_op_q->p_sub_code[p_op_q->pending_idx] & BTM_BLE_MULTI_ADV_SUBCODE_MASK); + + p_op_q->pending_idx = (p_op_q->pending_idx + 1) % BTM_BleMaxMultiAdvInstanceCount(); +} + +/******************************************************************************* +** +** Function btm_ble_multi_adv_vsc_cmpl_cback +** +** Description Multi adv VSC complete callback +** +** Parameters +** +** Returns void +** +*******************************************************************************/ +void btm_ble_multi_adv_vsc_cmpl_cback (tBTM_VSC_CMPL *p_params) +{ + UINT8 status, subcode; + UINT8 *p = p_params->p_param_buf, inst_id; + UINT16 len = p_params->param_len; + tBTM_BLE_MULTI_ADV_INST *p_inst ; + UINT8 cb_evt = 0, opcode; + + if (len < 2) + { + BTM_TRACE_ERROR("wrong length for btm_ble_multi_adv_vsc_cmpl_cback"); + return; + } + + STREAM_TO_UINT8(status, p); + STREAM_TO_UINT8(subcode, p); + + btm_ble_multi_adv_deq_op_q(&opcode, &inst_id, &cb_evt); + + BTM_TRACE_DEBUG("op_code = %02x inst_id = %d cb_evt = %02x", opcode, inst_id, cb_evt); + + if (opcode != subcode || inst_id == 0) + { + BTM_TRACE_ERROR("get unexpected VSC cmpl, expect: %d get: %d",subcode,opcode); + return; + } + + p_inst = &btm_multi_adv_cb.p_adv_inst[inst_id - 1]; + + switch (subcode) + { + case BTM_BLE_MULTI_ADV_ENB: + { + BTM_TRACE_DEBUG("BTM_BLE_MULTI_ADV_ENB status = %d", status); + + /* Mark as not in use here, if instance cannot be enabled */ + if (HCI_SUCCESS != status && BTM_BLE_MULTI_ADV_ENB_EVT == cb_evt) + btm_multi_adv_cb.p_adv_inst[inst_id-1].in_use = FALSE; + break; + } + + case BTM_BLE_MULTI_ADV_SET_PARAM: + { + BTM_TRACE_DEBUG("BTM_BLE_MULTI_ADV_SET_PARAM status = %d", status); + break; + } + + case BTM_BLE_MULTI_ADV_WRITE_ADV_DATA: + { + BTM_TRACE_DEBUG("BTM_BLE_MULTI_ADV_WRITE_ADV_DATA status = %d", status); + break; + } + + case BTM_BLE_MULTI_ADV_WRITE_SCAN_RSP_DATA: + { + BTM_TRACE_DEBUG("BTM_BLE_MULTI_ADV_WRITE_SCAN_RSP_DATA status = %d", status); + break; + } + + case BTM_BLE_MULTI_ADV_SET_RANDOM_ADDR: + { + BTM_TRACE_DEBUG("BTM_BLE_MULTI_ADV_SET_RANDOM_ADDR status = %d", status); + break; + } + + default: + break; + } + + if (cb_evt != 0 && p_inst->p_cback != NULL) + { + (p_inst->p_cback)(cb_evt, inst_id, p_inst->p_ref, status); + } + return; +} + +/******************************************************************************* +** +** Function btm_ble_enable_multi_adv +** +** Description This function enable the customer specific feature in controller +** +** Parameters enable: enable or disable +** inst_id: adv instance ID, can not be 0 +** +** Returns status +** +*******************************************************************************/ +tBTM_STATUS btm_ble_enable_multi_adv (BOOLEAN enable, UINT8 inst_id, UINT8 cb_evt) +{ + UINT8 param[BTM_BLE_MULTI_ADV_ENB_LEN], *pp; + UINT8 enb = enable ? 1: 0; + tBTM_STATUS rt; + + pp = param; + memset(param, 0, BTM_BLE_MULTI_ADV_ENB_LEN); + + UINT8_TO_STREAM (pp, BTM_BLE_MULTI_ADV_ENB); + UINT8_TO_STREAM (pp, enb); + UINT8_TO_STREAM (pp, inst_id); + + BTM_TRACE_EVENT (" btm_ble_enable_multi_adv: enb %d, Inst ID %d",enb,inst_id); + + if ((rt = BTM_VendorSpecificCommand (HCI_BLE_MULTI_ADV_OCF, + BTM_BLE_MULTI_ADV_ENB_LEN, + param, + btm_ble_multi_adv_vsc_cmpl_cback)) + == BTM_CMD_STARTED) + { + btm_ble_multi_adv_enq_op_q(BTM_BLE_MULTI_ADV_ENB, inst_id, cb_evt); + } + return rt; +} +/******************************************************************************* +** +** Function btm_ble_map_adv_tx_power +** +** Description return the actual power in dBm based on the mapping in config file +** +** Parameters advertise parameters used for this instance. +** +** Returns tx power in dBm +** +*******************************************************************************/ +int btm_ble_tx_power[BTM_BLE_ADV_TX_POWER_MAX + 1] = BTM_BLE_ADV_TX_POWER; +char btm_ble_map_adv_tx_power(int tx_power_index) +{ + if(0 <= tx_power_index && tx_power_index < BTM_BLE_ADV_TX_POWER_MAX) + return (char)btm_ble_tx_power[tx_power_index]; + return 0; +} +/******************************************************************************* +** +** Function btm_ble_multi_adv_set_params +** +** Description This function enable the customer specific feature in controller +** +** Parameters advertise parameters used for this instance. +** +** Returns status +** +*******************************************************************************/ +tBTM_STATUS btm_ble_multi_adv_set_params (tBTM_BLE_MULTI_ADV_INST *p_inst, + tBTM_BLE_ADV_PARAMS *p_params, + UINT8 cb_evt) +{ + UINT8 param[BTM_BLE_MULTI_ADV_SET_PARAM_LEN], *pp; + tBTM_STATUS rt; + BD_ADDR dummy ={0,0,0,0,0,0}; + + pp = param; + memset(param, 0, BTM_BLE_MULTI_ADV_SET_PARAM_LEN); + + UINT8_TO_STREAM(pp, BTM_BLE_MULTI_ADV_SET_PARAM); + + UINT16_TO_STREAM (pp, p_params->adv_int_min); + UINT16_TO_STREAM (pp, p_params->adv_int_max); + UINT8_TO_STREAM (pp, p_params->adv_type); + +#if (defined BLE_PRIVACY_SPT && BLE_PRIVACY_SPT == TRUE) + if (btm_cb.ble_ctr_cb.privacy_mode != BTM_PRIVACY_NONE) + { + UINT8_TO_STREAM (pp, BLE_ADDR_RANDOM); + BDADDR_TO_STREAM (pp, p_inst->rpa); + } + else +#endif + { + UINT8_TO_STREAM (pp, BLE_ADDR_PUBLIC); + BDADDR_TO_STREAM (pp, controller_get_interface()->get_address()->address); + } + + BTM_TRACE_EVENT (" btm_ble_multi_adv_set_params,Min %d, Max %d,adv_type %d", + p_params->adv_int_min,p_params->adv_int_max,p_params->adv_type); + + UINT8_TO_STREAM (pp, 0); + BDADDR_TO_STREAM (pp, dummy); + + if (p_params->channel_map == 0 || p_params->channel_map > BTM_BLE_DEFAULT_ADV_CHNL_MAP) + p_params->channel_map = BTM_BLE_DEFAULT_ADV_CHNL_MAP; + UINT8_TO_STREAM (pp, p_params->channel_map); + + if (p_params->adv_filter_policy >= AP_SCAN_CONN_POLICY_MAX) + p_params->adv_filter_policy = AP_SCAN_CONN_ALL; + UINT8_TO_STREAM (pp, p_params->adv_filter_policy); + + UINT8_TO_STREAM (pp, p_inst->inst_id); + + if (p_params->tx_power > BTM_BLE_ADV_TX_POWER_MAX) + p_params->tx_power = BTM_BLE_ADV_TX_POWER_MAX; + UINT8_TO_STREAM (pp, btm_ble_map_adv_tx_power(p_params->tx_power)); + + BTM_TRACE_EVENT("set_params:Chnl Map %d,adv_fltr policy %d,ID:%d, TX Power%d", + p_params->channel_map,p_params->adv_filter_policy,p_inst->inst_id,p_params->tx_power); + + if ((rt = BTM_VendorSpecificCommand (HCI_BLE_MULTI_ADV_OCF, + BTM_BLE_MULTI_ADV_SET_PARAM_LEN, + param, + btm_ble_multi_adv_vsc_cmpl_cback)) + == BTM_CMD_STARTED) + { + p_inst->adv_evt = p_params->adv_type; + +#if (defined BLE_PRIVACY_SPT && BLE_PRIVACY_SPT == TRUE) + if (btm_cb.ble_ctr_cb.privacy_mode != BTM_PRIVACY_NONE) + { + /* start timer */ + p_inst->raddr_timer_ent.param = (TIMER_PARAM_TYPE) p_inst; + btu_start_timer_oneshot(&p_inst->raddr_timer_ent, BTU_TTYPE_BLE_RANDOM_ADDR, + BTM_BLE_PRIVATE_ADDR_INT); + } +#endif + btm_ble_multi_adv_enq_op_q(BTM_BLE_MULTI_ADV_SET_PARAM, p_inst->inst_id, cb_evt); + } + return rt; +} + +/******************************************************************************* +** +** Function btm_ble_multi_adv_write_rpa +** +** Description This function write the random address for the adv instance into +** controller +** +** Parameters +** +** Returns status +** +*******************************************************************************/ +tBTM_STATUS btm_ble_multi_adv_write_rpa (tBTM_BLE_MULTI_ADV_INST *p_inst, BD_ADDR random_addr) +{ + UINT8 param[BTM_BLE_MULTI_ADV_SET_RANDOM_ADDR_LEN], *pp = param; + tBTM_STATUS rt; + + BTM_TRACE_EVENT ("%s-BD_ADDR:%02x-%02x-%02x-%02x-%02x-%02x,inst_id:%d", + __FUNCTION__, random_addr[5], random_addr[4], random_addr[3], random_addr[2], + random_addr[1], random_addr[0], p_inst->inst_id); + + memset(param, 0, BTM_BLE_MULTI_ADV_SET_RANDOM_ADDR_LEN); + + UINT8_TO_STREAM (pp, BTM_BLE_MULTI_ADV_SET_RANDOM_ADDR); + BDADDR_TO_STREAM(pp, random_addr); + UINT8_TO_STREAM(pp, p_inst->inst_id); + + if ((rt = BTM_VendorSpecificCommand (HCI_BLE_MULTI_ADV_OCF, + BTM_BLE_MULTI_ADV_SET_RANDOM_ADDR_LEN, + param, + btm_ble_multi_adv_vsc_cmpl_cback)) == BTM_CMD_STARTED) + { + /* start a periodical timer to refresh random addr */ + btu_stop_timer_oneshot(&p_inst->raddr_timer_ent); + p_inst->raddr_timer_ent.param = (TIMER_PARAM_TYPE) p_inst; + btu_start_timer_oneshot(&p_inst->raddr_timer_ent, BTU_TTYPE_BLE_RANDOM_ADDR, + BTM_BLE_PRIVATE_ADDR_INT); + + btm_ble_multi_adv_enq_op_q(BTM_BLE_MULTI_ADV_SET_RANDOM_ADDR, p_inst->inst_id, 0); + } + return rt; +} + +/******************************************************************************* +** +** Function btm_ble_multi_adv_gen_rpa_cmpl +** +** Description RPA generation completion callback for each adv instance. Will +** continue write the new RPA into controller. +** +** Returns none. +** +*******************************************************************************/ +void btm_ble_multi_adv_gen_rpa_cmpl(tBTM_RAND_ENC *p) +{ +#if (SMP_INCLUDED == TRUE) + tSMP_ENC output; + UINT8 index = 0; + tBTM_BLE_MULTI_ADV_INST *p_inst = NULL; + + /* Retrieve the index of adv instance from stored Q */ + if (btm_multi_adv_idx_q.front == -1) + { + BTM_TRACE_ERROR(" %s can't locate advertise instance", __FUNCTION__); + return; + } + else + { + index = btm_multi_adv_idx_q.inst_index_queue[btm_multi_adv_idx_q.front]; + if (btm_multi_adv_idx_q.front == btm_multi_adv_idx_q.rear) + { + btm_multi_adv_idx_q.front = -1; + btm_multi_adv_idx_q.rear = -1; + } + else + { + btm_multi_adv_idx_q.front = (btm_multi_adv_idx_q.front + 1) % BTM_BLE_MULTI_ADV_MAX; + } + } + + p_inst = &(btm_multi_adv_cb.p_adv_inst[index]); + + BTM_TRACE_EVENT ("btm_ble_multi_adv_gen_rpa_cmpl inst_id = %d", p_inst->inst_id); + if (p) + { + p->param_buf[2] &= (~BLE_RESOLVE_ADDR_MASK); + p->param_buf[2] |= BLE_RESOLVE_ADDR_MSB; + + p_inst->rpa[2] = p->param_buf[0]; + p_inst->rpa[1] = p->param_buf[1]; + p_inst->rpa[0] = p->param_buf[2]; + + if (!SMP_Encrypt(btm_cb.devcb.id_keys.irk, BT_OCTET16_LEN, p->param_buf, 3, &output)) + { + BTM_TRACE_DEBUG("generate random address failed"); + } + else + { + /* set hash to be LSB of rpAddress */ + p_inst->rpa[5] = output.param_buf[0]; + p_inst->rpa[4] = output.param_buf[1]; + p_inst->rpa[3] = output.param_buf[2]; + } + + if (p_inst->inst_id != BTM_BLE_MULTI_ADV_DEFAULT_STD && + p_inst->inst_id < BTM_BleMaxMultiAdvInstanceCount()) + { + /* set it to controller */ + btm_ble_multi_adv_write_rpa(p_inst, p_inst->rpa); + } + } +#endif +} + +/******************************************************************************* +** +** Function btm_ble_multi_adv_configure_rpa +** +** Description This function set the random address for the adv instance +** +** Parameters advertise parameters used for this instance. +** +** Returns none +** +*******************************************************************************/ +void btm_ble_multi_adv_configure_rpa (tBTM_BLE_MULTI_ADV_INST *p_inst) +{ + if (btm_multi_adv_idx_q.front == (btm_multi_adv_idx_q.rear + 1) % BTM_BLE_MULTI_ADV_MAX) + { + BTM_TRACE_ERROR("outstanding rand generation exceeded max allowed "); + return; + } + else + { + if (btm_multi_adv_idx_q.front == -1) + { + btm_multi_adv_idx_q.front = 0; + btm_multi_adv_idx_q.rear = 0; + } + else + { + btm_multi_adv_idx_q.rear = (btm_multi_adv_idx_q.rear + 1) % BTM_BLE_MULTI_ADV_MAX; + } + btm_multi_adv_idx_q.inst_index_queue[btm_multi_adv_idx_q.rear] = p_inst->index; + } + btm_gen_resolvable_private_addr((void *)btm_ble_multi_adv_gen_rpa_cmpl); +} + +/******************************************************************************* +** +** Function btm_ble_multi_adv_reenable +** +** Description This function re-enable adv instance upon a connection establishment. +** +** Parameters advertise parameters used for this instance. +** +** Returns none. +** +*******************************************************************************/ +void btm_ble_multi_adv_reenable(UINT8 inst_id) +{ + tBTM_BLE_MULTI_ADV_INST *p_inst = &btm_multi_adv_cb.p_adv_inst[inst_id - 1]; + + if (TRUE == p_inst->in_use) + { + if (p_inst->adv_evt != BTM_BLE_CONNECT_DIR_EVT) + btm_ble_enable_multi_adv (TRUE, p_inst->inst_id, 0); + else + /* mark directed adv as disabled if adv has been stopped */ + { + (p_inst->p_cback)(BTM_BLE_MULTI_ADV_DISABLE_EVT,p_inst->inst_id,p_inst->p_ref,0); + p_inst->in_use = FALSE; + } + } +} + +/******************************************************************************* +** +** Function btm_ble_multi_adv_enb_privacy +** +** Description This function enable/disable privacy setting in multi adv +** +** Parameters enable: enable or disable the adv instance. +** +** Returns none. +** +*******************************************************************************/ +void btm_ble_multi_adv_enb_privacy(BOOLEAN enable) +{ + UINT8 i; + tBTM_BLE_MULTI_ADV_INST *p_inst = &btm_multi_adv_cb.p_adv_inst[0]; + + for (i = 0; i < BTM_BleMaxMultiAdvInstanceCount() - 1; i ++, p_inst++) + { + p_inst->in_use = FALSE; + if (enable) + btm_ble_multi_adv_configure_rpa (p_inst); + else + btu_stop_timer_oneshot(&p_inst->raddr_timer_ent); + } +} + +/******************************************************************************* +** +** Function BTM_BleEnableAdvInstance +** +** Description This function enable a Multi-ADV instance with the specified +** adv parameters +** +** Parameters p_params: pointer to the adv parameter structure, set as default +** adv parameter when the instance is enabled. +** p_cback: callback function for the adv instance. +** p_ref: reference data attach to the adv instance to be enabled. +** +** Returns status +** +*******************************************************************************/ +tBTM_STATUS BTM_BleEnableAdvInstance (tBTM_BLE_ADV_PARAMS *p_params, + tBTM_BLE_MULTI_ADV_CBACK *p_cback,void *p_ref) +{ + UINT8 i; + tBTM_STATUS rt = BTM_NO_RESOURCES; + tBTM_BLE_MULTI_ADV_INST *p_inst = &btm_multi_adv_cb.p_adv_inst[0]; + + BTM_TRACE_EVENT("BTM_BleEnableAdvInstance called"); + + if (0 == btm_cb.cmn_ble_vsc_cb.adv_inst_max) + { + BTM_TRACE_ERROR("Controller does not support Multi ADV"); + return BTM_ERR_PROCESSING; + } + + if (NULL == p_inst) + { + BTM_TRACE_ERROR("Invalid instance in BTM_BleEnableAdvInstance"); + return BTM_ERR_PROCESSING; + } + + for (i = 0; i < BTM_BleMaxMultiAdvInstanceCount() - 1; i ++, p_inst++) + { + if (FALSE == p_inst->in_use) + { + p_inst->in_use = TRUE; + /* configure adv parameter */ + if (p_params) + rt = btm_ble_multi_adv_set_params(p_inst, p_params, 0); + else + rt = BTM_CMD_STARTED; + + /* enable adv */ + BTM_TRACE_EVENT("btm_ble_enable_multi_adv being called with inst_id:%d", + p_inst->inst_id); + + if (BTM_CMD_STARTED == rt) + { + if ((rt = btm_ble_enable_multi_adv (TRUE, p_inst->inst_id, + BTM_BLE_MULTI_ADV_ENB_EVT)) == BTM_CMD_STARTED) + { + p_inst->p_cback = p_cback; + p_inst->p_ref = p_ref; + } + } + + if (BTM_CMD_STARTED != rt) + { + p_inst->in_use = FALSE; + BTM_TRACE_ERROR("BTM_BleEnableAdvInstance failed"); + } + break; + } + } + return rt; +} + +/******************************************************************************* +** +** Function BTM_BleUpdateAdvInstParam +** +** Description This function update a Multi-ADV instance with the specified +** adv parameters. +** +** Parameters inst_id: adv instance ID +** p_params: pointer to the adv parameter structure. +** +** Returns status +** +*******************************************************************************/ +tBTM_STATUS BTM_BleUpdateAdvInstParam (UINT8 inst_id, tBTM_BLE_ADV_PARAMS *p_params) +{ + tBTM_STATUS rt = BTM_ILLEGAL_VALUE; + tBTM_BLE_MULTI_ADV_INST *p_inst = &btm_multi_adv_cb.p_adv_inst[inst_id - 1]; + + BTM_TRACE_EVENT("BTM_BleUpdateAdvInstParam called with inst_id:%d", inst_id); + + if (0 == btm_cb.cmn_ble_vsc_cb.adv_inst_max) + { + BTM_TRACE_ERROR("Controller does not support Multi ADV"); + return BTM_ERR_PROCESSING; + } + + if (inst_id < BTM_BleMaxMultiAdvInstanceCount() && + inst_id != BTM_BLE_MULTI_ADV_DEFAULT_STD && + p_params != NULL) + { + if (FALSE == p_inst->in_use) + { + BTM_TRACE_DEBUG("adv instance %d is not active", inst_id); + return BTM_WRONG_MODE; + } + else + btm_ble_enable_multi_adv(FALSE, inst_id, 0); + + if (BTM_CMD_STARTED == btm_ble_multi_adv_set_params(p_inst, p_params, 0)) + rt = btm_ble_enable_multi_adv(TRUE, inst_id, BTM_BLE_MULTI_ADV_PARAM_EVT); + } + return rt; +} + +/******************************************************************************* +** +** Function BTM_BleCfgAdvInstData +** +** Description This function configure a Multi-ADV instance with the specified +** adv data or scan response data. +** +** Parameters inst_id: adv instance ID +** is_scan_rsp: is this scan response. if no, set as adv data. +** data_mask: adv data mask. +** p_data: pointer to the adv data structure. +** +** Returns status +** +*******************************************************************************/ +tBTM_STATUS BTM_BleCfgAdvInstData (UINT8 inst_id, BOOLEAN is_scan_rsp, + tBTM_BLE_AD_MASK data_mask, + tBTM_BLE_ADV_DATA *p_data) +{ + UINT8 param[BTM_BLE_MULTI_ADV_WRITE_DATA_LEN], *pp = param; + UINT8 sub_code = (is_scan_rsp) ? + BTM_BLE_MULTI_ADV_WRITE_SCAN_RSP_DATA : BTM_BLE_MULTI_ADV_WRITE_ADV_DATA; + UINT8 *p_len; + tBTM_STATUS rt; + UINT8 *pp_temp = (UINT8*)(param + BTM_BLE_MULTI_ADV_WRITE_DATA_LEN -1); + tBTM_BLE_VSC_CB cmn_ble_vsc_cb; + + BTM_BleGetVendorCapabilities(&cmn_ble_vsc_cb); + if (0 == cmn_ble_vsc_cb.adv_inst_max) + { + BTM_TRACE_ERROR("Controller does not support Multi ADV"); + return BTM_ERR_PROCESSING; + } + + btm_ble_update_dmt_flag_bits(&p_data->flag, btm_cb.btm_inq_vars.connectable_mode, + btm_cb.btm_inq_vars.discoverable_mode); + + BTM_TRACE_EVENT("BTM_BleCfgAdvInstData called with inst_id:%d", inst_id); + if (inst_id > BTM_BLE_MULTI_ADV_MAX || inst_id == BTM_BLE_MULTI_ADV_DEFAULT_STD) + return BTM_ILLEGAL_VALUE; + + memset(param, 0, BTM_BLE_MULTI_ADV_WRITE_DATA_LEN); + + UINT8_TO_STREAM(pp, sub_code); + p_len = pp ++; + btm_ble_build_adv_data(&data_mask, &pp, p_data); + *p_len = (UINT8)(pp - param - 2); + UINT8_TO_STREAM(pp_temp, inst_id); + + if ((rt = BTM_VendorSpecificCommand (HCI_BLE_MULTI_ADV_OCF, + (UINT8)BTM_BLE_MULTI_ADV_WRITE_DATA_LEN, + param, + btm_ble_multi_adv_vsc_cmpl_cback)) + == BTM_CMD_STARTED) + { + btm_ble_multi_adv_enq_op_q(sub_code, inst_id, BTM_BLE_MULTI_ADV_DATA_EVT); + } + return rt; +} + +/******************************************************************************* +** +** Function BTM_BleDisableAdvInstance +** +** Description This function disables a Multi-ADV instance. +** +** Parameters inst_id: adv instance ID +** +** Returns status +** +*******************************************************************************/ +tBTM_STATUS BTM_BleDisableAdvInstance (UINT8 inst_id) +{ + tBTM_STATUS rt = BTM_ILLEGAL_VALUE; + tBTM_BLE_VSC_CB cmn_ble_vsc_cb; + + BTM_TRACE_EVENT("BTM_BleDisableAdvInstance with inst_id:%d", inst_id); + + BTM_BleGetVendorCapabilities(&cmn_ble_vsc_cb); + + if (0 == cmn_ble_vsc_cb.adv_inst_max) + { + BTM_TRACE_ERROR("Controller does not support Multi ADV"); + return BTM_ERR_PROCESSING; + } + + if (inst_id < BTM_BleMaxMultiAdvInstanceCount() && + inst_id != BTM_BLE_MULTI_ADV_DEFAULT_STD) + { + if ((rt = btm_ble_enable_multi_adv(FALSE, inst_id, BTM_BLE_MULTI_ADV_DISABLE_EVT)) + == BTM_CMD_STARTED) + { + btm_ble_multi_adv_configure_rpa(&btm_multi_adv_cb.p_adv_inst[inst_id-1]); + btu_stop_timer_oneshot(&btm_multi_adv_cb.p_adv_inst[inst_id-1].raddr_timer_ent); + btm_multi_adv_cb.p_adv_inst[inst_id-1].in_use = FALSE; + } + } + return rt; +} +/******************************************************************************* +** +** Function btm_ble_multi_adv_vse_cback +** +** Description VSE callback for multi adv events. +** +** Returns +** +*******************************************************************************/ +void btm_ble_multi_adv_vse_cback(UINT8 len, UINT8 *p) +{ + UINT8 sub_event; + UINT8 adv_inst, idx; + UINT16 conn_handle; + + /* Check if this is a BLE RSSI vendor specific event */ + STREAM_TO_UINT8(sub_event, p); + len--; + + BTM_TRACE_EVENT("btm_ble_multi_adv_vse_cback called with event:%d", sub_event); + if ((sub_event == HCI_VSE_SUBCODE_BLE_MULTI_ADV_ST_CHG) && (len >= 4)) + { + STREAM_TO_UINT8(adv_inst, p); + ++p; + STREAM_TO_UINT16(conn_handle, p); + + if ((idx = btm_handle_to_acl_index(conn_handle)) != MAX_L2CAP_LINKS) + { +#if (defined BLE_PRIVACY_SPT && BLE_PRIVACY_SPT == TRUE) + if (btm_cb.ble_ctr_cb.privacy_mode != BTM_PRIVACY_NONE && + adv_inst <= BTM_BLE_MULTI_ADV_MAX && adv_inst != BTM_BLE_MULTI_ADV_DEFAULT_STD) + { + memcpy(btm_cb.acl_db[idx].conn_addr, btm_multi_adv_cb.p_adv_inst[adv_inst - 1].rpa, + BD_ADDR_LEN); + } +#endif + } + + if (adv_inst < BTM_BleMaxMultiAdvInstanceCount() && + adv_inst != BTM_BLE_MULTI_ADV_DEFAULT_STD) + { + BTM_TRACE_EVENT("btm_ble_multi_adv_reenable called"); + btm_ble_multi_adv_reenable(adv_inst); + } + /* re-enable connectibility */ + else if (adv_inst == BTM_BLE_MULTI_ADV_DEFAULT_STD) + { + if (btm_cb.ble_ctr_cb.inq_var.connectable_mode == BTM_BLE_CONNECTABLE) + { + btm_ble_set_connectability ( btm_cb.ble_ctr_cb.inq_var.connectable_mode ); + } + } + + } + +} +/******************************************************************************* +** +** Function btm_ble_multi_adv_init +** +** Description This function initialize the multi adv control block. +** +** Parameters None +** +** Returns void +** +*******************************************************************************/ +void btm_ble_multi_adv_init() +{ + UINT8 i = 0; + memset(&btm_multi_adv_cb, 0, sizeof(tBTM_BLE_MULTI_ADV_CB)); + memset (&btm_multi_adv_idx_q,0, sizeof (tBTM_BLE_MULTI_ADV_INST_IDX_Q)); + btm_multi_adv_idx_q.front = -1; + btm_multi_adv_idx_q.rear = -1; + + if (btm_cb.cmn_ble_vsc_cb.adv_inst_max > 0) + { + btm_multi_adv_cb.p_adv_inst = GKI_getbuf( sizeof(tBTM_BLE_MULTI_ADV_INST)* + (btm_cb.cmn_ble_vsc_cb.adv_inst_max)); + memset(btm_multi_adv_cb.p_adv_inst, 0, sizeof(tBTM_BLE_MULTI_ADV_INST)* + (btm_cb.cmn_ble_vsc_cb.adv_inst_max)); + + btm_multi_adv_cb.op_q.p_sub_code = GKI_getbuf( sizeof(UINT8) * + (btm_cb.cmn_ble_vsc_cb.adv_inst_max)); + memset(btm_multi_adv_cb.op_q.p_sub_code, 0, + sizeof(UINT8)*(btm_cb.cmn_ble_vsc_cb.adv_inst_max)); + + btm_multi_adv_cb.op_q.p_inst_id = GKI_getbuf( sizeof(UINT8) * + (btm_cb.cmn_ble_vsc_cb.adv_inst_max)); + memset(btm_multi_adv_cb.op_q.p_inst_id, 0, + sizeof(UINT8)*(btm_cb.cmn_ble_vsc_cb.adv_inst_max)); + } + + /* Initialize adv instance indices and IDs. */ + for (i = 0; i < btm_cb.cmn_ble_vsc_cb.adv_inst_max; i++) { + btm_multi_adv_cb.p_adv_inst[i].index = i; + btm_multi_adv_cb.p_adv_inst[i].inst_id = i + 1; + } + + BTM_RegisterForVSEvents(btm_ble_multi_adv_vse_cback, TRUE); +} + +/******************************************************************************* +** +** Function btm_ble_multi_adv_cleanup +** +** Description This function cleans up multi adv control block. +** +** Parameters +** Returns void +** +*******************************************************************************/ +void btm_ble_multi_adv_cleanup(void) +{ + if (btm_multi_adv_cb.p_adv_inst) + GKI_freebuf(btm_multi_adv_cb.p_adv_inst); + + if (btm_multi_adv_cb.op_q.p_sub_code) + GKI_freebuf(btm_multi_adv_cb.op_q.p_sub_code); + + if (btm_multi_adv_cb.op_q.p_inst_id) + GKI_freebuf(btm_multi_adv_cb.op_q.p_inst_id); + +} + +/******************************************************************************* +** +** Function btm_ble_multi_adv_get_ref +** +** Description This function obtains the reference pointer for the instance ID provided +** +** Parameters inst_id - Instance ID +** +** Returns void* +** +*******************************************************************************/ +void* btm_ble_multi_adv_get_ref(UINT8 inst_id) +{ + tBTM_BLE_MULTI_ADV_INST *p_inst = NULL; + + if (inst_id < BTM_BleMaxMultiAdvInstanceCount()) + { + p_inst = &btm_multi_adv_cb.p_adv_inst[inst_id - 1]; + if (NULL != p_inst) + return p_inst->p_ref; + } + + return NULL; +} +#endif + diff --git a/components/bt/bluedroid/stack/btm/btm_ble_privacy.c b/components/bt/bluedroid/stack/btm/btm_ble_privacy.c new file mode 100755 index 0000000000..c7362a7b9f --- /dev/null +++ b/components/bt/bluedroid/stack/btm/btm_ble_privacy.c @@ -0,0 +1,1029 @@ +/****************************************************************************** + * + * Copyright (C) 1999-2012 Broadcom Corporation + * + * 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 functions for BLE controller based privacy. + * + ******************************************************************************/ +#include +#include "bt_target.h" + +#if (BLE_INCLUDED == TRUE && BLE_PRIVACY_SPT == TRUE) +#include "bt_types.h" +#include "hcimsgs.h" +#include "btu.h" +//#include "vendor_hcidefs.h" +#include "btm_int.h" +#include "controller.h" +#include "hcidefs.h" + +#define HCI_VENDOR_BLE_RPA_VSC (0x0155 | HCI_GRP_VENDOR_SPECIFIC) + +/* RPA offload VSC specifics */ +#define BTM_BLE_META_IRK_ENABLE 0x01 +#define BTM_BLE_META_ADD_IRK_ENTRY 0x02 +#define BTM_BLE_META_REMOVE_IRK_ENTRY 0x03 +#define BTM_BLE_META_CLEAR_IRK_LIST 0x04 +#define BTM_BLE_META_READ_IRK_ENTRY 0x05 +#define BTM_BLE_META_CS_RESOLVE_ADDR 0x00000001 +#define BTM_BLE_IRK_ENABLE_LEN 2 + +#define BTM_BLE_META_ADD_IRK_LEN 24 +#define BTM_BLE_META_REMOVE_IRK_LEN 8 +#define BTM_BLE_META_CLEAR_IRK_LEN 1 +#define BTM_BLE_META_READ_IRK_LEN 2 +#define BTM_BLE_META_ADD_WL_ATTR_LEN 9 + +/******************************************************************************* +** Functions implemented controller based privacy using Resolving List +*******************************************************************************/ +/******************************************************************************* +** +** Function btm_ble_enq_resolving_list_pending +** +** Description add target address into resolving pending operation queue +** +** Parameters target_bda: target device address +** add_entry: TRUE for add entry, FALSE for remove entry +** +** Returns void +** +*******************************************************************************/ +void btm_ble_enq_resolving_list_pending(BD_ADDR pseudo_bda, UINT8 op_code) +{ + tBTM_BLE_RESOLVE_Q *p_q = &btm_cb.ble_ctr_cb.resolving_list_pend_q; + + memcpy(p_q->resolve_q_random_pseudo[p_q->q_next], pseudo_bda, BD_ADDR_LEN); + p_q->resolve_q_action[p_q->q_next] = op_code; + p_q->q_next ++; + p_q->q_next %= controller_get_interface()->get_ble_resolving_list_max_size(); +} + +/******************************************************************************* +** +** Function btm_ble_brcm_find_resolving_pending_entry +** +** Description check to see if the action is in pending list +** +** Parameters TRUE: action pending; +** FALSE: new action +** +** Returns void +** +*******************************************************************************/ +BOOLEAN btm_ble_brcm_find_resolving_pending_entry(BD_ADDR pseudo_addr, UINT8 action) +{ + tBTM_BLE_RESOLVE_Q *p_q = &btm_cb.ble_ctr_cb.resolving_list_pend_q; + + for (UINT8 i = p_q->q_pending; i != p_q->q_next;) + { + if (memcmp(p_q->resolve_q_random_pseudo[i], pseudo_addr, BD_ADDR_LEN) == 0 && + action == p_q->resolve_q_action[i]) + return TRUE; + + i ++; + i %= controller_get_interface()->get_ble_resolving_list_max_size(); + } + return FALSE; +} + +/******************************************************************************* +** +** Function btm_ble_deq_resolving_pending +** +** Description dequeue target address from resolving pending operation queue +** +** Parameters pseudo_addr: pseudo_addr device address +** +** Returns void +** +*******************************************************************************/ +BOOLEAN btm_ble_deq_resolving_pending(BD_ADDR pseudo_addr) +{ + tBTM_BLE_RESOLVE_Q *p_q = &btm_cb.ble_ctr_cb.resolving_list_pend_q; + + if (p_q->q_next != p_q->q_pending) + { + memcpy(pseudo_addr, p_q->resolve_q_random_pseudo[p_q->q_pending], BD_ADDR_LEN); + memset(p_q->resolve_q_random_pseudo[p_q->q_pending], 0, BD_ADDR_LEN); + p_q->q_pending ++; + p_q->q_pending %= controller_get_interface()->get_ble_resolving_list_max_size(); + return TRUE; + } + + return FALSE; +} + +/******************************************************************************* +** +** Function btm_ble_clear_irk_index +** +** Description clear IRK list index mask for availability +** +** Returns none +** +*******************************************************************************/ +void btm_ble_clear_irk_index(UINT8 index) +{ + UINT8 byte; + UINT8 bit; + + if (index < controller_get_interface()->get_ble_resolving_list_max_size()) + { + byte = index / 8; + bit = index % 8; + btm_cb.ble_ctr_cb.irk_list_mask[byte] &= (~(1 << bit)); + } +} + +/******************************************************************************* +** +** Function btm_ble_find_irk_index +** +** Description find the first available IRK list index +** +** Returns index from 0 ~ max (127 default) +** +*******************************************************************************/ +UINT8 btm_ble_find_irk_index(void) +{ + UINT8 i = 0; + UINT8 byte; + UINT8 bit; + + while (i < controller_get_interface()->get_ble_resolving_list_max_size()) + { + byte = i / 8; + bit = i % 8; + + if ((btm_cb.ble_ctr_cb.irk_list_mask[byte] & (1 << bit)) == 0) + { + btm_cb.ble_ctr_cb.irk_list_mask[byte] |= (1 << bit); + return i; + } + i++; + } + + BTM_TRACE_ERROR ("%s failed, list full", __func__); + return i; +} + +/******************************************************************************* +** +** Function btm_ble_update_resolving_list +** +** Description update resolving list entry in host maintained record +** +** Returns void +** +*******************************************************************************/ +void btm_ble_update_resolving_list(BD_ADDR pseudo_bda, BOOLEAN add) +{ + tBTM_SEC_DEV_REC *p_dev_rec = btm_find_dev(pseudo_bda); + if (p_dev_rec == NULL) + return; + + if (add) + { + p_dev_rec->ble.in_controller_list |= BTM_RESOLVING_LIST_BIT; + if (!controller_get_interface()->supports_ble_privacy()) + p_dev_rec->ble.resolving_list_index = btm_ble_find_irk_index(); + } + else + { + p_dev_rec->ble.in_controller_list &= ~BTM_RESOLVING_LIST_BIT; + if (!controller_get_interface()->supports_ble_privacy()) + { + /* clear IRK list index mask */ + btm_ble_clear_irk_index(p_dev_rec->ble.resolving_list_index); + p_dev_rec->ble.resolving_list_index = 0; + } + } +} + +/******************************************************************************* +** +** Function btm_ble_clear_resolving_list_complete +** +** Description This function is called when command complete for +** clear resolving list +** +** Returns void +** +*******************************************************************************/ +void btm_ble_clear_resolving_list_complete(UINT8 *p, UINT16 evt_len) +{ + UINT8 status = 0; + STREAM_TO_UINT8(status, p); + + BTM_TRACE_DEBUG("%s status=%d", __func__, status); + + if (status == HCI_SUCCESS) + { + if (evt_len >= 3) + { + /* VSC complete has one extra byte for op code and list size, skip it here */ + p ++; + + /* updated the available list size, and current list size */ + uint8_t irk_list_sz_max = 0; + STREAM_TO_UINT8(irk_list_sz_max, p); + + if (controller_get_interface()->get_ble_resolving_list_max_size() == 0) + btm_ble_resolving_list_init(irk_list_sz_max); + + uint8_t irk_mask_size = (irk_list_sz_max % 8) ? + (irk_list_sz_max / 8 + 1) : (irk_list_sz_max / 8); + memset(btm_cb.ble_ctr_cb.irk_list_mask, 0, irk_mask_size); + } + + btm_cb.ble_ctr_cb.resolving_list_avail_size = + controller_get_interface()->get_ble_resolving_list_max_size(); + + BTM_TRACE_DEBUG("%s resolving_list_avail_size=%d", + __func__, btm_cb.ble_ctr_cb.resolving_list_avail_size); + + for (UINT8 i = 0; i < BTM_SEC_MAX_DEVICE_RECORDS; ++i) + btm_cb.sec_dev_rec[i].ble.in_controller_list &= ~BTM_RESOLVING_LIST_BIT; + } +} + +/******************************************************************************* +** +** Function btm_ble_add_resolving_list_entry_complete +** +** Description This function is called when command complete for +** add resolving list entry +** +** Returns void +** +*******************************************************************************/ +void btm_ble_add_resolving_list_entry_complete(UINT8 *p, UINT16 evt_len) +{ + UINT8 status; + STREAM_TO_UINT8(status, p); + + BTM_TRACE_DEBUG("%s status = %d", __func__, status); + + BD_ADDR pseudo_bda; + if (!btm_ble_deq_resolving_pending(pseudo_bda)) + { + BTM_TRACE_DEBUG("no pending resolving list operation"); + return; + } + + if (status == HCI_SUCCESS) + { + /* privacy 1.2 command complete does not have these extra byte */ + if (evt_len > 2) + { + /* VSC complete has one extra byte for op code, skip it here */ + p ++; + STREAM_TO_UINT8(btm_cb.ble_ctr_cb.resolving_list_avail_size, p); + } + else + btm_cb.ble_ctr_cb.resolving_list_avail_size --; + } + else if (status == HCI_ERR_MEMORY_FULL) /* BT_ERROR_CODE_MEMORY_CAPACITY_EXCEEDED */ + { + btm_cb.ble_ctr_cb.resolving_list_avail_size = 0; + BTM_TRACE_DEBUG("%s Resolving list Full ", __func__); + } +} + +/******************************************************************************* +** +** Function btm_ble_remove_resolving_list_entry_complete +** +** Description This function is called when command complete for +** remove resolving list entry +** +** Returns void +** +*******************************************************************************/ +void btm_ble_remove_resolving_list_entry_complete(UINT8 *p, UINT16 evt_len) +{ + BD_ADDR pseudo_bda; + UINT8 status; + + STREAM_TO_UINT8(status, p); + + BTM_TRACE_DEBUG("%s status = %d", __func__, status); + + if (!btm_ble_deq_resolving_pending(pseudo_bda)) + { + BTM_TRACE_ERROR("%s no pending resolving list operation", __func__); + return; + } + + if (status == HCI_SUCCESS) + { + /* proprietary: spec does not have these extra bytes */ + if (evt_len > 2) + { + p ++; /* skip opcode */ + STREAM_TO_UINT8(btm_cb.ble_ctr_cb.resolving_list_avail_size, p); + } + else + btm_cb.ble_ctr_cb.resolving_list_avail_size++; + } +} + +/******************************************************************************* +** +** Function btm_ble_read_resolving_list_entry_complete +** +** Description This function is called when command complete for +** remove resolving list entry +** +** Returns void +** +*******************************************************************************/ +void btm_ble_read_resolving_list_entry_complete(UINT8 *p, UINT16 evt_len) +{ + UINT8 status, rra_type = BTM_BLE_ADDR_PSEUDO; + BD_ADDR rra, pseudo_bda; + + STREAM_TO_UINT8 (status, p); + + BTM_TRACE_DEBUG("%s status = %d", __func__, status); + + if (!btm_ble_deq_resolving_pending(pseudo_bda)) + { + BTM_TRACE_ERROR("no pending resolving list operation"); + return; + } + + if (status == HCI_SUCCESS) + { + /* proprietary spec has extra bytes */ + if (evt_len > 8) + { + p += (2 + 16 + 1 + 6); /* skip subcode, index, IRK value, address type, identity addr type */ + STREAM_TO_BDADDR(rra, p); + + BTM_TRACE_ERROR("%s peer_addr: %02x:%02x:%02x:%02x:%02x:%02x", + __func__, rra[0], rra[1], rra[2], rra[3], rra[4], rra[5]); + } + else + { + STREAM_TO_BDADDR(rra, p); + } + btm_ble_refresh_peer_resolvable_private_addr(pseudo_bda, rra, rra_type); + } +} +/******************************************************************************* + VSC that implement controller based privacy +********************************************************************************/ +/******************************************************************************* +** +** Function btm_ble_resolving_list_vsc_op_cmpl +** +** Description IRK operation VSC complete handler +** +** Parameters +** +** Returns void +** +*******************************************************************************/ +void btm_ble_resolving_list_vsc_op_cmpl (tBTM_VSC_CMPL *p_params) +{ + UINT8 *p = p_params->p_param_buf, op_subcode; + UINT16 evt_len = p_params->param_len; + + op_subcode = *(p + 1); + + BTM_TRACE_DEBUG("%s op_subcode = %d", __func__, op_subcode); + + if (op_subcode == BTM_BLE_META_CLEAR_IRK_LIST) + { + btm_ble_clear_resolving_list_complete(p, evt_len); + } + else if (op_subcode == BTM_BLE_META_ADD_IRK_ENTRY) + { + btm_ble_add_resolving_list_entry_complete(p, evt_len); + } + else if (op_subcode == BTM_BLE_META_REMOVE_IRK_ENTRY) + { + btm_ble_remove_resolving_list_entry_complete(p, evt_len); + } + else if (op_subcode == BTM_BLE_META_READ_IRK_ENTRY) + { + btm_ble_read_resolving_list_entry_complete(p, evt_len); + } + else if (op_subcode == BTM_BLE_META_IRK_ENABLE) + { + /* RPA offloading enable/disabled */ + } +} + +/******************************************************************************* +** +** Function btm_ble_remove_resolving_list_entry +** +** Description This function to remove an IRK entry from the list +** +** Parameters ble_addr_type: address type +** ble_addr: LE adddress +** +** Returns status +** +*******************************************************************************/ +tBTM_STATUS btm_ble_remove_resolving_list_entry(tBTM_SEC_DEV_REC *p_dev_rec) +{ + /* if controller does not support RPA offloading or privacy 1.2, skip */ + if (controller_get_interface()->get_ble_resolving_list_max_size() == 0) + return BTM_WRONG_MODE; + + tBTM_STATUS st = BTM_NO_RESOURCES; + if (controller_get_interface()->supports_ble_privacy()) + { + if (btsnd_hcic_ble_rm_device_resolving_list(p_dev_rec->ble.static_addr_type, + p_dev_rec->ble.static_addr)) + st = BTM_CMD_STARTED; + } + else + { + UINT8 param[20]= {0}; + UINT8 *p = param; + + UINT8_TO_STREAM(p, BTM_BLE_META_REMOVE_IRK_ENTRY); + UINT8_TO_STREAM(p, p_dev_rec->ble.static_addr_type); + BDADDR_TO_STREAM(p, p_dev_rec->ble.static_addr); + + st = BTM_VendorSpecificCommand(HCI_VENDOR_BLE_RPA_VSC, + BTM_BLE_META_REMOVE_IRK_LEN, + param, + btm_ble_resolving_list_vsc_op_cmpl); + } + + if (st == BTM_CMD_STARTED) + btm_ble_enq_resolving_list_pending( p_dev_rec->bd_addr, BTM_BLE_META_REMOVE_IRK_ENTRY); + + return st; +} + +/******************************************************************************* +** +** Function btm_ble_clear_resolving_list +** +** Description This function clears the resolving list +** +** Parameters None. +** +** Returns status +** +*******************************************************************************/ +tBTM_STATUS btm_ble_clear_resolving_list(void) +{ + tBTM_STATUS st = BTM_NO_RESOURCES; + + if (controller_get_interface()->supports_ble_privacy()) + { + if (btsnd_hcic_ble_clear_resolving_list()) + st = BTM_SUCCESS; + } + else + { + UINT8 param[20] = {0}; + UINT8 *p = param; + + UINT8_TO_STREAM(p, BTM_BLE_META_CLEAR_IRK_LIST); + st = BTM_VendorSpecificCommand (HCI_VENDOR_BLE_RPA_VSC, + BTM_BLE_META_CLEAR_IRK_LEN, + param, + btm_ble_resolving_list_vsc_op_cmpl); + } + + return st; +} + +/******************************************************************************* +** +** Function btm_ble_read_resolving_list_entry +** +** Description This function read an IRK entry by index +** +** Parameters entry index. +** +** Returns status +** +*******************************************************************************/ +tBTM_STATUS btm_ble_read_resolving_list_entry(tBTM_SEC_DEV_REC *p_dev_rec) +{ + tBTM_STATUS st = BTM_NO_RESOURCES; + + if (!(p_dev_rec->ble.in_controller_list & BTM_RESOLVING_LIST_BIT)) + return BTM_WRONG_MODE; + + if (controller_get_interface()->supports_ble_privacy()) + { + if (btsnd_hcic_ble_read_resolvable_addr_peer(p_dev_rec->ble.static_addr_type, + p_dev_rec->ble.static_addr)) + st = BTM_CMD_STARTED; + } + else + { + UINT8 param[20] = {0}; + UINT8 *p = param; + + UINT8_TO_STREAM(p, BTM_BLE_META_READ_IRK_ENTRY); + UINT8_TO_STREAM(p, p_dev_rec->ble.resolving_list_index); + + st = BTM_VendorSpecificCommand (HCI_VENDOR_BLE_RPA_VSC, + BTM_BLE_META_READ_IRK_LEN, + param, + btm_ble_resolving_list_vsc_op_cmpl); + } + + if (st == BTM_CMD_STARTED) + btm_ble_enq_resolving_list_pending(p_dev_rec->bd_addr, + BTM_BLE_META_READ_IRK_ENTRY); + + return st; +} + + +/******************************************************************************* +** +** Function btm_ble_suspend_resolving_list_activity +** +** Description This function suspends all resolving list activity, including +** scan, initiating, and advertising, if resolving list is being +** enabled. +** +** Parameters +** +** Returns TRUE if suspended; FALSE otherwise +** +*******************************************************************************/ +BOOLEAN btm_ble_suspend_resolving_list_activity(void) +{ + tBTM_BLE_CB *p_ble_cb = &btm_cb.ble_ctr_cb; + + /* if resolving list is not enabled, do not need to terminate any activity */ + /* if asking for stop all activity */ + /* if already suspended */ + if (p_ble_cb->suspended_rl_state != BTM_BLE_RL_IDLE) + return TRUE; + + /* direct connection active, wait until it completed */ + if (btm_ble_get_conn_st() == BLE_DIR_CONN) + { + BTM_TRACE_ERROR("resolving list can not be edited, EnQ now"); + return FALSE; + } + + p_ble_cb->suspended_rl_state = BTM_BLE_RL_IDLE; + + if (p_ble_cb->inq_var.adv_mode == BTM_BLE_ADV_ENABLE) + { + btm_ble_stop_adv(); + p_ble_cb->suspended_rl_state |= BTM_BLE_RL_ADV; + } + + if (BTM_BLE_IS_SCAN_ACTIVE(p_ble_cb->scan_activity)) + { + btm_ble_stop_scan(); + p_ble_cb->suspended_rl_state |= BTM_BLE_RL_SCAN; + } + + if (btm_ble_suspend_bg_conn()) + p_ble_cb->suspended_rl_state |= BTM_BLE_RL_INIT; + + return TRUE; +} + +/******************************************************************************* +** +** Function btm_ble_resume_resolving_list_activity +** +** Description This function resumes the resolving list activity, including +** scanning, initiating, and advertising, if any of these +** activities has been suspended earlier. +** +** Returns none +** +*******************************************************************************/ +void btm_ble_resume_resolving_list_activity(void) +{ + tBTM_BLE_CB *p_ble_cb = &btm_cb.ble_ctr_cb; + + if (p_ble_cb->suspended_rl_state & BTM_BLE_RL_ADV) + btm_ble_start_adv(); + + if (p_ble_cb->suspended_rl_state & BTM_BLE_RL_SCAN) + btm_ble_start_scan(); + + if (p_ble_cb->suspended_rl_state & BTM_BLE_RL_INIT) + btm_ble_resume_bg_conn(); + + p_ble_cb->suspended_rl_state = BTM_BLE_RL_IDLE; +} + +/******************************************************************************* +** +** Function btm_ble_vendor_enable_irk_feature +** +** Description This function is called to enable or disable the RRA +** offloading feature. +** +** Parameters enable: enable or disable the RRA offloading feature +** +** Returns BTM_SUCCESS if successful +** +*******************************************************************************/ +tBTM_STATUS btm_ble_vendor_enable_irk_feature(BOOLEAN enable) +{ + UINT8 param[20], *p; + tBTM_STATUS st = BTM_MODE_UNSUPPORTED; + + p = param; + memset(param, 0, 20); + + /* select feature based on control block settings */ + UINT8_TO_STREAM(p, BTM_BLE_META_IRK_ENABLE); + UINT8_TO_STREAM(p, enable ? 0x01 : 0x00); + + st = BTM_VendorSpecificCommand (HCI_VENDOR_BLE_RPA_VSC, BTM_BLE_IRK_ENABLE_LEN, + param, btm_ble_resolving_list_vsc_op_cmpl); + + return st; +} + +/******************************************************************************* +** +** Function btm_ble_exe_disable_resolving_list +** +** Description execute resolving list disable +** +** Returns none +** +*******************************************************************************/ +BOOLEAN btm_ble_exe_disable_resolving_list(void) +{ + if (!btm_ble_suspend_resolving_list_activity()) + return FALSE; + + if (!controller_get_interface()->supports_ble_privacy()) + btm_ble_vendor_enable_irk_feature(FALSE); + else + btsnd_hcic_ble_set_addr_resolution_enable(FALSE); + + return TRUE; +} + +/******************************************************************************* +** +** Function btm_ble_exe_enable_resolving_list +** +** Description enable LE resolve address list +** +** Returns none +** +*******************************************************************************/ +void btm_ble_exe_enable_resolving_list(void) +{ + if (!btm_ble_suspend_resolving_list_activity()) + return; + + if (!controller_get_interface()->supports_ble_privacy()) + btm_ble_vendor_enable_irk_feature(TRUE); + else + btsnd_hcic_ble_set_addr_resolution_enable(TRUE); +} + +/******************************************************************************* +** +** Function btm_ble_disable_resolving_list +** +** Description Disable LE Address resolution +** +** Returns none +** +*******************************************************************************/ +BOOLEAN btm_ble_disable_resolving_list(UINT8 rl_mask, BOOLEAN to_resume ) +{ + UINT8 rl_state = btm_cb.ble_ctr_cb.rl_state; + + /* if controller does not support RPA offloading or privacy 1.2, skip */ + if (controller_get_interface()->get_ble_resolving_list_max_size()== 0) + return FALSE; + + btm_cb.ble_ctr_cb.rl_state &= ~rl_mask; + + if (rl_state != BTM_BLE_RL_IDLE && btm_cb.ble_ctr_cb.rl_state == BTM_BLE_RL_IDLE) + { + if (btm_ble_exe_disable_resolving_list()) + { + if (to_resume) + btm_ble_resume_resolving_list_activity(); + + return TRUE; + } + else + return FALSE; + } + + return TRUE; +} + +/******************************************************************************* +** +** Function btm_ble_resolving_list_load_dev +** +** Description This function add a device which is using RPA into white list +** +** Parameters pointer to device security record +** +** Returns TRUE if device added, otherwise falase. +** +*******************************************************************************/ +BOOLEAN btm_ble_resolving_list_load_dev(tBTM_SEC_DEV_REC *p_dev_rec) +{ + BOOLEAN rt = FALSE; + UINT8 rl_mask = btm_cb.ble_ctr_cb.rl_state; + + BTM_TRACE_DEBUG("%s btm_cb.ble_ctr_cb.privacy_mode = %d", __func__, + btm_cb.ble_ctr_cb.privacy_mode); + + /* if controller does not support RPA offloading or privacy 1.2, skip */ + if (controller_get_interface()->get_ble_resolving_list_max_size() == 0) + return FALSE; + + BTM_TRACE_DEBUG("%s btm_cb.ble_ctr_cb.privacy_mode = %d", + __func__, btm_cb.ble_ctr_cb.privacy_mode); + + /* only add RPA enabled device into resolving list */ + if (p_dev_rec != NULL && /* RPA is being used and PID is known */ + (p_dev_rec->sec_flags & BTM_SEC_IN_USE) != 0 && + ((p_dev_rec->ble.key_type & BTM_LE_KEY_PID) != 0 || + (p_dev_rec->ble.key_type & BTM_LE_KEY_LID) != 0)) + { + if (!(p_dev_rec->ble.in_controller_list & BTM_RESOLVING_LIST_BIT) && + btm_ble_brcm_find_resolving_pending_entry(p_dev_rec->bd_addr, + BTM_BLE_META_ADD_IRK_ENTRY) == FALSE) + { + if (btm_cb.ble_ctr_cb.resolving_list_avail_size > 0) + { + if (rl_mask) + { + if (!btm_ble_disable_resolving_list (rl_mask, FALSE)) + return FALSE; + } + + btm_ble_update_resolving_list(p_dev_rec->bd_addr, TRUE); + if (controller_get_interface()->supports_ble_privacy()) + { + BD_ADDR dummy_bda = {0}; + UINT8 *peer_irk = p_dev_rec->ble.keys.irk; + UINT8 *local_irk = btm_cb.devcb.id_keys.irk; + + if (memcmp(p_dev_rec->ble.static_addr, dummy_bda, BD_ADDR_LEN) == 0) + { + memcpy(p_dev_rec->ble.static_addr, p_dev_rec->bd_addr, BD_ADDR_LEN); + p_dev_rec->ble.static_addr_type = p_dev_rec->ble.ble_addr_type; + } + + BTM_TRACE_DEBUG("%s:adding device to controller resolving list", __func__); + // use identical IRK for now + rt = btsnd_hcic_ble_add_device_resolving_list(p_dev_rec->ble.static_addr_type, + p_dev_rec->ble.static_addr, peer_irk, local_irk); + } + else + { + UINT8 param[40] = {0}; + UINT8 *p = param; + + UINT8_TO_STREAM(p, BTM_BLE_META_ADD_IRK_ENTRY); + ARRAY_TO_STREAM(p, p_dev_rec->ble.keys.irk, BT_OCTET16_LEN); + UINT8_TO_STREAM(p, p_dev_rec->ble.static_addr_type); + BDADDR_TO_STREAM(p,p_dev_rec->ble.static_addr); + + if (BTM_VendorSpecificCommand (HCI_VENDOR_BLE_RPA_VSC, + BTM_BLE_META_ADD_IRK_LEN, + param, + btm_ble_resolving_list_vsc_op_cmpl) + == BTM_CMD_STARTED) + rt = TRUE; + } + + if (rt) + btm_ble_enq_resolving_list_pending(p_dev_rec->bd_addr, + BTM_BLE_META_ADD_IRK_ENTRY); + + /* if resolving list has been turned on, re-enable it */ + if (rl_mask) + btm_ble_enable_resolving_list(rl_mask); + else + btm_ble_enable_resolving_list(BTM_BLE_RL_INIT); + } + } + else + { + BTM_TRACE_ERROR("Device already in Resolving list"); + rt = TRUE; + } + } + else + { + BTM_TRACE_DEBUG("Device not a RPA enabled device"); + } + return rt; +} + +/******************************************************************************* +** +** Function btm_ble_resolving_list_remove_dev +** +** Description This function removes the device from resolving list +** +** Parameters +** +** Returns status +** +*******************************************************************************/ +void btm_ble_resolving_list_remove_dev(tBTM_SEC_DEV_REC *p_dev_rec) +{ + UINT8 rl_mask = btm_cb.ble_ctr_cb.rl_state; + + BTM_TRACE_EVENT ("%s", __func__); + if (rl_mask) + { + if (!btm_ble_disable_resolving_list (rl_mask, FALSE)) + return; + } + + if ((p_dev_rec->ble.in_controller_list & BTM_RESOLVING_LIST_BIT) && + btm_ble_brcm_find_resolving_pending_entry(p_dev_rec->bd_addr, + BTM_BLE_META_REMOVE_IRK_ENTRY) == FALSE) + { + btm_ble_update_resolving_list( p_dev_rec->bd_addr, FALSE); + btm_ble_remove_resolving_list_entry(p_dev_rec); + } + else + { + BTM_TRACE_DEBUG("Device not in resolving list"); + } + + /* if resolving list has been turned on, re-enable it */ + if (rl_mask) + btm_ble_enable_resolving_list(rl_mask); +} + +/******************************************************************************* +** +** Function btm_ble_enable_resolving_list +** +** Description enable LE resolve address list +** +** Returns none +** +*******************************************************************************/ +void btm_ble_enable_resolving_list(UINT8 rl_mask) +{ + UINT8 rl_state = btm_cb.ble_ctr_cb.rl_state; + + btm_cb.ble_ctr_cb.rl_state |= rl_mask; + if (rl_state == BTM_BLE_RL_IDLE && + btm_cb.ble_ctr_cb.rl_state != BTM_BLE_RL_IDLE && + controller_get_interface()->get_ble_resolving_list_max_size() != 0) + { + btm_ble_exe_enable_resolving_list(); + btm_ble_resume_resolving_list_activity(); + } +} + +/******************************************************************************* +** +** Function btm_ble_resolving_list_empty +** +** Description check to see if resoving list is empty or not +** +** Returns TRUE: empty; FALSE non-empty +** +*******************************************************************************/ +BOOLEAN btm_ble_resolving_list_empty(void) +{ + return (controller_get_interface()->get_ble_resolving_list_max_size() == + btm_cb.ble_ctr_cb.resolving_list_avail_size); +} + +/******************************************************************************* +** +** Function btm_ble_enable_resolving_list_for_platform +** +** Description enable/disable resolving list feature depending on if any +** resolving list is empty and whitelist is involoved in the +** operation. +** +** Returns none +** +*******************************************************************************/ +void btm_ble_enable_resolving_list_for_platform (UINT8 rl_mask) +{ + /* if controller does not support, skip */ + if (controller_get_interface()->get_ble_resolving_list_max_size() == 0) + return; + + if (btm_cb.ble_ctr_cb.wl_state == BTM_BLE_WL_IDLE) + { + if (controller_get_interface()->get_ble_resolving_list_max_size() > + btm_cb.ble_ctr_cb.resolving_list_avail_size) + btm_ble_enable_resolving_list(rl_mask); + else + btm_ble_disable_resolving_list(rl_mask, TRUE); + return; + } + + tBTM_SEC_DEV_REC *p_dev = &btm_cb.sec_dev_rec[0]; + for (UINT8 i = 0; i < BTM_SEC_MAX_DEVICE_RECORDS; i ++, p_dev ++) + { + if ((p_dev->ble.in_controller_list & BTM_RESOLVING_LIST_BIT) && + (p_dev->ble.in_controller_list & BTM_WHITE_LIST_BIT)) + { + btm_ble_enable_resolving_list(rl_mask); + return; + } + } + btm_ble_disable_resolving_list(rl_mask, TRUE); +} + +/******************************************************************************* +** +** Function btm_ble_resolving_list_init +** +** Description Initialize resolving list in host stack +** +** Parameters Max resolving list size +** +** Returns void +** +*******************************************************************************/ +void btm_ble_resolving_list_init(UINT8 max_irk_list_sz) +{ + tBTM_BLE_RESOLVE_Q *p_q = &btm_cb.ble_ctr_cb.resolving_list_pend_q; + UINT8 irk_mask_size = (max_irk_list_sz % 8) ? + (max_irk_list_sz/8 + 1) : (max_irk_list_sz/8); + + if (max_irk_list_sz > 0) + { + p_q->resolve_q_random_pseudo = (BD_ADDR *)GKI_getbuf(sizeof(BD_ADDR) * max_irk_list_sz); + p_q->resolve_q_action = (UINT8 *)GKI_getbuf(max_irk_list_sz); + + /* RPA offloading feature */ + if (btm_cb.ble_ctr_cb.irk_list_mask == NULL) + btm_cb.ble_ctr_cb.irk_list_mask = (UINT8 *)GKI_getbuf(irk_mask_size); + + BTM_TRACE_DEBUG ("%s max_irk_list_sz = %d", __func__, max_irk_list_sz); + } + + controller_get_interface()->set_ble_resolving_list_max_size(max_irk_list_sz); + btm_ble_clear_resolving_list(); + btm_cb.ble_ctr_cb.resolving_list_avail_size = max_irk_list_sz; +} + +/******************************************************************************* +** +** Function btm_ble_resolving_list_cleanup +** +** Description Cleanup resolving list dynamic memory +** +** Parameters +** +** Returns void +** +*******************************************************************************/ +void btm_ble_resolving_list_cleanup(void) +{ + tBTM_BLE_RESOLVE_Q *p_q = &btm_cb.ble_ctr_cb.resolving_list_pend_q; + + if (p_q->resolve_q_random_pseudo) + GKI_freebuf(p_q->resolve_q_random_pseudo); + + if (p_q->resolve_q_action) + GKI_freebuf(p_q->resolve_q_action); + + controller_get_interface()->set_ble_resolving_list_max_size(0); + if (btm_cb.ble_ctr_cb.irk_list_mask) + GKI_freebuf(btm_cb.ble_ctr_cb.irk_list_mask); + + btm_cb.ble_ctr_cb.irk_list_mask = NULL; +} +#endif diff --git a/components/bt/bluedroid/stack/btm/btm_dev.c b/components/bt/bluedroid/stack/btm/btm_dev.c new file mode 100755 index 0000000000..f7e27ee9d5 --- /dev/null +++ b/components/bt/bluedroid/stack/btm/btm_dev.c @@ -0,0 +1,642 @@ +/****************************************************************************** + * + * Copyright (C) 1999-2012 Broadcom Corporation + * + * 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 functions for the Bluetooth Device Manager + * + ******************************************************************************/ + +#include +#include +//#include +#include + +#include "bt_types.h" +#include "controller.h" +#include "gki.h" +#include "hcimsgs.h" +#include "btu.h" +#include "btm_api.h" +#include "btm_int.h" +#include "hcidefs.h" +#include "l2c_api.h" + +static tBTM_SEC_DEV_REC *btm_find_oldest_dev (void); + +/******************************************************************************* +** +** Function BTM_SecAddDevice +** +** Description Add/modify device. This function will be normally called +** during host startup to restore all required information +** stored in the NVRAM. +** +** Parameters: bd_addr - BD address of the peer +** dev_class - Device Class +** bd_name - Name of the peer device. NULL if unknown. +** features - Remote device's features (up to 3 pages). NULL if not known +** trusted_mask - Bitwise OR of services that do not +** require authorization. (array of UINT32) +** link_key - Connection link key. NULL if unknown. +** +** Returns TRUE if added OK, else FALSE +** +*******************************************************************************/ +BOOLEAN BTM_SecAddDevice (BD_ADDR bd_addr, DEV_CLASS dev_class, BD_NAME bd_name, + UINT8 *features, UINT32 trusted_mask[], + LINK_KEY link_key, UINT8 key_type, tBTM_IO_CAP io_cap, + UINT8 pin_length) +{ + tBTM_SEC_DEV_REC *p_dev_rec; + int i, j; + BOOLEAN found = FALSE; + + BTM_TRACE_API("%s, link key type:%x", __FUNCTION__,key_type); + p_dev_rec = btm_find_dev (bd_addr); + if (!p_dev_rec) + { + /* There is no device record, allocate one. + * If we can not find an empty spot for this one, let it fail. */ + for (i = 0; i < BTM_SEC_MAX_DEVICE_RECORDS; i++) + { + if (!(btm_cb.sec_dev_rec[i].sec_flags & BTM_SEC_IN_USE)) + { + p_dev_rec = &btm_cb.sec_dev_rec[i]; + + /* Mark this record as in use and initialize */ + memset (p_dev_rec, 0, sizeof (tBTM_SEC_DEV_REC)); + p_dev_rec->sec_flags = BTM_SEC_IN_USE; + memcpy (p_dev_rec->bd_addr, bd_addr, BD_ADDR_LEN); + p_dev_rec->hci_handle = BTM_GetHCIConnHandle (bd_addr, BT_TRANSPORT_BR_EDR); + +#if BLE_INCLUDED == TRUE + /* use default value for background connection params */ + /* update conn params, use default value for background connection params */ + memset(&p_dev_rec->conn_params, 0xff, sizeof(tBTM_LE_CONN_PRAMS)); +#endif + break; + } + } + + if (!p_dev_rec) + return(FALSE); + } + + p_dev_rec->bond_type = BOND_TYPE_UNKNOWN; /* Default value */ + p_dev_rec->timestamp = btm_cb.dev_rec_count++; + + if (dev_class) + memcpy (p_dev_rec->dev_class, dev_class, DEV_CLASS_LEN); + + memset(p_dev_rec->sec_bd_name, 0, sizeof(tBTM_BD_NAME)); + + if (bd_name && bd_name[0]) + { + p_dev_rec->sec_flags |= BTM_SEC_NAME_KNOWN; + BCM_STRNCPY_S ((char *)p_dev_rec->sec_bd_name, sizeof (p_dev_rec->sec_bd_name), + (char *)bd_name, BTM_MAX_REM_BD_NAME_LEN); + } + + p_dev_rec->num_read_pages = 0; + if (features) + { + memcpy (p_dev_rec->features, features, sizeof (p_dev_rec->features)); + for (i = HCI_EXT_FEATURES_PAGE_MAX; i >= 0; i--) + { + for (j = 0; j < HCI_FEATURE_BYTES_PER_PAGE; j++) + { + if (p_dev_rec->features[i][j] != 0) + { + found = TRUE; + break; + } + } + if (found) + { + p_dev_rec->num_read_pages = i + 1; + break; + } + } + } + else + memset (p_dev_rec->features, 0, sizeof (p_dev_rec->features)); + + BTM_SEC_COPY_TRUSTED_DEVICE(trusted_mask, p_dev_rec->trusted_mask); + + if (link_key) + { + BTM_TRACE_EVENT ("BTM_SecAddDevice() BDA: %02x:%02x:%02x:%02x:%02x:%02x", + bd_addr[0], bd_addr[1], bd_addr[2], + bd_addr[3], bd_addr[4], bd_addr[5]); + p_dev_rec->sec_flags |= BTM_SEC_LINK_KEY_KNOWN; + memcpy (p_dev_rec->link_key, link_key, LINK_KEY_LEN); + p_dev_rec->link_key_type = key_type; + p_dev_rec->pin_code_length = pin_length; + + if (pin_length >= 16 || + key_type == BTM_LKEY_TYPE_AUTH_COMB || + key_type == BTM_LKEY_TYPE_AUTH_COMB_P_256) { + // Set the fiag if the link key was made by using either a 16 digit + // pin or MITM. + p_dev_rec->sec_flags |= BTM_SEC_16_DIGIT_PIN_AUTHED; + } + } + +#if defined(BTIF_MIXED_MODE_INCLUDED) && (BTIF_MIXED_MODE_INCLUDED == TRUE) + if (key_type < BTM_MAX_PRE_SM4_LKEY_TYPE) + p_dev_rec->sm4 = BTM_SM4_KNOWN; + else + p_dev_rec->sm4 = BTM_SM4_TRUE; +#endif + + p_dev_rec->rmt_io_caps = io_cap; + p_dev_rec->device_type |= BT_DEVICE_TYPE_BREDR; + + return(TRUE); +} + + +/******************************************************************************* +** +** Function BTM_SecDeleteDevice +** +** Description Free resources associated with the device. +** +** Parameters: bd_addr - BD address of the peer +** +** Returns TRUE if removed OK, FALSE if not found or ACL link is active +** +*******************************************************************************/ +BOOLEAN BTM_SecDeleteDevice (BD_ADDR bd_addr) +{ + tBTM_SEC_DEV_REC *p_dev_rec; + + if (BTM_IsAclConnectionUp(bd_addr, BT_TRANSPORT_LE) || + BTM_IsAclConnectionUp(bd_addr, BT_TRANSPORT_BR_EDR)) + { + BTM_TRACE_WARNING("%s FAILED: Cannot Delete when connection is active", __func__); + return FALSE; + } + + if ((p_dev_rec = btm_find_dev(bd_addr)) != NULL) + { + btm_sec_free_dev(p_dev_rec); + /* Tell controller to get rid of the link key, if it has one stored */ + BTM_DeleteStoredLinkKey (p_dev_rec->bd_addr, NULL); + } + + return TRUE; +} + +/******************************************************************************* +** +** Function BTM_SecReadDevName +** +** Description Looks for the device name in the security database for the +** specified BD address. +** +** Returns Pointer to the name or NULL +** +*******************************************************************************/ +char *BTM_SecReadDevName (BD_ADDR bd_addr) +{ + char *p_name = NULL; + tBTM_SEC_DEV_REC *p_srec; + + if ((p_srec = btm_find_dev(bd_addr)) != NULL) + p_name = (char *)p_srec->sec_bd_name; + + return(p_name); +} + +/******************************************************************************* +** +** Function btm_sec_alloc_dev +** +** Description Look for the record in the device database for the record +** with specified address +** +** Returns Pointer to the record or NULL +** +*******************************************************************************/ +tBTM_SEC_DEV_REC *btm_sec_alloc_dev (BD_ADDR bd_addr) +{ + tBTM_SEC_DEV_REC *p_dev_rec = NULL; + tBTM_INQ_INFO *p_inq_info; + int i; + DEV_CLASS old_cod; + int i_new_entry = BTM_SEC_MAX_DEVICE_RECORDS; + int i_old_entry = BTM_SEC_MAX_DEVICE_RECORDS; + BTM_TRACE_EVENT ("btm_sec_alloc_dev"); + + for (i = 0; i < BTM_SEC_MAX_DEVICE_RECORDS; i++) + { + /* look for old entry where device details are present */ + if (!(btm_cb.sec_dev_rec[i].sec_flags & BTM_SEC_IN_USE) && + (!memcmp (btm_cb.sec_dev_rec[i].bd_addr, bd_addr, BD_ADDR_LEN))) + { + i_old_entry = i; + BTM_TRACE_EVENT ("btm_sec_alloc_dev old device found"); + break; + } + } + + for (i = 0; i < BTM_SEC_MAX_DEVICE_RECORDS; i++) + { + if (!(btm_cb.sec_dev_rec[i].sec_flags & BTM_SEC_IN_USE)) + { + i_new_entry = i; + break; + } + } + + if (i_new_entry == BTM_SEC_MAX_DEVICE_RECORDS) { + p_dev_rec = btm_find_oldest_dev(); + } + else { + /* if the old device entry not present go with + new entry */ + if(i_old_entry == BTM_SEC_MAX_DEVICE_RECORDS) { + p_dev_rec = &btm_cb.sec_dev_rec[i_new_entry]; + } + else { + p_dev_rec = &btm_cb.sec_dev_rec[i_old_entry]; + memcpy (old_cod, p_dev_rec->dev_class, DEV_CLASS_LEN); + } + } + memset (p_dev_rec, 0, sizeof (tBTM_SEC_DEV_REC)); + + /* Retain the old COD for device */ + if(i_old_entry != BTM_SEC_MAX_DEVICE_RECORDS) { + BTM_TRACE_EVENT ("btm_sec_alloc_dev restoring cod "); + memcpy (p_dev_rec->dev_class, old_cod, DEV_CLASS_LEN); + + } + + p_dev_rec->bond_type = BOND_TYPE_UNKNOWN; /* Default value */ + p_dev_rec->sec_flags = BTM_SEC_IN_USE; + + /* Check with the BT manager if details about remote device are known */ + /* outgoing connection */ + if ((p_inq_info = BTM_InqDbRead(bd_addr)) != NULL) + { + memcpy (p_dev_rec->dev_class, p_inq_info->results.dev_class, DEV_CLASS_LEN); + +#if BLE_INCLUDED == TRUE + p_dev_rec->device_type = p_inq_info->results.device_type; + p_dev_rec->ble.ble_addr_type = p_inq_info->results.ble_addr_type; + + /* update conn params, use default value for background connection params */ + memset(&p_dev_rec->conn_params, 0xff, sizeof(tBTM_LE_CONN_PRAMS)); +#endif + } + else + { +#if BLE_INCLUDED == TRUE + /* update conn params, use default value for background connection params */ + memset(&p_dev_rec->conn_params, 0xff, sizeof(tBTM_LE_CONN_PRAMS)); +#endif + + if (!memcmp (bd_addr, btm_cb.connecting_bda, BD_ADDR_LEN)) + memcpy (p_dev_rec->dev_class, btm_cb.connecting_dc, DEV_CLASS_LEN); + } + + memcpy (p_dev_rec->bd_addr, bd_addr, BD_ADDR_LEN); + +#if BLE_INCLUDED == TRUE + p_dev_rec->ble_hci_handle = BTM_GetHCIConnHandle (bd_addr, BT_TRANSPORT_LE); +#endif + p_dev_rec->hci_handle = BTM_GetHCIConnHandle (bd_addr, BT_TRANSPORT_BR_EDR); + p_dev_rec->timestamp = btm_cb.dev_rec_count++; + + return(p_dev_rec); +} + + +/******************************************************************************* +** +** Function btm_sec_free_dev +** +** Description Mark device record as not used +** +*******************************************************************************/ +void btm_sec_free_dev (tBTM_SEC_DEV_REC *p_dev_rec) +{ + p_dev_rec->bond_type = BOND_TYPE_UNKNOWN; + p_dev_rec->sec_flags = 0; + +#if BLE_INCLUDED == TRUE + /* Clear out any saved BLE keys */ + btm_sec_clear_ble_keys (p_dev_rec); +#endif + + +} + +/******************************************************************************* +** +** Function btm_dev_support_switch +** +** Description This function is called by the L2CAP to check if remote +** device supports role switch +** +** Parameters: bd_addr - Address of the peer device +** +** Returns TRUE if device is known and role switch is supported +** +*******************************************************************************/ +BOOLEAN btm_dev_support_switch (BD_ADDR bd_addr) +{ + tBTM_SEC_DEV_REC *p_dev_rec; + UINT8 xx; + BOOLEAN feature_empty = TRUE; + +#if BTM_SCO_INCLUDED == TRUE + /* Role switch is not allowed if a SCO is up */ + if (btm_is_sco_active_by_bdaddr(bd_addr)) + return(FALSE); +#endif + p_dev_rec = btm_find_dev (bd_addr); + if (p_dev_rec && controller_get_interface()->supports_master_slave_role_switch()) + { + if (HCI_SWITCH_SUPPORTED(p_dev_rec->features[HCI_EXT_FEATURES_PAGE_0])) + { + BTM_TRACE_DEBUG("btm_dev_support_switch return TRUE (feature found)"); + return (TRUE); + } + + /* If the feature field is all zero, we never received them */ + for (xx = 0 ; xx < BD_FEATURES_LEN ; xx++) + { + if (p_dev_rec->features[HCI_EXT_FEATURES_PAGE_0][xx] != 0x00) + { + feature_empty = FALSE; /* at least one is != 0 */ + break; + } + } + + /* If we don't know peer's capabilities, assume it supports Role-switch */ + if (feature_empty) + { + BTM_TRACE_DEBUG("btm_dev_support_switch return TRUE (feature empty)"); + return (TRUE); + } + } + + BTM_TRACE_DEBUG("btm_dev_support_switch return FALSE"); + return(FALSE); +} + +/******************************************************************************* +** +** Function btm_find_dev_by_handle +** +** Description Look for the record in the device database for the record +** with specified handle +** +** Returns Pointer to the record or NULL +** +*******************************************************************************/ +tBTM_SEC_DEV_REC *btm_find_dev_by_handle (UINT16 handle) +{ + tBTM_SEC_DEV_REC *p_dev_rec = &btm_cb.sec_dev_rec[0]; + int i; + + for (i = 0; i < BTM_SEC_MAX_DEVICE_RECORDS; i++, p_dev_rec++) + { + if ((p_dev_rec->sec_flags & BTM_SEC_IN_USE) + && ((p_dev_rec->hci_handle == handle) +#if BLE_INCLUDED == TRUE + ||(p_dev_rec->ble_hci_handle == handle) +#endif + )) + return(p_dev_rec); + } + return(NULL); +} + +/******************************************************************************* +** +** Function btm_find_dev +** +** Description Look for the record in the device database for the record +** with specified BD address +** +** Returns Pointer to the record or NULL +** +*******************************************************************************/ +tBTM_SEC_DEV_REC *btm_find_dev(BD_ADDR bd_addr) +{ + tBTM_SEC_DEV_REC *p_dev_rec = &btm_cb.sec_dev_rec[0]; + + if (bd_addr) + { + for (uint8_t i = 0; i < BTM_SEC_MAX_DEVICE_RECORDS; i++, p_dev_rec++) + { + if (p_dev_rec->sec_flags & BTM_SEC_IN_USE) + { + if (!memcmp (p_dev_rec->bd_addr, bd_addr, BD_ADDR_LEN)) + return(p_dev_rec); + +#if BLE_INCLUDED == TRUE + // If a LE random address is looking for device record + if (!memcmp(p_dev_rec->ble.pseudo_addr, bd_addr, BD_ADDR_LEN)) + return (p_dev_rec); + + if (btm_ble_addr_resolvable(bd_addr, p_dev_rec)) + return(p_dev_rec); +#endif + } + } + } + return(NULL); +} + +/******************************************************************************* +** +** Function btm_consolidate_dev +** +** Description combine security records if identified as same peer +** +** Returns none +** +*******************************************************************************/ +void btm_consolidate_dev(tBTM_SEC_DEV_REC *p_target_rec) +{ +#if BLE_INCLUDED == TRUE + tBTM_SEC_DEV_REC *p_dev_rec = &btm_cb.sec_dev_rec[0]; + tBTM_SEC_DEV_REC temp_rec = *p_target_rec; + BD_ADDR dummy_bda = {0}; + + BTM_TRACE_DEBUG("%s", __func__); + + for (uint8_t i = 0; i < BTM_SEC_MAX_DEVICE_RECORDS; i++, p_dev_rec++) + { + if (p_target_rec!= p_dev_rec && p_dev_rec->sec_flags & BTM_SEC_IN_USE) + { + if (!memcmp (p_dev_rec->bd_addr, p_target_rec->bd_addr, BD_ADDR_LEN)) + { + memcpy(p_target_rec, p_dev_rec, sizeof(tBTM_SEC_DEV_REC)); + p_target_rec->ble = temp_rec.ble; + p_target_rec->ble_hci_handle = temp_rec.ble_hci_handle; + p_target_rec->enc_key_size = temp_rec.enc_key_size; + p_target_rec->conn_params = temp_rec.conn_params; + p_target_rec->device_type |= temp_rec.device_type; + p_target_rec->sec_flags |= temp_rec.sec_flags; + + p_target_rec->new_encryption_key_is_p256 = temp_rec.new_encryption_key_is_p256; + p_target_rec->no_smp_on_br = temp_rec.no_smp_on_br; + p_target_rec->bond_type = temp_rec.bond_type; + /* mark the combined record as unused */ + p_dev_rec->sec_flags &= ~BTM_SEC_IN_USE; + p_dev_rec->bond_type = BOND_TYPE_UNKNOWN; + break; + } + + /* an RPA device entry is a duplicate of the target record */ + if (btm_ble_addr_resolvable(p_dev_rec->bd_addr, p_target_rec)) + { + if (memcmp(p_target_rec->ble.pseudo_addr, p_dev_rec->bd_addr, BD_ADDR_LEN) == 0) + { + p_target_rec->ble.ble_addr_type = p_dev_rec->ble.ble_addr_type; + p_target_rec->device_type |= p_dev_rec->device_type; + p_dev_rec->sec_flags &= ~BTM_SEC_IN_USE; + p_dev_rec->bond_type = BOND_TYPE_UNKNOWN; + } + break; + } + } + } +#endif +} + +/******************************************************************************* +** +** Function btm_find_or_alloc_dev +** +** Description Look for the record in the device database for the record +** with specified BD address +** +** Returns Pointer to the record or NULL +** +*******************************************************************************/ +tBTM_SEC_DEV_REC *btm_find_or_alloc_dev (BD_ADDR bd_addr) +{ + tBTM_SEC_DEV_REC *p_dev_rec; + BTM_TRACE_EVENT ("btm_find_or_alloc_dev"); + if ((p_dev_rec = btm_find_dev (bd_addr)) == NULL) + { + + /* Allocate a new device record or reuse the oldest one */ + p_dev_rec = btm_sec_alloc_dev (bd_addr); + } + return(p_dev_rec); +} + +/******************************************************************************* +** +** Function btm_find_oldest_dev +** +** Description Locates the oldest device in use. It first looks for +** the oldest non-paired device. If all devices are paired it +** deletes the oldest paired device. +** +** Returns Pointer to the record or NULL +** +*******************************************************************************/ +tBTM_SEC_DEV_REC *btm_find_oldest_dev (void) +{ + tBTM_SEC_DEV_REC *p_dev_rec = &btm_cb.sec_dev_rec[0]; + tBTM_SEC_DEV_REC *p_oldest = p_dev_rec; + UINT32 ot = 0xFFFFFFFF; + int i; + + /* First look for the non-paired devices for the oldest entry */ + for (i = 0; i < BTM_SEC_MAX_DEVICE_RECORDS; i++, p_dev_rec++) + { + if (((p_dev_rec->sec_flags & BTM_SEC_IN_USE) == 0) + || ((p_dev_rec->sec_flags & (BTM_SEC_LINK_KEY_KNOWN |BTM_SEC_LE_LINK_KEY_KNOWN)) != 0)) + continue; /* Device is paired so skip it */ + + if (p_dev_rec->timestamp < ot) + { + p_oldest = p_dev_rec; + ot = p_dev_rec->timestamp; + } + } + + if (ot != 0xFFFFFFFF) + return(p_oldest); + + /* All devices are paired; find the oldest */ + p_dev_rec = &btm_cb.sec_dev_rec[0]; + for (i = 0; i < BTM_SEC_MAX_DEVICE_RECORDS; i++, p_dev_rec++) + { + if ((p_dev_rec->sec_flags & BTM_SEC_IN_USE) == 0) + continue; + + if (p_dev_rec->timestamp < ot) + { + p_oldest = p_dev_rec; + ot = p_dev_rec->timestamp; + } + } + return(p_oldest); +} + +/******************************************************************************* +** +** Function btm_get_bond_type_dev +** +** Description Get the bond type for a device in the device database +** with specified BD address +** +** Returns The device bond type if known, otherwise BOND_TYPE_UNKNOWN +** +*******************************************************************************/ +tBTM_BOND_TYPE btm_get_bond_type_dev(BD_ADDR bd_addr) +{ + tBTM_SEC_DEV_REC *p_dev_rec = btm_find_dev(bd_addr); + + if (p_dev_rec == NULL) + return BOND_TYPE_UNKNOWN; + + return p_dev_rec->bond_type; +} + +/******************************************************************************* +** +** Function btm_set_bond_type_dev +** +** Description Set the bond type for a device in the device database +** with specified BD address +** +** Returns TRUE on success, otherwise FALSE +** +*******************************************************************************/ +BOOLEAN btm_set_bond_type_dev(BD_ADDR bd_addr, tBTM_BOND_TYPE bond_type) +{ + tBTM_SEC_DEV_REC *p_dev_rec = btm_find_dev(bd_addr); + + if (p_dev_rec == NULL) + return FALSE; + + p_dev_rec->bond_type = bond_type; + return TRUE; +} diff --git a/components/bt/bluedroid/stack/btm/btm_devctl.c b/components/bt/bluedroid/stack/btm/btm_devctl.c new file mode 100755 index 0000000000..a4aa638f4e --- /dev/null +++ b/components/bt/bluedroid/stack/btm/btm_devctl.c @@ -0,0 +1,982 @@ +/****************************************************************************** + * + * Copyright (C) 1999-2012 Broadcom Corporation + * + * 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 functions that handle BTM interface functions for the + * Bluetooth device including Rest, HCI buffer size and others + * + ******************************************************************************/ + +#include +#include +//#include +#include +#include "bt_trace.h" +#include "bt_types.h" +//#include "bt_utils.h" +#include "btm_int.h" +#include "btu.h" +#include "controller.h" +#include "hci_layer.h" +#include "hcimsgs.h" +#include "l2c_int.h" +//#include "btcore/include/module.h" +//#include "osi/include/thread.h" + +#if BLE_INCLUDED == TRUE +#include "gatt_int.h" +#endif /* BLE_INCLUDED */ + +//extern thread_t *bt_workqueue_thread; + +/********************************************************************************/ +/* L O C A L D A T A D E F I N I T I O N S */ +/********************************************************************************/ + +#ifndef BTM_DEV_RESET_TIMEOUT +#define BTM_DEV_RESET_TIMEOUT 4 +#endif + +#define BTM_DEV_REPLY_TIMEOUT 2 /* 1 second expiration time is not good. Timer may start between 0 and 1 second. */ + /* if it starts at the very end of the 0 second, timer will expire really easily. */ + +#define BTM_INFO_TIMEOUT 5 /* 5 seconds for info response */ + +/********************************************************************************/ +/* L O C A L F U N C T I O N P R O T O T Y P E S */ +/********************************************************************************/ + +static void btm_decode_ext_features_page (UINT8 page_number, const BD_FEATURES p_features); + +/******************************************************************************* +** +** Function btm_dev_init +** +** Description This function is on the BTM startup +** +** Returns void +** +*******************************************************************************/ +void btm_dev_init (void) +{ +#if 0 /* cleared in btm_init; put back in if called from anywhere else! */ + memset (&btm_cb.devcb, 0, sizeof (tBTM_DEVCB)); +#endif + + /* Initialize nonzero defaults */ +#if (BTM_MAX_LOC_BD_NAME_LEN > 0) + memset(btm_cb.cfg.bd_name, 0, sizeof(tBTM_LOC_BD_NAME)); +#endif + + btm_cb.devcb.reset_timer.param = (TIMER_PARAM_TYPE)TT_DEV_RESET; + btm_cb.devcb.rln_timer.param = (TIMER_PARAM_TYPE)TT_DEV_RLN; + + btm_cb.btm_acl_pkt_types_supported = BTM_ACL_PKT_TYPES_MASK_DH1 + BTM_ACL_PKT_TYPES_MASK_DM1 + + BTM_ACL_PKT_TYPES_MASK_DH3 + BTM_ACL_PKT_TYPES_MASK_DM3 + + BTM_ACL_PKT_TYPES_MASK_DH5 + BTM_ACL_PKT_TYPES_MASK_DM5; + + btm_cb.btm_sco_pkt_types_supported = BTM_SCO_PKT_TYPES_MASK_HV1 + + BTM_SCO_PKT_TYPES_MASK_HV2 + + BTM_SCO_PKT_TYPES_MASK_HV3 + + BTM_SCO_PKT_TYPES_MASK_EV3 + + BTM_SCO_PKT_TYPES_MASK_EV4 + + BTM_SCO_PKT_TYPES_MASK_EV5; +} + + +/******************************************************************************* +** +** Function btm_db_reset +** +** Description This function is called by BTM_DeviceReset and clears out any +** pending callbacks for inquiries, discoveries, other pending +** functions that may be in progress. +** +** Returns void +** +*******************************************************************************/ +static void btm_db_reset (void) +{ + tBTM_CMPL_CB *p_cb; + tBTM_STATUS status = BTM_DEV_RESET; + + btm_inq_db_reset(); + + if (btm_cb.devcb.p_rln_cmpl_cb) + { + p_cb = btm_cb.devcb.p_rln_cmpl_cb; + btm_cb.devcb.p_rln_cmpl_cb = NULL; + + if (p_cb) + (*p_cb)((void *) NULL); + } + + if (btm_cb.devcb.p_rssi_cmpl_cb) + { + p_cb = btm_cb.devcb.p_rssi_cmpl_cb; + btm_cb.devcb.p_rssi_cmpl_cb = NULL; + + if (p_cb) + (*p_cb)((tBTM_RSSI_RESULTS *) &status); + } +} + +static void reset_complete(void) { + const controller_t *controller = controller_get_interface(); + + /* Tell L2CAP that all connections are gone */ + l2cu_device_reset (); + + /* Clear current security state */ + for (int devinx = 0; devinx < BTM_SEC_MAX_DEVICE_RECORDS; devinx++) { + btm_cb.sec_dev_rec[devinx].sec_state = BTM_SEC_STATE_IDLE; + } + + /* After the reset controller should restore all parameters to defaults. */ + btm_cb.btm_inq_vars.inq_counter = 1; + btm_cb.btm_inq_vars.inq_scan_window = HCI_DEF_INQUIRYSCAN_WINDOW; + btm_cb.btm_inq_vars.inq_scan_period = HCI_DEF_INQUIRYSCAN_INTERVAL; + btm_cb.btm_inq_vars.inq_scan_type = HCI_DEF_SCAN_TYPE; + + btm_cb.btm_inq_vars.page_scan_window = HCI_DEF_PAGESCAN_WINDOW; + btm_cb.btm_inq_vars.page_scan_period = HCI_DEF_PAGESCAN_INTERVAL; + btm_cb.btm_inq_vars.page_scan_type = HCI_DEF_SCAN_TYPE; + +#if (BLE_INCLUDED == TRUE) + btm_cb.ble_ctr_cb.conn_state = BLE_CONN_IDLE; + btm_cb.ble_ctr_cb.bg_conn_type = BTM_BLE_CONN_NONE; + btm_cb.ble_ctr_cb.p_select_cback = NULL; + gatt_reset_bgdev_list(); + btm_ble_multi_adv_init(); +#endif + + btm_pm_reset(); + + l2c_link_processs_num_bufs(controller->get_acl_buffer_count_classic()); +#if (BLE_INCLUDED == TRUE) + +#if (defined BLE_PRIVACY_SPT && BLE_PRIVACY_SPT == TRUE) + /* Set up the BLE privacy settings */ + if (controller->supports_ble() && controller->supports_ble_privacy() && + controller->get_ble_resolving_list_max_size() > 0) { + btm_ble_resolving_list_init(controller->get_ble_resolving_list_max_size()); + /* set the default random private address timeout */ + btsnd_hcic_ble_set_rand_priv_addr_timeout(BTM_BLE_PRIVATE_ADDR_INT); + } +#endif + + if (controller->supports_ble()) { + btm_ble_white_list_init(controller->get_ble_white_list_size()); + l2c_link_processs_ble_num_bufs(controller->get_acl_buffer_count_ble()); + } +#endif + + BTM_SetPinType (btm_cb.cfg.pin_type, btm_cb.cfg.pin_code, btm_cb.cfg.pin_code_len); + + for (int i = 0; i <= controller->get_last_features_classic_index(); i++) { + btm_decode_ext_features_page(i, controller->get_features_classic(i)->as_array); + } + + btm_report_device_status(BTM_DEV_STATUS_UP); +} + +// TODO(zachoverflow): remove this function +void BTM_DeviceReset (UNUSED_ATTR tBTM_CMPL_CB *p_cb) { + /* Flush all ACL connections */ + btm_acl_device_down(); + + /* Clear the callback, so application would not hang on reset */ + btm_db_reset(); + + controller_get_interface()->devctl_reset(reset_complete); +} + +/******************************************************************************* +** +** Function BTM_IsDeviceUp +** +** Description This function is called to check if the device is up. +** +** Returns TRUE if device is up, else FALSE +** +*******************************************************************************/ +BOOLEAN BTM_IsDeviceUp (void) +{ + return controller_get_interface()->get_is_ready(); +} + +/******************************************************************************* +** +** Function btm_dev_timeout +** +** Description This function is called when a timer list entry expires. +** +** Returns void +** +*******************************************************************************/ +void btm_dev_timeout (TIMER_LIST_ENT *p_tle) +{ + TIMER_PARAM_TYPE timer_type = (TIMER_PARAM_TYPE)p_tle->param; + + if (timer_type == (TIMER_PARAM_TYPE)TT_DEV_RLN) + { + tBTM_CMPL_CB *p_cb = btm_cb.devcb.p_rln_cmpl_cb; + + btm_cb.devcb.p_rln_cmpl_cb = NULL; + + if (p_cb) + (*p_cb)((void *) NULL); + } +} + +/******************************************************************************* +** +** Function btm_decode_ext_features_page +** +** Description This function is decodes a features page. +** +** Returns void +** +*******************************************************************************/ +static void btm_decode_ext_features_page (UINT8 page_number, const UINT8 *p_features) +{ + UINT8 last; + UINT8 first; + + BTM_TRACE_DEBUG ("btm_decode_ext_features_page page: %d", page_number); + switch (page_number) + { + /* Extended (Legacy) Page 0 */ + case HCI_EXT_FEATURES_PAGE_0: + + /* Create ACL supported packet types mask */ + btm_cb.btm_acl_pkt_types_supported = (BTM_ACL_PKT_TYPES_MASK_DH1 + + BTM_ACL_PKT_TYPES_MASK_DM1); + + if (HCI_3_SLOT_PACKETS_SUPPORTED(p_features)) + btm_cb.btm_acl_pkt_types_supported |= (BTM_ACL_PKT_TYPES_MASK_DH3 + + BTM_ACL_PKT_TYPES_MASK_DM3); + + if (HCI_5_SLOT_PACKETS_SUPPORTED(p_features)) + btm_cb.btm_acl_pkt_types_supported |= (BTM_ACL_PKT_TYPES_MASK_DH5 + + BTM_ACL_PKT_TYPES_MASK_DM5); + + /* Add in EDR related ACL types */ + if (!HCI_EDR_ACL_2MPS_SUPPORTED(p_features)) + { + btm_cb.btm_acl_pkt_types_supported |= (BTM_ACL_PKT_TYPES_MASK_NO_2_DH1 + + BTM_ACL_PKT_TYPES_MASK_NO_2_DH3 + + BTM_ACL_PKT_TYPES_MASK_NO_2_DH5); + } + + if (!HCI_EDR_ACL_3MPS_SUPPORTED(p_features)) + { + btm_cb.btm_acl_pkt_types_supported |= (BTM_ACL_PKT_TYPES_MASK_NO_3_DH1 + + BTM_ACL_PKT_TYPES_MASK_NO_3_DH3 + + BTM_ACL_PKT_TYPES_MASK_NO_3_DH5); + } + + /* Check to see if 3 and 5 slot packets are available */ + if (HCI_EDR_ACL_2MPS_SUPPORTED(p_features) || + HCI_EDR_ACL_3MPS_SUPPORTED(p_features)) + { + if (!HCI_3_SLOT_EDR_ACL_SUPPORTED(p_features)) + btm_cb.btm_acl_pkt_types_supported |= (BTM_ACL_PKT_TYPES_MASK_NO_2_DH3 + + BTM_ACL_PKT_TYPES_MASK_NO_3_DH3); + + if (!HCI_5_SLOT_EDR_ACL_SUPPORTED(p_features)) + btm_cb.btm_acl_pkt_types_supported |= (BTM_ACL_PKT_TYPES_MASK_NO_2_DH5 + + BTM_ACL_PKT_TYPES_MASK_NO_3_DH5); + } + + BTM_TRACE_DEBUG("Local supported ACL packet types: 0x%04x", + btm_cb.btm_acl_pkt_types_supported); + + /* Create (e)SCO supported packet types mask */ + btm_cb.btm_sco_pkt_types_supported = 0; +#if BTM_SCO_INCLUDED == TRUE + btm_cb.sco_cb.esco_supported = FALSE; +#endif + if (HCI_SCO_LINK_SUPPORTED(p_features)) + { + btm_cb.btm_sco_pkt_types_supported = BTM_SCO_PKT_TYPES_MASK_HV1; + + if (HCI_HV2_PACKETS_SUPPORTED(p_features)) + btm_cb.btm_sco_pkt_types_supported |= BTM_SCO_PKT_TYPES_MASK_HV2; + + if (HCI_HV3_PACKETS_SUPPORTED(p_features)) + btm_cb.btm_sco_pkt_types_supported |= BTM_SCO_PKT_TYPES_MASK_HV3; + } + + if (HCI_ESCO_EV3_SUPPORTED(p_features)) + btm_cb.btm_sco_pkt_types_supported |= BTM_SCO_PKT_TYPES_MASK_EV3; + + if (HCI_ESCO_EV4_SUPPORTED(p_features)) + btm_cb.btm_sco_pkt_types_supported |= BTM_SCO_PKT_TYPES_MASK_EV4; + + if (HCI_ESCO_EV5_SUPPORTED(p_features)) + btm_cb.btm_sco_pkt_types_supported |= BTM_SCO_PKT_TYPES_MASK_EV5; +#if BTM_SCO_INCLUDED == TRUE + if (btm_cb.btm_sco_pkt_types_supported & BTM_ESCO_LINK_ONLY_MASK) + { + btm_cb.sco_cb.esco_supported = TRUE; + + /* Add in EDR related eSCO types */ + if (HCI_EDR_ESCO_2MPS_SUPPORTED(p_features)) + { + if (!HCI_3_SLOT_EDR_ESCO_SUPPORTED(p_features)) + btm_cb.btm_sco_pkt_types_supported |= BTM_SCO_PKT_TYPES_MASK_NO_2_EV5; + } + else + { + btm_cb.btm_sco_pkt_types_supported |= (BTM_SCO_PKT_TYPES_MASK_NO_2_EV3 + + BTM_SCO_PKT_TYPES_MASK_NO_2_EV5); + } + + if (HCI_EDR_ESCO_3MPS_SUPPORTED(p_features)) + { + if (!HCI_3_SLOT_EDR_ESCO_SUPPORTED(p_features)) + btm_cb.btm_sco_pkt_types_supported |= BTM_SCO_PKT_TYPES_MASK_NO_3_EV5; + } + else + { + btm_cb.btm_sco_pkt_types_supported |= (BTM_SCO_PKT_TYPES_MASK_NO_3_EV3 + + BTM_SCO_PKT_TYPES_MASK_NO_3_EV5); + } + } +#endif + + BTM_TRACE_DEBUG("Local supported SCO packet types: 0x%04x", + btm_cb.btm_sco_pkt_types_supported); + + /* Create Default Policy Settings */ + if (HCI_SWITCH_SUPPORTED(p_features)) + btm_cb.btm_def_link_policy |= HCI_ENABLE_MASTER_SLAVE_SWITCH; + else + btm_cb.btm_def_link_policy &= ~HCI_ENABLE_MASTER_SLAVE_SWITCH; + + if (HCI_HOLD_MODE_SUPPORTED(p_features)) + btm_cb.btm_def_link_policy |= HCI_ENABLE_HOLD_MODE; + else + btm_cb.btm_def_link_policy &= ~HCI_ENABLE_HOLD_MODE; + + if (HCI_SNIFF_MODE_SUPPORTED(p_features)) + btm_cb.btm_def_link_policy |= HCI_ENABLE_SNIFF_MODE; + else + btm_cb.btm_def_link_policy &= ~HCI_ENABLE_SNIFF_MODE; + + if (HCI_PARK_MODE_SUPPORTED(p_features)) + btm_cb.btm_def_link_policy |= HCI_ENABLE_PARK_MODE; + else + btm_cb.btm_def_link_policy &= ~HCI_ENABLE_PARK_MODE; + + btm_sec_dev_reset (); + + if (HCI_LMP_INQ_RSSI_SUPPORTED(p_features)) + { + if (HCI_EXT_INQ_RSP_SUPPORTED(p_features)) + BTM_SetInquiryMode (BTM_INQ_RESULT_EXTENDED); + else + BTM_SetInquiryMode (BTM_INQ_RESULT_WITH_RSSI); + } + +#if L2CAP_NON_FLUSHABLE_PB_INCLUDED == TRUE + if( HCI_NON_FLUSHABLE_PB_SUPPORTED(p_features)) + l2cu_set_non_flushable_pbf(TRUE); + else + l2cu_set_non_flushable_pbf(FALSE); +#endif + BTM_SetPageScanType (BTM_DEFAULT_SCAN_TYPE); + BTM_SetInquiryScanType (BTM_DEFAULT_SCAN_TYPE); + + break; + + /* Extended Page 1 */ + case HCI_EXT_FEATURES_PAGE_1: + /* Nothing to do for page 1 */ + break; + + /* Extended Page 2 */ + case HCI_EXT_FEATURES_PAGE_2: + /* Nothing to do for page 2 */ + break; + + default: + BTM_TRACE_ERROR("btm_decode_ext_features_page page=%d unknown", page_number); + break; + } +} + +/******************************************************************************* +** +** Function BTM_SetLocalDeviceName +** +** Description This function is called to set the local device name. +** +** Returns status of the operation +** +*******************************************************************************/ +tBTM_STATUS BTM_SetLocalDeviceName (char *p_name) +{ + UINT8 *p; + + if (!p_name || !p_name[0] || (strlen ((char *)p_name) > BD_NAME_LEN)) + return (BTM_ILLEGAL_VALUE); + + if (!controller_get_interface()->get_is_ready()) + return (BTM_DEV_RESET); + +#if BTM_MAX_LOC_BD_NAME_LEN > 0 + /* Save the device name if local storage is enabled */ + p = (UINT8 *)btm_cb.cfg.bd_name; + if (p != (UINT8 *)p_name) + { + BCM_STRNCPY_S(btm_cb.cfg.bd_name, sizeof(btm_cb.cfg.bd_name), p_name, BTM_MAX_LOC_BD_NAME_LEN); + btm_cb.cfg.bd_name[BTM_MAX_LOC_BD_NAME_LEN] = '\0'; + } +#else + p = (UINT8 *)p_name; +#endif + + if (btsnd_hcic_change_name(p)) + return (BTM_CMD_STARTED); + else + return (BTM_NO_RESOURCES); +} + + + +/******************************************************************************* +** +** Function BTM_ReadLocalDeviceName +** +** Description This function is called to read the local device name. +** +** Returns status of the operation +** If success, BTM_SUCCESS is returned and p_name points stored +** local device name +** If BTM doesn't store local device name, BTM_NO_RESOURCES is +** is returned and p_name is set to NULL +** +*******************************************************************************/ +tBTM_STATUS BTM_ReadLocalDeviceName (char **p_name) +{ +#if BTM_MAX_LOC_BD_NAME_LEN > 0 + *p_name = btm_cb.cfg.bd_name; + return(BTM_SUCCESS); +#else + *p_name = NULL; + return(BTM_NO_RESOURCES); +#endif +} + + +/******************************************************************************* +** +** Function BTM_ReadLocalDeviceNameFromController +** +** Description Get local device name from controller. Do not use cached +** name (used to get chip-id prior to btm reset complete). +** +** Returns BTM_CMD_STARTED if successful, otherwise an error +** +*******************************************************************************/ +tBTM_STATUS BTM_ReadLocalDeviceNameFromController (tBTM_CMPL_CB *p_rln_cmpl_cback) +{ + /* Check if rln already in progress */ + if (btm_cb.devcb.p_rln_cmpl_cb) + return(BTM_NO_RESOURCES); + + /* Save callback */ + btm_cb.devcb.p_rln_cmpl_cb = p_rln_cmpl_cback; + + btsnd_hcic_read_name(); + btu_start_timer (&btm_cb.devcb.rln_timer, BTU_TTYPE_BTM_DEV_CTL, BTM_DEV_REPLY_TIMEOUT); + + return BTM_CMD_STARTED; +} + +/******************************************************************************* +** +** Function btm_read_local_name_complete +** +** Description This function is called when local name read complete. +** message is received from the HCI. +** +** Returns void +** +*******************************************************************************/ +void btm_read_local_name_complete (UINT8 *p, UINT16 evt_len) +{ + tBTM_CMPL_CB *p_cb = btm_cb.devcb.p_rln_cmpl_cb; + UINT8 status; + UNUSED(evt_len); + + btu_stop_timer (&btm_cb.devcb.rln_timer); + + /* If there was a callback address for read local name, call it */ + btm_cb.devcb.p_rln_cmpl_cb = NULL; + + if (p_cb) + { + STREAM_TO_UINT8 (status, p); + + if (status == HCI_SUCCESS) + (*p_cb)(p); + else + (*p_cb)(NULL); + } +} + +/******************************************************************************* +** +** Function BTM_SetDeviceClass +** +** Description This function is called to set the local device class +** +** Returns status of the operation +** +*******************************************************************************/ +tBTM_STATUS BTM_SetDeviceClass (DEV_CLASS dev_class) +{ + if(!memcmp (btm_cb.devcb.dev_class, dev_class, DEV_CLASS_LEN)) + return(BTM_SUCCESS); + + memcpy (btm_cb.devcb.dev_class, dev_class, DEV_CLASS_LEN); + + if (!controller_get_interface()->get_is_ready()) + return (BTM_DEV_RESET); + + if (!btsnd_hcic_write_dev_class (dev_class)) + return (BTM_NO_RESOURCES); + + return (BTM_SUCCESS); +} + + +/******************************************************************************* +** +** Function BTM_ReadDeviceClass +** +** Description This function is called to read the local device class +** +** Returns pointer to the device class +** +*******************************************************************************/ +UINT8 *BTM_ReadDeviceClass (void) +{ + return ((UINT8 *)btm_cb.devcb.dev_class); +} + + +/******************************************************************************* +** +** Function BTM_ReadLocalFeatures +** +** Description This function is called to read the local features +** +** Returns pointer to the local features string +** +*******************************************************************************/ +// TODO(zachoverflow): get rid of this function +UINT8 *BTM_ReadLocalFeatures (void) +{ + // Discarding const modifier for now, until this function dies + return (UINT8 *)controller_get_interface()->get_features_classic(0)->as_array; +} + +/******************************************************************************* +** +** Function BTM_RegisterForDeviceStatusNotif +** +** Description This function is called to register for device status +** change notifications. +** +** If one registration is already there calling function should +** save the pointer to the function that is return and +** call it when processing of the event is complete +** +** Returns status of the operation +** +*******************************************************************************/ +tBTM_DEV_STATUS_CB *BTM_RegisterForDeviceStatusNotif (tBTM_DEV_STATUS_CB *p_cb) +{ + tBTM_DEV_STATUS_CB *p_prev = btm_cb.devcb.p_dev_status_cb; + + btm_cb.devcb.p_dev_status_cb = p_cb; + return (p_prev); +} + +/******************************************************************************* +** +** Function BTM_VendorSpecificCommand +** +** Description Send a vendor specific HCI command to the controller. +** +** Returns +** BTM_SUCCESS Command sent. Does not expect command complete +** event. (command cmpl callback param is NULL) +** BTM_CMD_STARTED Command sent. Waiting for command cmpl event. +** +** Notes +** Opcode will be OR'd with HCI_GRP_VENDOR_SPECIFIC. +** +*******************************************************************************/ +tBTM_STATUS BTM_VendorSpecificCommand(UINT16 opcode, UINT8 param_len, + UINT8 *p_param_buf, tBTM_VSC_CMPL_CB *p_cb) +{ + void *p_buf; + + BTM_TRACE_EVENT ("BTM: BTM_VendorSpecificCommand: Opcode: 0x%04X, ParamLen: %i.", + opcode, param_len); + + /* Allocate a buffer to hold HCI command plus the callback function */ + if ((p_buf = GKI_getbuf((UINT16)(sizeof(BT_HDR) + sizeof (tBTM_CMPL_CB *) + + param_len + HCIC_PREAMBLE_SIZE))) != NULL) + { + /* Send the HCI command (opcode will be OR'd with HCI_GRP_VENDOR_SPECIFIC) */ + btsnd_hcic_vendor_spec_cmd (p_buf, opcode, param_len, p_param_buf, (void *)p_cb); + + /* Return value */ + if (p_cb != NULL) + return (BTM_CMD_STARTED); + else + return (BTM_SUCCESS); + } + else + return (BTM_NO_RESOURCES); + +} + + +/******************************************************************************* +** +** Function btm_vsc_complete +** +** Description This function is called when local HCI Vendor Specific +** Command complete message is received from the HCI. +** +** Returns void +** +*******************************************************************************/ +void btm_vsc_complete (UINT8 *p, UINT16 opcode, UINT16 evt_len, + tBTM_CMPL_CB *p_vsc_cplt_cback) +{ + tBTM_VSC_CMPL vcs_cplt_params; + + /* If there was a callback address for vcs complete, call it */ + if (p_vsc_cplt_cback) + { + /* Pass paramters to the callback function */ + vcs_cplt_params.opcode = opcode; /* Number of bytes in return info */ + vcs_cplt_params.param_len = evt_len; /* Number of bytes in return info */ + vcs_cplt_params.p_param_buf = p; + (*p_vsc_cplt_cback)(&vcs_cplt_params); /* Call the VSC complete callback function */ + } +} + +/******************************************************************************* +** +** Function BTM_RegisterForVSEvents +** +** Description This function is called to register/deregister for vendor +** specific HCI events. +** +** If is_register=TRUE, then the function will be registered; +** if is_register=FALSE, then the function will be deregistered. +** +** Returns BTM_SUCCESS if successful, +** BTM_BUSY if maximum number of callbacks have already been +** registered. +** +*******************************************************************************/ +tBTM_STATUS BTM_RegisterForVSEvents (tBTM_VS_EVT_CB *p_cb, BOOLEAN is_register) +{ + tBTM_STATUS retval = BTM_SUCCESS; + UINT8 i, free_idx = BTM_MAX_VSE_CALLBACKS; + + /* See if callback is already registered */ + for (i=0; itransmit_command( + hci_packet_factory_get_interface()->make_set_event_mask((const bt_event_mask_t *)("\x00\x00\x00\x00\x00\x00\x00\x00")), + NULL, + NULL, + NULL); + + /* Send the HCI command */ + if (btsnd_hcic_enable_test_mode ()) + return (BTM_SUCCESS); + else + return (BTM_NO_RESOURCES); +} + +/******************************************************************************* +** +** Function BTM_DeleteStoredLinkKey +** +** Description This function is called to delete link key for the specified +** device addresses from the NVRAM storage attached to the Bluetooth +** controller. +** +** Parameters: bd_addr - Addresses of the devices +** p_cb - Call back function to be called to return +** the results +** +*******************************************************************************/ +tBTM_STATUS BTM_DeleteStoredLinkKey(BD_ADDR bd_addr, tBTM_CMPL_CB *p_cb) +{ + BD_ADDR local_bd_addr; + BOOLEAN delete_all_flag = FALSE; + + /* Check if the previous command is completed */ + if (btm_cb.devcb.p_stored_link_key_cmpl_cb) + return (BTM_BUSY); + + if (!bd_addr) + { + /* This is to delete all link keys */ + delete_all_flag = TRUE; + + /* We don't care the BD address. Just pass a non zero pointer */ + bd_addr = local_bd_addr; + } + + BTM_TRACE_EVENT ("BTM: BTM_DeleteStoredLinkKey: delete_all_flag: %s", + delete_all_flag ? "TRUE" : "FALSE"); + + /* Send the HCI command */ + btm_cb.devcb.p_stored_link_key_cmpl_cb = p_cb; + if (!btsnd_hcic_delete_stored_key (bd_addr, delete_all_flag)) + { + return (BTM_NO_RESOURCES); + } + else + return (BTM_SUCCESS); +} + +/******************************************************************************* +** +** Function btm_delete_stored_link_key_complete +** +** Description This function is called when the command complete message +** is received from the HCI for the delete stored link key command. +** +** Returns void +** +*******************************************************************************/ +void btm_delete_stored_link_key_complete (UINT8 *p) +{ + tBTM_CMPL_CB *p_cb = btm_cb.devcb.p_stored_link_key_cmpl_cb; + tBTM_DELETE_STORED_LINK_KEY_COMPLETE result; + + /* If there was a callback registered for read stored link key, call it */ + btm_cb.devcb.p_stored_link_key_cmpl_cb = NULL; + + if (p_cb) + { + /* Set the call back event to indicate command complete */ + result.event = BTM_CB_EVT_DELETE_STORED_LINK_KEYS; + + /* Extract the result fields from the HCI event */ + STREAM_TO_UINT8 (result.status, p); + STREAM_TO_UINT16 (result.num_keys, p); + + /* Call the call back and pass the result */ + (*p_cb)(&result); + } +} + +/******************************************************************************* +** +** Function btm_report_device_status +** +** Description This function is called when there is a change in the device +** status. This function will report the new device status to +** the application +** +** Returns void +** +*******************************************************************************/ +void btm_report_device_status (tBTM_DEV_STATUS status) +{ + tBTM_DEV_STATUS_CB *p_cb = btm_cb.devcb.p_dev_status_cb; + + /* Call the call back to pass the device status to application */ + if (p_cb) + (*p_cb)(status); +} + + diff --git a/components/bt/bluedroid/stack/btm/btm_inq.c b/components/bt/bluedroid/stack/btm/btm_inq.c new file mode 100755 index 0000000000..6a9eea526b --- /dev/null +++ b/components/bt/bluedroid/stack/btm/btm_inq.c @@ -0,0 +1,2950 @@ +/****************************************************************************** + * + * Copyright (C) 1999-2014 Broadcom Corporation + * + * 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 functions that handle inquiries. These include + * setting discoverable mode, controlling the mode of the Baseband, and + * maintaining a small database of inquiry responses, with API for people + * to browse it. + * + ******************************************************************************/ + +#include +#include +#include + +#include "bt_types.h" +#include "controller.h" +#include "gki.h" +#include "hcimsgs.h" +#include "btu.h" +#include "btm_api.h" +#include "btm_int.h" +#include "hcidefs.h" +#if (defined(SDP_INCLUDED) && SDP_INCLUDED == TRUE) +#include "sdpdefs.h" +#endif + +#define BTM_INQ_REPLY_TIMEOUT 3 /* 3 second timeout waiting for responses */ + +/* TRUE to enable DEBUG traces for btm_inq */ +#ifndef BTM_INQ_DEBUG +#define BTM_INQ_DEBUG FALSE +#endif +/********************************************************************************/ +/* L O C A L D A T A D E F I N I T I O N S */ +/********************************************************************************/ +static const LAP general_inq_lap = {0x9e,0x8b,0x33}; +static const LAP limited_inq_lap = {0x9e,0x8b,0x00}; + +#if (defined(SDP_INCLUDED) && SDP_INCLUDED == TRUE) +static const UINT16 BTM_EIR_UUID_LKUP_TBL[BTM_EIR_MAX_SERVICES] = +{ + UUID_SERVCLASS_SERVICE_DISCOVERY_SERVER, +/* UUID_SERVCLASS_BROWSE_GROUP_DESCRIPTOR, */ +/* UUID_SERVCLASS_PUBLIC_BROWSE_GROUP, */ + UUID_SERVCLASS_SERIAL_PORT, + UUID_SERVCLASS_LAN_ACCESS_USING_PPP, + UUID_SERVCLASS_DIALUP_NETWORKING, + UUID_SERVCLASS_IRMC_SYNC, + UUID_SERVCLASS_OBEX_OBJECT_PUSH, + UUID_SERVCLASS_OBEX_FILE_TRANSFER, + UUID_SERVCLASS_IRMC_SYNC_COMMAND, + UUID_SERVCLASS_HEADSET, + UUID_SERVCLASS_CORDLESS_TELEPHONY, + UUID_SERVCLASS_AUDIO_SOURCE, + UUID_SERVCLASS_AUDIO_SINK, + UUID_SERVCLASS_AV_REM_CTRL_TARGET, +/* UUID_SERVCLASS_ADV_AUDIO_DISTRIBUTION, */ + UUID_SERVCLASS_AV_REMOTE_CONTROL, +/* UUID_SERVCLASS_VIDEO_CONFERENCING, */ + UUID_SERVCLASS_INTERCOM, + UUID_SERVCLASS_FAX, + UUID_SERVCLASS_HEADSET_AUDIO_GATEWAY, +/* UUID_SERVCLASS_WAP, */ +/* UUID_SERVCLASS_WAP_CLIENT, */ + UUID_SERVCLASS_PANU, + UUID_SERVCLASS_NAP, + UUID_SERVCLASS_GN, + UUID_SERVCLASS_DIRECT_PRINTING, +/* UUID_SERVCLASS_REFERENCE_PRINTING, */ + UUID_SERVCLASS_IMAGING, + UUID_SERVCLASS_IMAGING_RESPONDER, + UUID_SERVCLASS_IMAGING_AUTO_ARCHIVE, + UUID_SERVCLASS_IMAGING_REF_OBJECTS, + UUID_SERVCLASS_HF_HANDSFREE, + UUID_SERVCLASS_AG_HANDSFREE, + UUID_SERVCLASS_DIR_PRT_REF_OBJ_SERVICE, +/* UUID_SERVCLASS_REFLECTED_UI, */ + UUID_SERVCLASS_BASIC_PRINTING, + UUID_SERVCLASS_PRINTING_STATUS, + UUID_SERVCLASS_HUMAN_INTERFACE, + UUID_SERVCLASS_CABLE_REPLACEMENT, + UUID_SERVCLASS_HCRP_PRINT, + UUID_SERVCLASS_HCRP_SCAN, +/* UUID_SERVCLASS_COMMON_ISDN_ACCESS, */ +/* UUID_SERVCLASS_VIDEO_CONFERENCING_GW, */ +/* UUID_SERVCLASS_UDI_MT, */ +/* UUID_SERVCLASS_UDI_TA, */ +/* UUID_SERVCLASS_VCP, */ + UUID_SERVCLASS_SAP, + UUID_SERVCLASS_PBAP_PCE, + UUID_SERVCLASS_PBAP_PSE, + UUID_SERVCLASS_PHONE_ACCESS, + UUID_SERVCLASS_HEADSET_HS, + UUID_SERVCLASS_PNP_INFORMATION, +/* UUID_SERVCLASS_GENERIC_NETWORKING, */ +/* UUID_SERVCLASS_GENERIC_FILETRANSFER, */ +/* UUID_SERVCLASS_GENERIC_AUDIO, */ +/* UUID_SERVCLASS_GENERIC_TELEPHONY, */ +/* UUID_SERVCLASS_UPNP_SERVICE, */ +/* UUID_SERVCLASS_UPNP_IP_SERVICE, */ +/* UUID_SERVCLASS_ESDP_UPNP_IP_PAN, */ +/* UUID_SERVCLASS_ESDP_UPNP_IP_LAP, */ +/* UUID_SERVCLASS_ESDP_UPNP_IP_L2CAP, */ + UUID_SERVCLASS_VIDEO_SOURCE, + UUID_SERVCLASS_VIDEO_SINK, +/* UUID_SERVCLASS_VIDEO_DISTRIBUTION */ + UUID_SERVCLASS_MESSAGE_ACCESS, + UUID_SERVCLASS_MESSAGE_NOTIFICATION, + UUID_SERVCLASS_HDP_SOURCE, + UUID_SERVCLASS_HDP_SINK +}; +#else +static const UINT16 BTM_EIR_UUID_LKUP_TBL[BTM_EIR_MAX_SERVICES]; +#endif + +/********************************************************************************/ +/* L O C A L F U N C T I O N P R O T O T Y P E S */ +/********************************************************************************/ +static void btm_initiate_inquiry (tBTM_INQUIRY_VAR_ST *p_inq); +static tBTM_STATUS btm_set_inq_event_filter (UINT8 filter_cond_type, tBTM_INQ_FILT_COND *p_filt_cond); +static void btm_clr_inq_result_flt (void); + +static UINT8 btm_convert_uuid_to_eir_service( UINT16 uuid16 ); +static void btm_set_eir_uuid( UINT8 *p_eir, tBTM_INQ_RESULTS *p_results ); +static UINT8 *btm_eir_get_uuid_list( UINT8 *p_eir, UINT8 uuid_size, + UINT8 *p_num_uuid, UINT8 *p_uuid_list_type ); +static UINT16 btm_convert_uuid_to_uuid16( UINT8 *p_uuid, UINT8 uuid_size ); + +/******************************************************************************* +** +** Function BTM_SetDiscoverability +** +** Description This function is called to set the device into or out of +** discoverable mode. Discoverable mode means inquiry +** scans are enabled. If a value of '0' is entered for window or +** interval, the default values are used. +** +** Returns BTM_SUCCESS if successful +** BTM_BUSY if a setting of the filter is already in progress +** BTM_NO_RESOURCES if couldn't get a memory pool buffer +** BTM_ILLEGAL_VALUE if a bad parameter was detected +** BTM_WRONG_MODE if the device is not up. +** +*******************************************************************************/ +tBTM_STATUS BTM_SetDiscoverability (UINT16 inq_mode, UINT16 window, UINT16 interval) +{ + UINT8 scan_mode = 0; + UINT16 service_class; + UINT8 *p_cod; + UINT8 major, minor; + DEV_CLASS cod; + LAP temp_lap[2]; + BOOLEAN is_limited; + BOOLEAN cod_limited; + + BTM_TRACE_API ("BTM_SetDiscoverability\n"); +#if (BLE_INCLUDED == TRUE && BLE_INCLUDED == TRUE) + if (controller_get_interface()->supports_ble()) + { + if (btm_ble_set_discoverability((UINT16)(inq_mode)) + == BTM_SUCCESS) + { + btm_cb.btm_inq_vars.discoverable_mode &= (~BTM_BLE_DISCOVERABLE_MASK); + btm_cb.btm_inq_vars.discoverable_mode |= (inq_mode & BTM_BLE_DISCOVERABLE_MASK); + } + } + inq_mode &= ~BTM_BLE_DISCOVERABLE_MASK; +#endif + + /*** Check mode parameter ***/ + if (inq_mode > BTM_MAX_DISCOVERABLE) + return (BTM_ILLEGAL_VALUE); + + /* Make sure the controller is active */ + if (!controller_get_interface()->get_is_ready()) + return (BTM_DEV_RESET); + + /* If the window and/or interval is '0', set to default values */ + if (!window) + window = BTM_DEFAULT_DISC_WINDOW; + + if (!interval) + interval = BTM_DEFAULT_DISC_INTERVAL; + + BTM_TRACE_API ("BTM_SetDiscoverability: mode %d [NonDisc-0, Lim-1, Gen-2], window 0x%04x, interval 0x%04x\n", + inq_mode, window, interval); + + /*** Check for valid window and interval parameters ***/ + /*** Only check window and duration if mode is connectable ***/ + if (inq_mode != BTM_NON_DISCOVERABLE) + { + /* window must be less than or equal to interval */ + if (window < HCI_MIN_INQUIRYSCAN_WINDOW || + window > HCI_MAX_INQUIRYSCAN_WINDOW || + interval < HCI_MIN_INQUIRYSCAN_INTERVAL || + interval > HCI_MAX_INQUIRYSCAN_INTERVAL || + window > interval) + { + return (BTM_ILLEGAL_VALUE); + } + } + + /* Set the IAC if needed */ + if (inq_mode != BTM_NON_DISCOVERABLE) + { + if (inq_mode & BTM_LIMITED_DISCOVERABLE) + { + /* Use the GIAC and LIAC codes for limited discoverable mode */ + memcpy (temp_lap[0], limited_inq_lap, LAP_LEN); + memcpy (temp_lap[1], general_inq_lap, LAP_LEN); + + if (!btsnd_hcic_write_cur_iac_lap (2, (LAP * const) temp_lap)) + return (BTM_NO_RESOURCES); /* Cannot continue */ + } + else + { + if (!btsnd_hcic_write_cur_iac_lap (1, (LAP * const) &general_inq_lap)) + return (BTM_NO_RESOURCES); /* Cannot continue */ + } + + scan_mode |= HCI_INQUIRY_SCAN_ENABLED; + } + + /* Send down the inquiry scan window and period if changed */ + if ((window != btm_cb.btm_inq_vars.inq_scan_window) || + (interval != btm_cb.btm_inq_vars.inq_scan_period)) + { + if (btsnd_hcic_write_inqscan_cfg (interval, window)) + { + btm_cb.btm_inq_vars.inq_scan_window = window; + btm_cb.btm_inq_vars.inq_scan_period = interval; + } + else + return (BTM_NO_RESOURCES); + } + + if (btm_cb.btm_inq_vars.connectable_mode & BTM_CONNECTABLE_MASK) + scan_mode |= HCI_PAGE_SCAN_ENABLED; + + if (btsnd_hcic_write_scan_enable (scan_mode)) + { + btm_cb.btm_inq_vars.discoverable_mode &= (~BTM_DISCOVERABLE_MASK); + btm_cb.btm_inq_vars.discoverable_mode |= inq_mode; + } + else + return (BTM_NO_RESOURCES); + + /* Change the service class bit if mode has changed */ + p_cod = BTM_ReadDeviceClass(); + BTM_COD_SERVICE_CLASS(service_class, p_cod); + is_limited = (inq_mode & BTM_LIMITED_DISCOVERABLE) ? TRUE : FALSE; + cod_limited = (service_class & BTM_COD_SERVICE_LMTD_DISCOVER) ? TRUE : FALSE; + if (is_limited ^ cod_limited) + { + BTM_COD_MINOR_CLASS(minor, p_cod ); + BTM_COD_MAJOR_CLASS(major, p_cod ); + if (is_limited) + service_class |= BTM_COD_SERVICE_LMTD_DISCOVER; + else + service_class &= ~BTM_COD_SERVICE_LMTD_DISCOVER; + + FIELDS_TO_COD(cod, minor, major, service_class); + (void) BTM_SetDeviceClass (cod); + } + + return (BTM_SUCCESS); +} + +/******************************************************************************* +** +** Function BTM_SetInquiryScanType +** +** Description This function is called to set the iquiry scan-type to +** standard or interlaced. +** +** Returns BTM_SUCCESS if successful +** BTM_MODE_UNSUPPORTED if not a 1.2 device +** BTM_WRONG_MODE if the device is not up. +** +*******************************************************************************/ +tBTM_STATUS BTM_SetInquiryScanType (UINT16 scan_type) +{ + + BTM_TRACE_API ("BTM_SetInquiryScanType\n"); + if (scan_type != BTM_SCAN_TYPE_STANDARD && scan_type != BTM_SCAN_TYPE_INTERLACED) + return (BTM_ILLEGAL_VALUE); + + /* whatever app wants if device is not 1.2 scan type should be STANDARD */ + if (!controller_get_interface()->supports_interlaced_inquiry_scan()) + return (BTM_MODE_UNSUPPORTED); + + /* Check for scan type if configuration has been changed */ + if (scan_type != btm_cb.btm_inq_vars.inq_scan_type) + { + if (BTM_IsDeviceUp()) + { + if (btsnd_hcic_write_inqscan_type ((UINT8)scan_type)) + btm_cb.btm_inq_vars.inq_scan_type = scan_type; + else + return (BTM_NO_RESOURCES); + } + else return (BTM_WRONG_MODE); + } + return (BTM_SUCCESS); +} + +/******************************************************************************* +** +** Function BTM_SetPageScanType +** +** Description This function is called to set the page scan-type to +** standard or interlaced. +** +** Returns BTM_SUCCESS if successful +** BTM_MODE_UNSUPPORTED if not a 1.2 device +** BTM_WRONG_MODE if the device is not up. +** +*******************************************************************************/ +tBTM_STATUS BTM_SetPageScanType (UINT16 scan_type) +{ + BTM_TRACE_API ("BTM_SetPageScanType\n"); + if (scan_type != BTM_SCAN_TYPE_STANDARD && scan_type != BTM_SCAN_TYPE_INTERLACED) + return (BTM_ILLEGAL_VALUE); + + /* whatever app wants if device is not 1.2 scan type should be STANDARD */ + if (!controller_get_interface()->supports_interlaced_inquiry_scan()) + return (BTM_MODE_UNSUPPORTED); + + /* Check for scan type if configuration has been changed */ + if (scan_type != btm_cb.btm_inq_vars.page_scan_type) + { + if (BTM_IsDeviceUp()) + { + if (btsnd_hcic_write_pagescan_type ((UINT8)scan_type)) + btm_cb.btm_inq_vars.page_scan_type = scan_type; + else + return (BTM_NO_RESOURCES); + } + else return (BTM_WRONG_MODE); + } + return (BTM_SUCCESS); +} + + +/******************************************************************************* +** +** Function BTM_SetInquiryMode +** +** Description This function is called to set standard or with RSSI +** mode of the inquiry for local device. +** +** Output Params: mode - standard, with RSSI, extended +** +** Returns BTM_SUCCESS if successful +** BTM_NO_RESOURCES if couldn't get a memory pool buffer +** BTM_ILLEGAL_VALUE if a bad parameter was detected +** BTM_WRONG_MODE if the device is not up. +** +*******************************************************************************/ +tBTM_STATUS BTM_SetInquiryMode (UINT8 mode) +{ + const controller_t *controller = controller_get_interface(); + BTM_TRACE_API ("BTM_SetInquiryMode\n"); + if (mode == BTM_INQ_RESULT_STANDARD) + { + /* mandatory mode */ + } + else if (mode == BTM_INQ_RESULT_WITH_RSSI) + { + if (!controller->supports_rssi_with_inquiry_results()) + return (BTM_MODE_UNSUPPORTED); + } + else if (mode == BTM_INQ_RESULT_EXTENDED) + { + if (!controller->supports_extended_inquiry_response()) + return (BTM_MODE_UNSUPPORTED); + } + else + return (BTM_ILLEGAL_VALUE); + + if (!BTM_IsDeviceUp()) + return (BTM_WRONG_MODE); + + if (!btsnd_hcic_write_inquiry_mode (mode)) + return (BTM_NO_RESOURCES); + + return (BTM_SUCCESS); +} + +/******************************************************************************* +** +** Function BTM_ReadDiscoverability +** +** Description This function is called to read the current discoverability +** mode of the device. +** +** Output Params: p_window - current inquiry scan duration +** p_interval - current inquiry scan interval +** +** Returns BTM_NON_DISCOVERABLE, BTM_LIMITED_DISCOVERABLE, or +** BTM_GENERAL_DISCOVERABLE +** +*******************************************************************************/ +UINT16 BTM_ReadDiscoverability (UINT16 *p_window, UINT16 *p_interval) +{ + BTM_TRACE_API ("BTM_ReadDiscoverability\n"); + if (p_window) + *p_window = btm_cb.btm_inq_vars.inq_scan_window; + + if (p_interval) + *p_interval = btm_cb.btm_inq_vars.inq_scan_period; + + return (btm_cb.btm_inq_vars.discoverable_mode); +} + + +/******************************************************************************* +** +** Function BTM_SetPeriodicInquiryMode +** +** Description This function is called to set the device periodic inquiry mode. +** If the duration is zero, the periodic inquiry mode is cancelled. +** +** Note: We currently do not allow concurrent inquiry and periodic inquiry. +** +** Parameters: p_inqparms - pointer to the inquiry information +** mode - GENERAL or LIMITED inquiry +** duration - length in 1.28 sec intervals (If '0', the inquiry is CANCELLED) +** max_resps - maximum amount of devices to search for before ending the inquiry +** filter_cond_type - BTM_CLR_INQUIRY_FILTER, BTM_FILTER_COND_DEVICE_CLASS, or +** BTM_FILTER_COND_BD_ADDR +** filter_cond - value for the filter (based on filter_cond_type) +** +** max_delay - maximum amount of time between successive inquiries +** min_delay - minimum amount of time between successive inquiries +** p_results_cb - callback returning pointer to results (tBTM_INQ_RESULTS) +** +** Returns BTM_CMD_STARTED if successfully started +** BTM_ILLEGAL_VALUE if a bad parameter is detected +** BTM_NO_RESOURCES if could not allocate a message buffer +** BTM_SUCCESS - if cancelling the periodic inquiry +** BTM_BUSY - if an inquiry is already active +** BTM_WRONG_MODE if the device is not up. +** +*******************************************************************************/ +tBTM_STATUS BTM_SetPeriodicInquiryMode (tBTM_INQ_PARMS *p_inqparms, UINT16 max_delay, + UINT16 min_delay, tBTM_INQ_RESULTS_CB *p_results_cb) +{ + tBTM_STATUS status; + tBTM_INQUIRY_VAR_ST *p_inq = &btm_cb.btm_inq_vars; + + BTM_TRACE_API ("BTM_SetPeriodicInquiryMode: mode: %d, dur: %d, rsps: %d, flt: %d, min: %d, max: %d\n", + p_inqparms->mode, p_inqparms->duration, p_inqparms->max_resps, + p_inqparms->filter_cond_type, min_delay, max_delay); + + /*** Make sure the device is ready ***/ + if (!BTM_IsDeviceUp()) + return (BTM_WRONG_MODE); + + /* Only one active inquiry is allowed in this implementation. + Also do not allow an inquiry if the inquiry filter is being updated */ + if (p_inq->inq_active || p_inq->inqfilt_active) + return (BTM_BUSY); + + /* If illegal parameters return FALSE */ + if (p_inqparms->mode != BTM_GENERAL_INQUIRY && + p_inqparms->mode != BTM_LIMITED_INQUIRY) + return (BTM_ILLEGAL_VALUE); + + /* Verify the parameters for this command */ + if (p_inqparms->duration < BTM_MIN_INQUIRY_LEN || + p_inqparms->duration > BTM_MAX_INQUIRY_LENGTH || + min_delay <= p_inqparms->duration || + min_delay < BTM_PER_INQ_MIN_MIN_PERIOD || + min_delay > BTM_PER_INQ_MAX_MIN_PERIOD || + max_delay <= min_delay || + max_delay < BTM_PER_INQ_MIN_MAX_PERIOD) + /* max_delay > BTM_PER_INQ_MAX_MAX_PERIOD)*/ + /* BTM_PER_INQ_MAX_MAX_PERIOD set to 1's in all bits. Condition resulting in false always*/ + { + return (BTM_ILLEGAL_VALUE); + } + + /* Save the inquiry parameters to be used upon the completion of setting/clearing the inquiry filter */ + p_inq->inqparms = *p_inqparms; + p_inq->per_min_delay = min_delay; + p_inq->per_max_delay = max_delay; + p_inq->inq_cmpl_info.num_resp = 0; /* Clear the results counter */ + p_inq->p_inq_results_cb = p_results_cb; + + p_inq->inq_active = (UINT8)((p_inqparms->mode == BTM_LIMITED_INQUIRY) ? + (BTM_LIMITED_INQUIRY_ACTIVE | BTM_PERIODIC_INQUIRY_ACTIVE) : + (BTM_GENERAL_INQUIRY_ACTIVE | BTM_PERIODIC_INQUIRY_ACTIVE)); + + /* If a filter is specified, then save it for later and clear the current filter. + The setting of the filter is done upon completion of clearing of the previous + filter. + */ + if (p_inqparms->filter_cond_type != BTM_CLR_INQUIRY_FILTER) + { + p_inq->state = BTM_INQ_CLR_FILT_STATE; + p_inqparms->filter_cond_type = BTM_CLR_INQUIRY_FILTER; + } + else /* The filter is not being used so simply clear it; the inquiry can start after this operation */ + p_inq->state = BTM_INQ_SET_FILT_STATE; + + /* Before beginning the inquiry the current filter must be cleared, so initiate the command */ + if ((status = btm_set_inq_event_filter (p_inqparms->filter_cond_type, &p_inqparms->filter_cond)) != BTM_CMD_STARTED) + { + /* If set filter command is not succesful reset the state */ + p_inq->p_inq_results_cb = NULL; + p_inq->state = BTM_INQ_INACTIVE_STATE; + + } + + return (status); +} + + +/******************************************************************************* +** +** Function BTM_CancelPeriodicInquiry +** +** Description This function cancels a periodic inquiry +** +** Returns +** BTM_NO_RESOURCES if could not allocate a message buffer +** BTM_SUCCESS - if cancelling the periodic inquiry +** BTM_WRONG_MODE if the device is not up. +** +*******************************************************************************/ +tBTM_STATUS BTM_CancelPeriodicInquiry(void) +{ + tBTM_INQUIRY_VAR_ST *p_inq = &btm_cb.btm_inq_vars; + tBTM_STATUS status = BTM_SUCCESS; + BTM_TRACE_API ("BTM_CancelPeriodicInquiry called\n"); + + /*** Make sure the device is ready ***/ + if (!BTM_IsDeviceUp()) + return (BTM_WRONG_MODE); + + /* Only cancel if one is active */ + if (btm_cb.btm_inq_vars.inq_active & BTM_PERIODIC_INQUIRY_ACTIVE) + { + btm_cb.btm_inq_vars.inq_active = BTM_INQUIRY_INACTIVE; + btm_cb.btm_inq_vars.p_inq_results_cb = (tBTM_INQ_RESULTS_CB *) NULL; + + if (!btsnd_hcic_exit_per_inq ()) + status = BTM_NO_RESOURCES; + + /* If the event filter is in progress, mark it so that the processing of the return + event will be ignored */ + if(p_inq->inqfilt_active) + p_inq->pending_filt_complete_event++; + + p_inq->inqfilt_active = FALSE; + p_inq->inq_counter++; + } + + return (status); +} + + +/******************************************************************************* +** +** Function BTM_SetConnectability +** +** Description This function is called to set the device into or out of +** connectable mode. Discoverable mode means page scans enabled. +** +** Returns BTM_SUCCESS if successful +** BTM_ILLEGAL_VALUE if a bad parameter is detected +** BTM_NO_RESOURCES if could not allocate a message buffer +** BTM_WRONG_MODE if the device is not up. +** +*******************************************************************************/ +tBTM_STATUS BTM_SetConnectability (UINT16 page_mode, UINT16 window, UINT16 interval) +{ + UINT8 scan_mode = 0; + tBTM_INQUIRY_VAR_ST *p_inq = &btm_cb.btm_inq_vars; + + BTM_TRACE_API ("BTM_SetConnectability\n"); + +#if (BLE_INCLUDED == TRUE && BLE_INCLUDED == TRUE) + if (controller_get_interface()->supports_ble()) + { + if (btm_ble_set_connectability(page_mode) != BTM_SUCCESS) + { + return BTM_NO_RESOURCES; + } + p_inq->connectable_mode &= (~BTM_BLE_CONNECTABLE_MASK); + p_inq->connectable_mode |= (page_mode & BTM_BLE_CONNECTABLE_MASK); + } + page_mode &= ~BTM_BLE_CONNECTABLE_MASK; +#endif + + /*** Check mode parameter ***/ + if (page_mode != BTM_NON_CONNECTABLE && page_mode != BTM_CONNECTABLE) + return (BTM_ILLEGAL_VALUE); + + /* Make sure the controller is active */ + if (!controller_get_interface()->get_is_ready()) + return (BTM_DEV_RESET); + + /* If the window and/or interval is '0', set to default values */ + if (!window) + window = BTM_DEFAULT_CONN_WINDOW; + + if (!interval) + interval = BTM_DEFAULT_CONN_INTERVAL; + + BTM_TRACE_API ("BTM_SetConnectability: mode %d [NonConn-0, Conn-1], window 0x%04x, interval 0x%04x\n", + page_mode, window, interval); + + /*** Check for valid window and interval parameters ***/ + /*** Only check window and duration if mode is connectable ***/ + if (page_mode == BTM_CONNECTABLE) + { + /* window must be less than or equal to interval */ + if (window < HCI_MIN_PAGESCAN_WINDOW || + window > HCI_MAX_PAGESCAN_WINDOW || + interval < HCI_MIN_PAGESCAN_INTERVAL || + interval > HCI_MAX_PAGESCAN_INTERVAL || + window > interval) + { + return (BTM_ILLEGAL_VALUE); + } + + scan_mode |= HCI_PAGE_SCAN_ENABLED; + } + + if ((window != p_inq->page_scan_window) || + (interval != p_inq->page_scan_period)) + { + p_inq->page_scan_window = window; + p_inq->page_scan_period = interval; + if (!btsnd_hcic_write_pagescan_cfg (interval, window)) + return (BTM_NO_RESOURCES); + } + + /* Keep the inquiry scan as previouosly set */ + if (p_inq->discoverable_mode & BTM_DISCOVERABLE_MASK) + scan_mode |= HCI_INQUIRY_SCAN_ENABLED; + + if (btsnd_hcic_write_scan_enable (scan_mode)) + { + p_inq->connectable_mode &= (~BTM_CONNECTABLE_MASK); + p_inq->connectable_mode |= page_mode; + + return (BTM_SUCCESS); + } + + return (BTM_NO_RESOURCES); +} + + +/******************************************************************************* +** +** Function BTM_ReadConnectability +** +** Description This function is called to read the current discoverability +** mode of the device. +** Output Params p_window - current page scan duration +** p_interval - current time between page scans +** +** Returns BTM_NON_CONNECTABLE or BTM_CONNECTABLE +** +*******************************************************************************/ +UINT16 BTM_ReadConnectability (UINT16 *p_window, UINT16 *p_interval) +{ + BTM_TRACE_API ("BTM_ReadConnectability\n"); + if (p_window) + *p_window = btm_cb.btm_inq_vars.page_scan_window; + + if (p_interval) + *p_interval = btm_cb.btm_inq_vars.page_scan_period; + + return (btm_cb.btm_inq_vars.connectable_mode); +} + + + +/******************************************************************************* +** +** Function BTM_IsInquiryActive +** +** Description This function returns a bit mask of the current inquiry state +** +** Returns BTM_INQUIRY_INACTIVE if inactive (0) +** BTM_LIMITED_INQUIRY_ACTIVE if a limted inquiry is active +** BTM_GENERAL_INQUIRY_ACTIVE if a general inquiry is active +** BTM_PERIODIC_INQUIRY_ACTIVE if a periodic inquiry is active +** +*******************************************************************************/ +UINT16 BTM_IsInquiryActive (void) +{ + BTM_TRACE_API ("BTM_IsInquiryActive\n"); + + return(btm_cb.btm_inq_vars.inq_active); +} + + + +/******************************************************************************* +** +** Function BTM_CancelInquiry +** +** Description This function cancels an inquiry if active +** +** Returns BTM_SUCCESS if successful +** BTM_NO_RESOURCES if could not allocate a message buffer +** BTM_WRONG_MODE if the device is not up. +** +*******************************************************************************/ +tBTM_STATUS BTM_CancelInquiry(void) +{ + tBTM_STATUS status = BTM_SUCCESS; + tBTM_INQUIRY_VAR_ST *p_inq = &btm_cb.btm_inq_vars; +#if (defined(BTA_HOST_INTERLEAVE_SEARCH) && BTA_HOST_INTERLEAVE_SEARCH == TRUE) + UINT8 active_mode=p_inq->inq_active; +#endif + BTM_TRACE_API ("BTM_CancelInquiry called\n"); + + /*** Make sure the device is ready ***/ + if (!BTM_IsDeviceUp()) + return (BTM_WRONG_MODE); + + /* Only cancel if not in periodic mode, otherwise the caller should call BTM_CancelPeriodicMode */ + if ((p_inq->inq_active &BTM_INQUIRY_ACTIVE_MASK) != 0 && + (!(p_inq->inq_active & BTM_PERIODIC_INQUIRY_ACTIVE))) + { + p_inq->inq_active = BTM_INQUIRY_INACTIVE; + p_inq->state = BTM_INQ_INACTIVE_STATE; + p_inq->p_inq_results_cb = (tBTM_INQ_RESULTS_CB *) NULL; /* Do not notify caller anymore */ + p_inq->p_inq_cmpl_cb = (tBTM_CMPL_CB *) NULL; /* Do not notify caller anymore */ + + /* If the event filter is in progress, mark it so that the processing of the return + event will be ignored */ + if (p_inq->inqfilt_active) + { + p_inq->inqfilt_active = FALSE; + p_inq->pending_filt_complete_event++; + } + /* Initiate the cancel inquiry */ + else + { + if (((p_inq->inqparms.mode & BTM_BR_INQUIRY_MASK) != 0) +#if (defined(BTA_HOST_INTERLEAVE_SEARCH) && BTA_HOST_INTERLEAVE_SEARCH == TRUE) + &&(active_mode & BTM_BR_INQUIRY_MASK) +#endif + ) + { + if (!btsnd_hcic_inq_cancel()) + status = BTM_NO_RESOURCES; + } +#if BLE_INCLUDED == TRUE + if (((p_inq->inqparms.mode & BTM_BLE_INQUIRY_MASK) != 0) +#if (defined(BTA_HOST_INTERLEAVE_SEARCH) && BTA_HOST_INTERLEAVE_SEARCH == TRUE) + &&(active_mode & BTM_BLE_INQ_ACTIVE_MASK) +#endif + ) + btm_ble_stop_inquiry(); +#endif + } + + /* Do not send the BUSY_LEVEL event yet. Wait for the cancel_complete event + * and then send the BUSY_LEVEL event + * btm_acl_update_busy_level (BTM_BLI_INQ_DONE_EVT); + */ + + p_inq->inq_counter++; + btm_clr_inq_result_flt(); + } + + return (status); +} + + +/******************************************************************************* +** +** Function BTM_StartInquiry +** +** Description This function is called to start an inquiry. +** +** Parameters: p_inqparms - pointer to the inquiry information +** mode - GENERAL or LIMITED inquiry, BR/LE bit mask seperately +** duration - length in 1.28 sec intervals (If '0', the inquiry is CANCELLED) +** max_resps - maximum amount of devices to search for before ending the inquiry +** filter_cond_type - BTM_CLR_INQUIRY_FILTER, BTM_FILTER_COND_DEVICE_CLASS, or +** BTM_FILTER_COND_BD_ADDR +** filter_cond - value for the filter (based on filter_cond_type) +** +** p_results_cb - Pointer to the callback routine which gets called +** upon receipt of an inquiry result. If this field is +** NULL, the application is not notified. +** +** p_cmpl_cb - Pointer to the callback routine which gets called +** upon completion. If this field is NULL, the +** application is not notified when completed. +** Returns tBTM_STATUS +** BTM_CMD_STARTED if successfully initiated +** BTM_BUSY if already in progress +** BTM_ILLEGAL_VALUE if parameter(s) are out of range +** BTM_NO_RESOURCES if could not allocate resources to start the command +** BTM_WRONG_MODE if the device is not up. +** +*******************************************************************************/ +tBTM_STATUS BTM_StartInquiry (tBTM_INQ_PARMS *p_inqparms, tBTM_INQ_RESULTS_CB *p_results_cb, + tBTM_CMPL_CB *p_cmpl_cb) +{ + tBTM_STATUS status = BTM_CMD_STARTED; + tBTM_INQUIRY_VAR_ST *p_inq = &btm_cb.btm_inq_vars; + + BTM_TRACE_API ("BTM_StartInquiry: mode: %d, dur: %d, rsps: %d, flt: %d\n", + p_inqparms->mode, p_inqparms->duration, p_inqparms->max_resps, + p_inqparms->filter_cond_type); + + /* Only one active inquiry is allowed in this implementation. + Also do not allow an inquiry if the inquiry filter is being updated */ + if (p_inq->inq_active || p_inq->inqfilt_active) + { +#if (defined BLE_INCLUDED && BLE_INCLUDED == TRUE) + /*check if LE observe is already running*/ + if(p_inq->scan_type==INQ_LE_OBSERVE && p_inq->p_inq_ble_results_cb!=NULL) + { + BTM_TRACE_API("BTM_StartInquiry: LE observe in progress"); + p_inq->scan_type = INQ_GENERAL; + p_inq->inq_active = BTM_INQUIRY_INACTIVE; + btm_cb.ble_ctr_cb.inq_var.scan_type = BTM_BLE_SCAN_MODE_NONE; + btsnd_hcic_ble_set_scan_enable (BTM_BLE_SCAN_DISABLE, BTM_BLE_DUPLICATE_ENABLE); + } + else +#endif + { + return (BTM_BUSY); + BTM_TRACE_API("BTM_StartInquiry: return BUSY\n"); + } + } + else + p_inq->scan_type = INQ_GENERAL; + + /*** Make sure the device is ready ***/ + if (!BTM_IsDeviceUp()) + return (BTM_WRONG_MODE); + + if ((p_inqparms->mode & BTM_BR_INQUIRY_MASK)!= BTM_GENERAL_INQUIRY && + (p_inqparms->mode & BTM_BR_INQUIRY_MASK)!= BTM_LIMITED_INQUIRY +#if (BLE_INCLUDED == TRUE) + && (p_inqparms->mode & BTM_BLE_INQUIRY_MASK)!= BTM_BLE_GENERAL_INQUIRY + && (p_inqparms->mode & BTM_BLE_INQUIRY_MASK)!= BTM_BLE_LIMITED_INQUIRY +#endif + ) + return (BTM_ILLEGAL_VALUE); + +#if (defined(BTA_HOST_INTERLEAVE_SEARCH) && BTA_HOST_INTERLEAVE_SEARCH == TRUE) + if(p_inq->next_state==BTM_FINISH) + return BTM_ILLEGAL_VALUE; +#endif + + + /* Save the inquiry parameters to be used upon the completion of setting/clearing the inquiry filter */ + p_inq->inqparms = *p_inqparms; + + /* Initialize the inquiry variables */ + p_inq->state = BTM_INQ_ACTIVE_STATE; + p_inq->p_inq_cmpl_cb = p_cmpl_cb; + p_inq->p_inq_results_cb = p_results_cb; + p_inq->inq_cmpl_info.num_resp = 0; /* Clear the results counter */ + p_inq->inq_active = p_inqparms->mode; + + BTM_TRACE_DEBUG("BTM_StartInquiry: p_inq->inq_active = 0x%02x\n", p_inq->inq_active); + +/* interleave scan minimal conditions */ +#if (BLE_INCLUDED==TRUE && (defined(BTA_HOST_INTERLEAVE_SEARCH) && BTA_HOST_INTERLEAVE_SEARCH == TRUE)) + + /* check if both modes are present */ + if((p_inqparms->mode & BTM_BLE_INQUIRY_MASK) && (p_inqparms->mode & BTM_BR_INQUIRY_MASK)) + { + BTM_TRACE_API("BTM:Interleave Inquiry Mode Set\n"); + p_inqparms->duration=p_inqparms->intl_duration[p_inq->next_state]; + p_inq->inqparms.duration=p_inqparms->duration; + } + else + { + BTM_TRACE_API("BTM:Single Mode: No interleaving, Mode:0x%02x\n", p_inqparms->mode); + p_inq->next_state=BTM_NO_INTERLEAVING; + } +#endif + + + +/* start LE inquiry here if requested */ +#if BLE_INCLUDED == TRUE + if ((p_inqparms->mode & BTM_BLE_INQUIRY_MASK) +#if (defined(BTA_HOST_INTERLEAVE_SEARCH) && BTA_HOST_INTERLEAVE_SEARCH == TRUE) + &&(p_inq->next_state==BTM_BLE_ONE || p_inq->next_state==BTM_BLE_TWO || + p_inq->next_state==BTM_NO_INTERLEAVING) +#endif + ) + + { +#if (defined(BTA_HOST_INTERLEAVE_SEARCH) && BTA_HOST_INTERLEAVE_SEARCH == TRUE) + p_inq->inq_active = (p_inqparms->mode & BTM_BLE_INQUIRY_MASK); + BTM_TRACE_API("BTM:Starting LE Scan with duration %d and activeMode:0x%02x\n", + p_inqparms->duration, (p_inqparms->mode & BTM_BLE_INQUIRY_MASK)); +#endif + if (!controller_get_interface()->supports_ble()) + { + p_inq->inqparms.mode &= ~ BTM_BLE_INQUIRY_MASK; + status = BTM_ILLEGAL_VALUE; + } + /* BLE for now does not support filter condition for inquiry */ + else if ((status = btm_ble_start_inquiry((UINT8)(p_inqparms->mode & BTM_BLE_INQUIRY_MASK), + p_inqparms->duration)) != BTM_CMD_STARTED) + { + BTM_TRACE_ERROR("Err Starting LE Inquiry.\n"); + p_inq->inqparms.mode &= ~ BTM_BLE_INQUIRY_MASK; + } +#if (!defined(BTA_HOST_INTERLEAVE_SEARCH) || BTA_HOST_INTERLEAVE_SEARCH == FALSE) + p_inqparms->mode &= ~BTM_BLE_INQUIRY_MASK; +#endif + +#if (defined(BTA_HOST_INTERLEAVE_SEARCH) && BTA_HOST_INTERLEAVE_SEARCH == TRUE) + if(p_inq->next_state==BTM_NO_INTERLEAVING) + { + p_inq->next_state=BTM_FINISH; + } + else + { + BTM_TRACE_API("BTM:Interleaving: started LE scan, Advancing to next state: %d\n", + p_inq->next_state+1); + p_inq->next_state+=1; + } + /* reset next_state if status <> BTM_Started */ + if(status!=BTM_CMD_STARTED) + p_inq->next_state=BTM_BR_ONE; + + /* if interleave scan..return here */ + return status; +#endif + + + BTM_TRACE_DEBUG("BTM_StartInquiry: mode = %02x\n", p_inqparms->mode); + } +#endif /* end of BLE_INCLUDED */ + + /* we're done with this routine if BR/EDR inquiry is not desired. */ + if ((p_inqparms->mode & BTM_BR_INQUIRY_MASK) == BTM_INQUIRY_NONE) + return status; + + /* BR/EDR inquiry portion */ +#if (defined(BTA_HOST_INTERLEAVE_SEARCH) && BTA_HOST_INTERLEAVE_SEARCH == TRUE) + if((p_inq->next_state==BTM_BR_ONE || p_inq->next_state==BTM_BR_TWO || + p_inq->next_state==BTM_NO_INTERLEAVING )) + { + p_inq->inq_active = (p_inqparms->mode & BTM_BR_INQUIRY_MASK); +#endif + /* If a filter is specified, then save it for later and clear the current filter. + The setting of the filter is done upon completion of clearing of the previous + filter. + */ + switch (p_inqparms->filter_cond_type) + { + case BTM_CLR_INQUIRY_FILTER: + p_inq->state = BTM_INQ_SET_FILT_STATE; + break; + + case BTM_FILTER_COND_DEVICE_CLASS: + case BTM_FILTER_COND_BD_ADDR: + /* The filter is not being used so simply clear it; + the inquiry can start after this operation */ + p_inq->state = BTM_INQ_CLR_FILT_STATE; + p_inqparms->filter_cond_type = BTM_CLR_INQUIRY_FILTER; + /* =============>>>> adding LE filtering here ????? */ + break; + + default: + return (BTM_ILLEGAL_VALUE); + } + + /* Before beginning the inquiry the current filter must be cleared, so initiate the command */ + if ((status = btm_set_inq_event_filter (p_inqparms->filter_cond_type, + &p_inqparms->filter_cond)) != BTM_CMD_STARTED) + p_inq->state = BTM_INQ_INACTIVE_STATE; + +#if (defined(BTA_HOST_INTERLEAVE_SEARCH) && BTA_HOST_INTERLEAVE_SEARCH == TRUE) + if (p_inq->next_state==BTM_NO_INTERLEAVING) + p_inq->next_state=BTM_FINISH; + else + { + BTM_TRACE_API("BTM:Interleaving: Started BTM inq, Advancing to next state: %d\n", + p_inq->next_state+1); + p_inq->next_state+=1; + } + } + if (status!=BTM_CMD_STARTED) + { + /* Some error beginning the scan process. + Reset the next_state parameter.. Do we need to reset the inq_active also? + */ + BTM_TRACE_API("BTM:Interleaving: Error in Starting inquiry, status: 0x%02x\n", status); + p_inq->next_state=BTM_BR_ONE; + } +#endif + + + return (status); +} + + +/******************************************************************************* +** +** Function BTM_ReadRemoteDeviceName +** +** Description This function initiates a remote device HCI command to the +** controller and calls the callback when the process has completed. +** +** Input Params: remote_bda - device address of name to retrieve +** p_cb - callback function called when BTM_CMD_STARTED +** is returned. +** A pointer to tBTM_REMOTE_DEV_NAME is passed to the +** callback. +** +** Returns +** BTM_CMD_STARTED is returned if the request was successfully sent +** to HCI. +** BTM_BUSY if already in progress +** BTM_UNKNOWN_ADDR if device address is bad +** BTM_NO_RESOURCES if could not allocate resources to start the command +** BTM_WRONG_MODE if the device is not up. +** +*******************************************************************************/ +tBTM_STATUS BTM_ReadRemoteDeviceName (BD_ADDR remote_bda, tBTM_CMPL_CB *p_cb + ,tBT_TRANSPORT transport) +{ + tBTM_INQ_INFO *p_cur = NULL; + tINQ_DB_ENT *p_i; + + BTM_TRACE_API ("BTM_ReadRemoteDeviceName: bd addr [%02x%02x%02x%02x%02x%02x]\n", + remote_bda[0], remote_bda[1], remote_bda[2], + remote_bda[3], remote_bda[4], remote_bda[5]); + + /* Use the remote device's clock offset if it is in the local inquiry database */ + if ((p_i = btm_inq_db_find (remote_bda)) != NULL) + { + p_cur = &p_i->inq_info; + } + BTM_TRACE_API ("no device found in inquiry db\n"); + +#if (BLE_INCLUDED == TRUE) + if (transport == BT_TRANSPORT_LE) + { + return btm_ble_read_remote_name(remote_bda, p_cur, p_cb); + } + else +#endif + + return (btm_initiate_rem_name (remote_bda, p_cur, BTM_RMT_NAME_EXT, + BTM_EXT_RMT_NAME_TIMEOUT, p_cb)); +} + +/******************************************************************************* +** +** Function BTM_CancelRemoteDeviceName +** +** Description This function initiates the cancel request for the specified +** remote device. +** +** Input Params: None +** +** Returns +** BTM_CMD_STARTED is returned if the request was successfully sent +** to HCI. +** BTM_NO_RESOURCES if could not allocate resources to start the command +** BTM_WRONG_MODE if there is not an active remote name request. +** +*******************************************************************************/ +tBTM_STATUS BTM_CancelRemoteDeviceName (void) +{ + tBTM_INQUIRY_VAR_ST *p_inq = &btm_cb.btm_inq_vars; + + BTM_TRACE_API ("BTM_CancelRemoteDeviceName()\n"); + + /* Make sure there is not already one in progress */ + if (p_inq->remname_active) + { +#if BLE_INCLUDED == TRUE + if (BTM_UseLeLink(p_inq->remname_bda)) + { + if (btm_ble_cancel_remote_name(p_inq->remname_bda)) + return (BTM_CMD_STARTED); + else + return (BTM_UNKNOWN_ADDR); + } + else +#endif + if (btsnd_hcic_rmt_name_req_cancel (p_inq->remname_bda)) + return (BTM_CMD_STARTED); + else + return (BTM_NO_RESOURCES); + } + else + return (BTM_WRONG_MODE); +} + +/******************************************************************************* +** +** Function BTM_InqDbRead +** +** Description This function looks through the inquiry database for a match +** based on Bluetooth Device Address. This is the application's +** interface to get the inquiry details of a specific BD address. +** +** Returns pointer to entry, or NULL if not found +** +*******************************************************************************/ +tBTM_INQ_INFO *BTM_InqDbRead (BD_ADDR p_bda) +{ + BTM_TRACE_API ("BTM_InqDbRead: bd addr [%02x%02x%02x%02x%02x%02x]\n", + p_bda[0], p_bda[1], p_bda[2], p_bda[3], p_bda[4], p_bda[5]); + + tINQ_DB_ENT *p_ent = btm_inq_db_find(p_bda); + if (!p_ent) + return NULL; + + return &p_ent->inq_info; +} + + +/******************************************************************************* +** +** Function BTM_InqDbFirst +** +** Description This function looks through the inquiry database for the first +** used entry, and returns that. This is used in conjunction with +** BTM_InqDbNext by applications as a way to walk through the +** inquiry database. +** +** Returns pointer to first in-use entry, or NULL if DB is empty +** +*******************************************************************************/ +tBTM_INQ_INFO *BTM_InqDbFirst (void) +{ + UINT16 xx; + tINQ_DB_ENT *p_ent = btm_cb.btm_inq_vars.inq_db; + + for (xx = 0; xx < BTM_INQ_DB_SIZE; xx++, p_ent++) + { + if (p_ent->in_use) + return (&p_ent->inq_info); + } + + /* If here, no used entry found */ + return ((tBTM_INQ_INFO *)NULL); +} + + +/******************************************************************************* +** +** Function BTM_InqDbNext +** +** Description This function looks through the inquiry database for the next +** used entry, and returns that. If the input parameter is NULL, +** the first entry is returned. +** +** Returns pointer to next in-use entry, or NULL if no more found. +** +*******************************************************************************/ +tBTM_INQ_INFO *BTM_InqDbNext (tBTM_INQ_INFO *p_cur) +{ + tINQ_DB_ENT *p_ent; + UINT16 inx; + + if (p_cur) + { + p_ent = (tINQ_DB_ENT *) ((UINT8 *)p_cur - offsetof (tINQ_DB_ENT, inq_info)); + inx = (UINT16)((p_ent - btm_cb.btm_inq_vars.inq_db) + 1); + + for (p_ent = &btm_cb.btm_inq_vars.inq_db[inx]; inx < BTM_INQ_DB_SIZE; inx++, p_ent++) + { + if (p_ent->in_use) + return (&p_ent->inq_info); + } + + /* If here, more entries found */ + return ((tBTM_INQ_INFO *)NULL); + } + else + return (BTM_InqDbFirst()); +} + + +/******************************************************************************* +** +** Function BTM_ClearInqDb +** +** Description This function is called to clear out a device or all devices +** from the inquiry database. +** +** Parameter p_bda - (input) BD_ADDR -> Address of device to clear +** (NULL clears all entries) +** +** Returns BTM_BUSY if an inquiry, get remote name, or event filter +** is active, otherwise BTM_SUCCESS +** +*******************************************************************************/ +tBTM_STATUS BTM_ClearInqDb (BD_ADDR p_bda) +{ + tBTM_INQUIRY_VAR_ST *p_inq = &btm_cb.btm_inq_vars; + + /* If an inquiry or remote name is in progress return busy */ + if (p_inq->inq_active != BTM_INQUIRY_INACTIVE || + p_inq->inqfilt_active) + return (BTM_BUSY); + + btm_clr_inq_db(p_bda); + + return (BTM_SUCCESS); +} + +/******************************************************************************* +** +** Function BTM_ReadInquiryRspTxPower +** +** Description This command will read the inquiry Transmit Power level used +** to transmit the FHS and EIR data packets. +** This can be used directly in the Tx Power Level EIR data type. +** +** Returns BTM_SUCCESS if successful +** +*******************************************************************************/ +tBTM_STATUS BTM_ReadInquiryRspTxPower (tBTM_CMPL_CB *p_cb) +{ + if (btm_cb.devcb.p_txpwer_cmpl_cb) + return (BTM_BUSY); + + btu_start_timer (&btm_cb.devcb.txpwer_timer, BTU_TTYPE_BTM_ACL, BTM_INQ_REPLY_TIMEOUT ); + + + btm_cb.devcb.p_txpwer_cmpl_cb = p_cb; + + if (!btsnd_hcic_read_inq_tx_power ()) + { + btm_cb.devcb.p_txpwer_cmpl_cb = NULL; + btu_stop_timer (&btm_cb.devcb.txpwer_timer); + return (BTM_NO_RESOURCES); + } + else + return (BTM_CMD_STARTED); +} + +/********************************************************************************* +********************************************************************************** +** ** +** BTM Internal Inquiry Functions ** +** ** +********************************************************************************** +*********************************************************************************/ +/******************************************************************************* +** +** Function btm_inq_db_reset +** +** Description This function is called at at reset to clear the inquiry +** database & pending callback. +** +** Returns void +** +*******************************************************************************/ +void btm_inq_db_reset (void) +{ + tBTM_REMOTE_DEV_NAME rem_name; + tBTM_INQUIRY_VAR_ST *p_inq = &btm_cb.btm_inq_vars; + UINT8 num_responses; + UINT8 temp_inq_active; + tBTM_STATUS status; + + btu_stop_timer (&p_inq->inq_timer_ent); + + /* If an inquiry or periodic inquiry is active, reset the mode to inactive */ + if (p_inq->inq_active != BTM_INQUIRY_INACTIVE) + { + temp_inq_active = p_inq->inq_active; /* Save so state can change BEFORE + callback is called */ + p_inq->inq_active = BTM_INQUIRY_INACTIVE; + + /* If not a periodic inquiry, the complete callback must be called to notify caller */ + if (temp_inq_active == BTM_LIMITED_INQUIRY_ACTIVE || + temp_inq_active == BTM_GENERAL_INQUIRY_ACTIVE) + { + if (p_inq->p_inq_cmpl_cb) + { + num_responses = 0; + (*p_inq->p_inq_cmpl_cb)(&num_responses); + } + } + } + + /* Cancel a remote name request if active, and notify the caller (if waiting) */ + if (p_inq->remname_active ) + { + btu_stop_timer (&p_inq->rmt_name_timer_ent); + p_inq->remname_active = FALSE; + memset(p_inq->remname_bda, 0, BD_ADDR_LEN); + + if (p_inq->p_remname_cmpl_cb) + { + rem_name.status = BTM_DEV_RESET; + + (*p_inq->p_remname_cmpl_cb)(&rem_name); + p_inq->p_remname_cmpl_cb = NULL; + } + } + + /* Cancel an inquiry filter request if active, and notify the caller (if waiting) */ + if (p_inq->inqfilt_active) + { + p_inq->inqfilt_active = FALSE; + + if (p_inq->p_inqfilter_cmpl_cb) + { + status = BTM_DEV_RESET; + (*p_inq->p_inqfilter_cmpl_cb)(&status); + } + } + + p_inq->state = BTM_INQ_INACTIVE_STATE; + p_inq->pending_filt_complete_event = 0; + p_inq->p_inq_results_cb = NULL; + btm_clr_inq_db(NULL); /* Clear out all the entries in the database */ + btm_clr_inq_result_flt(); + + p_inq->discoverable_mode = BTM_NON_DISCOVERABLE; + p_inq->connectable_mode = BTM_NON_CONNECTABLE; + p_inq->page_scan_type = BTM_SCAN_TYPE_STANDARD; + p_inq->inq_scan_type = BTM_SCAN_TYPE_STANDARD; + +#if BLE_INCLUDED == TRUE + p_inq->discoverable_mode |= BTM_BLE_NON_DISCOVERABLE; + p_inq->connectable_mode |= BTM_BLE_NON_CONNECTABLE; +#endif + return; +} + + +/********************************************************************************* +** +** Function btm_inq_db_init +** +** Description This function is called at startup to initialize the inquiry +** database. +** +** Returns void +** +*******************************************************************************/ +void btm_inq_db_init (void) +{ +#if 0 /* cleared in btm_init; put back in if called from anywhere else! */ + memset (&btm_cb.btm_inq_vars, 0, sizeof (tBTM_INQUIRY_VAR_ST)); +#endif + btm_cb.btm_inq_vars.no_inc_ssp = BTM_NO_SSP_ON_INQUIRY; +} + +/********************************************************************************* +** +** Function btm_inq_stop_on_ssp +** +** Description This function is called on incoming SSP +** +** Returns void +** +*******************************************************************************/ +void btm_inq_stop_on_ssp(void) +{ + UINT8 normal_active = (BTM_GENERAL_INQUIRY_ACTIVE|BTM_LIMITED_INQUIRY_ACTIVE); + +#if (BTM_INQ_DEBUG == TRUE) + BTM_TRACE_DEBUG ("btm_inq_stop_on_ssp: no_inc_ssp=%d inq_active:0x%x state:%d inqfilt_active:%d\n", + btm_cb.btm_inq_vars.no_inc_ssp, btm_cb.btm_inq_vars.inq_active, btm_cb.btm_inq_vars.state, btm_cb.btm_inq_vars.inqfilt_active); +#endif + if (btm_cb.btm_inq_vars.no_inc_ssp) + { + if (btm_cb.btm_inq_vars.state == BTM_INQ_ACTIVE_STATE) + { + if (btm_cb.btm_inq_vars.inq_active & BTM_PERIODIC_INQUIRY_ACTIVE) + { + BTM_CancelPeriodicInquiry(); + } + else if (btm_cb.btm_inq_vars.inq_active & normal_active) + { + /* can not call BTM_CancelInquiry() here. We need to report inquiry complete evt */ + btsnd_hcic_inq_cancel(); + } + } + /* do not allow inquiry to start */ + btm_cb.btm_inq_vars.inq_active |= BTM_SSP_INQUIRY_ACTIVE; + } +} + +/********************************************************************************* +** +** Function btm_inq_clear_ssp +** +** Description This function is called when pairing_state becomes idle +** +** Returns void +** +*******************************************************************************/ +void btm_inq_clear_ssp(void) +{ + btm_cb.btm_inq_vars.inq_active &= ~BTM_SSP_INQUIRY_ACTIVE; +} + +/********************************************************************************* +** +** Function btm_clr_inq_db +** +** Description This function is called to clear out a device or all devices +** from the inquiry database. +** +** Parameter p_bda - (input) BD_ADDR -> Address of device to clear +** (NULL clears all entries) +** +** Returns void +** +*******************************************************************************/ +void btm_clr_inq_db (BD_ADDR p_bda) +{ + tBTM_INQUIRY_VAR_ST *p_inq = &btm_cb.btm_inq_vars; + tINQ_DB_ENT *p_ent = p_inq->inq_db; + UINT16 xx; + +#if (BTM_INQ_DEBUG == TRUE) + BTM_TRACE_DEBUG ("btm_clr_inq_db: inq_active:0x%x state:%d\n", + btm_cb.btm_inq_vars.inq_active, btm_cb.btm_inq_vars.state); +#endif + for (xx = 0; xx < BTM_INQ_DB_SIZE; xx++, p_ent++) + { + if (p_ent->in_use) + { + /* If this is the specified BD_ADDR or clearing all devices */ + if (p_bda == NULL || + (!memcmp (p_ent->inq_info.results.remote_bd_addr, p_bda, BD_ADDR_LEN))) + { + p_ent->in_use = FALSE; + } + } + } +#if (BTM_INQ_DEBUG == TRUE) + BTM_TRACE_DEBUG ("inq_active:0x%x state:%d\n", + btm_cb.btm_inq_vars.inq_active, btm_cb.btm_inq_vars.state); +#endif +} + + +/******************************************************************************* +** +** Function btm_clr_inq_result_flt +** +** Description This function looks through the bdaddr database for a match +** based on Bluetooth Device Address +** +** Returns TRUE if found, else FALSE (new entry) +** +*******************************************************************************/ +static void btm_clr_inq_result_flt (void) +{ + tBTM_INQUIRY_VAR_ST *p_inq = &btm_cb.btm_inq_vars; + + if (p_inq->p_bd_db) + { + GKI_freebuf(p_inq->p_bd_db); + p_inq->p_bd_db = NULL; + } + p_inq->num_bd_entries = 0; + p_inq->max_bd_entries = 0; +} + +/******************************************************************************* +** +** Function btm_inq_find_bdaddr +** +** Description This function looks through the bdaddr database for a match +** based on Bluetooth Device Address +** +** Returns TRUE if found, else FALSE (new entry) +** +*******************************************************************************/ +BOOLEAN btm_inq_find_bdaddr (BD_ADDR p_bda) +{ + tBTM_INQUIRY_VAR_ST *p_inq = &btm_cb.btm_inq_vars; + tINQ_BDADDR *p_db = &p_inq->p_bd_db[0]; + UINT16 xx; + + /* Don't bother searching, database doesn't exist or periodic mode */ + if ((p_inq->inq_active & BTM_PERIODIC_INQUIRY_ACTIVE) || !p_db) + return (FALSE); + + for (xx = 0; xx < p_inq->num_bd_entries; xx++, p_db++) + { + if (!memcmp(p_db->bd_addr, p_bda, BD_ADDR_LEN) + && p_db->inq_count == p_inq->inq_counter) + return (TRUE); + } + + if (xx < p_inq->max_bd_entries) + { + p_db->inq_count = p_inq->inq_counter; + memcpy(p_db->bd_addr, p_bda, BD_ADDR_LEN); + p_inq->num_bd_entries++; + } + + /* If here, New Entry */ + return (FALSE); +} + +/******************************************************************************* +** +** Function btm_inq_db_find +** +** Description This function looks through the inquiry database for a match +** based on Bluetooth Device Address +** +** Returns pointer to entry, or NULL if not found +** +*******************************************************************************/ +tINQ_DB_ENT *btm_inq_db_find (BD_ADDR p_bda) +{ + UINT16 xx; + tINQ_DB_ENT *p_ent = btm_cb.btm_inq_vars.inq_db; + + for (xx = 0; xx < BTM_INQ_DB_SIZE; xx++, p_ent++) + { + if ((p_ent->in_use) && (!memcmp (p_ent->inq_info.results.remote_bd_addr, p_bda, BD_ADDR_LEN))) + return (p_ent); + } + + /* If here, not found */ + return (NULL); +} + + +/******************************************************************************* +** +** Function btm_inq_db_new +** +** Description This function looks through the inquiry database for an unused +** entry. If no entry is free, it allocates the oldest entry. +** +** Returns pointer to entry +** +*******************************************************************************/ +tINQ_DB_ENT *btm_inq_db_new (BD_ADDR p_bda) +{ + UINT16 xx; + tINQ_DB_ENT *p_ent = btm_cb.btm_inq_vars.inq_db; + tINQ_DB_ENT *p_old = btm_cb.btm_inq_vars.inq_db; + UINT32 ot = 0xFFFFFFFF; + + for (xx = 0; xx < BTM_INQ_DB_SIZE; xx++, p_ent++) + { + if (!p_ent->in_use) + { + memset (p_ent, 0, sizeof (tINQ_DB_ENT)); + memcpy (p_ent->inq_info.results.remote_bd_addr, p_bda, BD_ADDR_LEN); + p_ent->in_use = TRUE; + + return (p_ent); + } + + if (p_ent->time_of_resp < ot) + { + p_old = p_ent; + ot = p_ent->time_of_resp; + } + } + + /* If here, no free entry found. Return the oldest. */ + + memset (p_old, 0, sizeof (tINQ_DB_ENT)); + memcpy (p_old->inq_info.results.remote_bd_addr, p_bda, BD_ADDR_LEN); + p_old->in_use = TRUE; + + return (p_old); +} + + +/******************************************************************************* +** +** Function btm_set_inq_event_filter +** +** Description This function is called to set the inquiry event filter. +** It is called by either internally, or by the external API function +** (BTM_SetInqEventFilter). It is used internally as part of the +** inquiry processing. +** +** Input Params: +** filter_cond_type - this is the type of inquiry filter to apply: +** BTM_FILTER_COND_DEVICE_CLASS, +** BTM_FILTER_COND_BD_ADDR, or +** BTM_CLR_INQUIRY_FILTER +** +** p_filt_cond - this is either a BD_ADDR or DEV_CLASS depending on the +** filter_cond_type (See section 4.7.3 of Core Spec 1.0b). +** +** Returns BTM_CMD_STARTED if successfully initiated +** BTM_NO_RESOURCES if couldn't get a memory pool buffer +** BTM_ILLEGAL_VALUE if a bad parameter was detected +** +*******************************************************************************/ +static tBTM_STATUS btm_set_inq_event_filter (UINT8 filter_cond_type, + tBTM_INQ_FILT_COND *p_filt_cond) +{ + UINT8 condition_length = DEV_CLASS_LEN * 2; + UINT8 condition_buf[DEV_CLASS_LEN * 2]; + UINT8 *p_cond = condition_buf; /* points to the condition to pass to HCI */ + +#if (BTM_INQ_DEBUG == TRUE) + BTM_TRACE_DEBUG ("btm_set_inq_event_filter: filter type %d [Clear-0, COD-1, BDADDR-2]\n", + filter_cond_type); + BTM_TRACE_DEBUG (" condition [%02x%02x%02x %02x%02x%02x]\n", + p_filt_cond->bdaddr_cond[0], p_filt_cond->bdaddr_cond[1], p_filt_cond->bdaddr_cond[2], + p_filt_cond->bdaddr_cond[3], p_filt_cond->bdaddr_cond[4], p_filt_cond->bdaddr_cond[5]); +#endif + + /* Load the correct filter condition to pass to the lower layer */ + switch (filter_cond_type) + { + case BTM_FILTER_COND_DEVICE_CLASS: + /* copy the device class and device class fields into contiguous memory to send to HCI */ + memcpy (condition_buf, p_filt_cond->cod_cond.dev_class, DEV_CLASS_LEN); + memcpy (&condition_buf[DEV_CLASS_LEN], + p_filt_cond->cod_cond.dev_class_mask, DEV_CLASS_LEN); + + /* condition length should already be set as the default */ + break; + + case BTM_FILTER_COND_BD_ADDR: + p_cond = p_filt_cond->bdaddr_cond; + + /* condition length should already be set as the default */ + break; + + case BTM_CLR_INQUIRY_FILTER: + condition_length = 0; + break; + + default: + return (BTM_ILLEGAL_VALUE); /* Bad parameter was passed in */ + } + + btm_cb.btm_inq_vars.inqfilt_active = TRUE; + + /* Filter the inquiry results for the specified condition type and value */ + if (btsnd_hcic_set_event_filter(HCI_FILTER_INQUIRY_RESULT, filter_cond_type, + p_cond, condition_length)) + + return (BTM_CMD_STARTED); + else + return (BTM_NO_RESOURCES); +} + + +/******************************************************************************* +** +** Function btm_event_filter_complete +** +** Description This function is called when a set event filter has completed. +** Note: This routine currently only handles inquiry filters. +** Connection filters are ignored for now. +** +** Returns void +** +*******************************************************************************/ +void btm_event_filter_complete (UINT8 *p) +{ + UINT8 hci_status; + tBTM_STATUS status; + tBTM_INQUIRY_VAR_ST *p_inq = &btm_cb.btm_inq_vars; + tBTM_CMPL_CB *p_cb = p_inq->p_inqfilter_cmpl_cb; + +#if (BTM_INQ_DEBUG == TRUE) + BTM_TRACE_DEBUG ("btm_event_filter_complete: inq_active:0x%x state:%d inqfilt_active:%d\n", + btm_cb.btm_inq_vars.inq_active, btm_cb.btm_inq_vars.state, btm_cb.btm_inq_vars.inqfilt_active); +#endif + /* If the filter complete event is from an old or cancelled request, ignore it */ + if(p_inq->pending_filt_complete_event) + { + p_inq->pending_filt_complete_event--; + return; + } + + /* Only process the inquiry filter; Ignore the connection filter until it + is used by the upper layers */ + if (p_inq->inqfilt_active == TRUE ) + { + /* Extract the returned status from the buffer */ + STREAM_TO_UINT8 (hci_status, p); + if (hci_status != HCI_SUCCESS) + { + /* If standalone operation, return the error status; if embedded in the inquiry, continue the inquiry */ + BTM_TRACE_WARNING ("BTM Warning: Set Event Filter Failed (HCI returned 0x%x)\n", hci_status); + status = BTM_ERR_PROCESSING; + } + else + status = BTM_SUCCESS; + + /* If the set filter was initiated externally (via BTM_SetInqEventFilter), call the + callback function to notify the initiator that it has completed */ + if (p_inq->state == BTM_INQ_INACTIVE_STATE) + { + p_inq->inqfilt_active = FALSE; + if (p_cb) + (*p_cb) (&status); + } + else /* An inquiry is active (the set filter command was internally generated), + process the next state of the process (Set a new filter or start the inquiry). */ + { + if(status != BTM_SUCCESS) + { + /* Process the inquiry complete (Error Status) */ + btm_process_inq_complete (BTM_ERR_PROCESSING, (UINT8)(p_inq->inqparms.mode & BTM_BR_INQUIRY_MASK)); + + /* btm_process_inq_complete() does not restore the following settings on periodic inquiry */ + p_inq->inqfilt_active = FALSE; + p_inq->inq_active = BTM_INQUIRY_INACTIVE; + p_inq->state = BTM_INQ_INACTIVE_STATE; + + return; + } + + /* Check to see if a new filter needs to be set up */ + if (p_inq->state == BTM_INQ_CLR_FILT_STATE) + { + if ((status = btm_set_inq_event_filter (p_inq->inqparms.filter_cond_type, &p_inq->inqparms.filter_cond)) == BTM_CMD_STARTED) + { + p_inq->state = BTM_INQ_SET_FILT_STATE; + } + else /* Error setting the filter: Call the initiator's callback function to indicate a failure */ + { + p_inq->inqfilt_active = FALSE; + + /* Process the inquiry complete (Error Status) */ + btm_process_inq_complete (BTM_ERR_PROCESSING, (UINT8)(p_inq->inqparms.mode & BTM_BR_INQUIRY_MASK)); + } + } + else /* Initiate the Inquiry or Periodic Inquiry */ + { + p_inq->state = BTM_INQ_ACTIVE_STATE; + p_inq->inqfilt_active = FALSE; + btm_initiate_inquiry (p_inq); + } + } + } +} + + +/******************************************************************************* +** +** Function btm_initiate_inquiry +** +** Description This function is called to start an inquiry or periodic inquiry +** upon completion of the setting and/or clearing of the inquiry filter. +** +** Inputs: p_inq (btm_cb.btm_inq_vars) - pointer to saved inquiry information +** mode - GENERAL or LIMITED inquiry +** duration - length in 1.28 sec intervals (If '0', the inquiry is CANCELLED) +** max_resps - maximum amount of devices to search for before ending the inquiry +** filter_cond_type - BTM_CLR_INQUIRY_FILTER, BTM_FILTER_COND_DEVICE_CLASS, or +** BTM_FILTER_COND_BD_ADDR +** filter_cond - value for the filter (based on filter_cond_type) +** +** Returns If an error occurs the initiator's callback is called with the error status. +** +*******************************************************************************/ +static void btm_initiate_inquiry (tBTM_INQUIRY_VAR_ST *p_inq) +{ + const LAP *lap; + tBTM_INQ_PARMS *p_inqparms = &p_inq->inqparms; + +#if (BTM_INQ_DEBUG == TRUE) + BTM_TRACE_DEBUG ("btm_initiate_inquiry: inq_active:0x%x state:%d inqfilt_active:%d\n", + btm_cb.btm_inq_vars.inq_active, btm_cb.btm_inq_vars.state, btm_cb.btm_inq_vars.inqfilt_active); +#endif + btm_acl_update_busy_level (BTM_BLI_INQ_EVT); + + if (p_inq->inq_active & BTM_SSP_INQUIRY_ACTIVE) + { + btm_process_inq_complete (BTM_NO_RESOURCES, (UINT8)(p_inqparms->mode & BTM_BR_INQUIRY_MASK)); + return; + } + + /* Make sure the number of responses doesn't overflow the database configuration */ + p_inqparms->max_resps = (UINT8)((p_inqparms->max_resps <= BTM_INQ_DB_SIZE) ? p_inqparms->max_resps : BTM_INQ_DB_SIZE); + + lap = (p_inq->inq_active & BTM_LIMITED_INQUIRY_ACTIVE) ? &limited_inq_lap : &general_inq_lap; + + if (p_inq->inq_active & BTM_PERIODIC_INQUIRY_ACTIVE) + { + if (!btsnd_hcic_per_inq_mode (p_inq->per_max_delay, + p_inq->per_min_delay, + *lap, p_inqparms->duration, + p_inqparms->max_resps)) + btm_process_inq_complete (BTM_NO_RESOURCES, (UINT8)(p_inqparms->mode & BTM_BR_INQUIRY_MASK)); + } + else + { + btm_clr_inq_result_flt(); + + /* Allocate memory to hold bd_addrs responding */ + if ((p_inq->p_bd_db = (tINQ_BDADDR *)GKI_getbuf(GKI_MAX_BUF_SIZE)) != NULL) + { + p_inq->max_bd_entries = (UINT16)(GKI_MAX_BUF_SIZE / sizeof(tINQ_BDADDR)); + memset(p_inq->p_bd_db, 0, GKI_MAX_BUF_SIZE); +/* BTM_TRACE_DEBUG("btm_initiate_inquiry: memory allocated for %d bdaddrs", + p_inq->max_bd_entries); */ + } + + if (!btsnd_hcic_inquiry(*lap, p_inqparms->duration, 0)) + btm_process_inq_complete (BTM_NO_RESOURCES, (UINT8)(p_inqparms->mode & BTM_BR_INQUIRY_MASK)); + } +} + +/******************************************************************************* +** +** Function btm_process_inq_results +** +** Description This function is called when inquiry results are received from +** the device. It updates the inquiry database. If the inquiry +** database is full, the oldest entry is discarded. +** +** Parameters inq_res_mode - BTM_INQ_RESULT_STANDARD +** BTM_INQ_RESULT_WITH_RSSI +** BTM_INQ_RESULT_EXTENDED +** +** Returns void +** +*******************************************************************************/ +void btm_process_inq_results (UINT8 *p, UINT8 inq_res_mode) +{ + UINT8 num_resp, xx; + BD_ADDR bda; + tINQ_DB_ENT *p_i; + tBTM_INQ_RESULTS *p_cur=NULL; + BOOLEAN is_new = TRUE; + BOOLEAN update = FALSE; + INT8 i_rssi; + tBTM_INQUIRY_VAR_ST *p_inq = &btm_cb.btm_inq_vars; + tBTM_INQ_RESULTS_CB *p_inq_results_cb = p_inq->p_inq_results_cb; + UINT8 page_scan_rep_mode = 0; + UINT8 page_scan_per_mode = 0; + UINT8 page_scan_mode = 0; + UINT8 rssi = 0; + DEV_CLASS dc; + UINT16 clock_offset; + UINT8 *p_eir_data = NULL; + +#if (BTM_INQ_DEBUG == TRUE) + BTM_TRACE_DEBUG ("btm_process_inq_results inq_active:0x%x state:%d inqfilt_active:%d inq_res_mode=%d\n", + btm_cb.btm_inq_vars.inq_active, btm_cb.btm_inq_vars.state, btm_cb.btm_inq_vars.inqfilt_active, inq_res_mode); +#endif + /* Only process the results if the BR inquiry is still active */ + if (!(p_inq->inq_active & BTM_BR_INQ_ACTIVE_MASK)) + return; + + STREAM_TO_UINT8 (num_resp, p); + + for (xx = 0; xx < num_resp; xx++) + { + update = FALSE; + /* Extract inquiry results */ + STREAM_TO_BDADDR (bda, p); + STREAM_TO_UINT8 (page_scan_rep_mode, p); + STREAM_TO_UINT8 (page_scan_per_mode, p); + + if (inq_res_mode == BTM_INQ_RESULT_STANDARD) + { + STREAM_TO_UINT8(page_scan_mode, p); + } + + STREAM_TO_DEVCLASS (dc, p); + STREAM_TO_UINT16 (clock_offset, p); + if (inq_res_mode != BTM_INQ_RESULT_STANDARD) + { + STREAM_TO_UINT8(rssi, p); + } + + p_i = btm_inq_db_find (bda); + + /* Only process the num_resp is smaller than max_resps. + If results are queued to BTU task while canceling inquiry, + or when more than one result is in this response, > max_resp + responses could be processed which can confuse some apps + */ + if (p_inq->inqparms.max_resps && + p_inq->inq_cmpl_info.num_resp >= p_inq->inqparms.max_resps +#if BLE_INCLUDED == TRUE + /* new device response */ + && ( p_i == NULL || + /* exisiting device with BR/EDR info */ + (p_i && (p_i->inq_info.results.device_type & BT_DEVICE_TYPE_BREDR) != 0) + ) +#endif + + ) + { + BTM_TRACE_WARNING("INQ RES: Extra Response Received...ignoring\n"); + return; + } + + /* Check if this address has already been processed for this inquiry */ + if (btm_inq_find_bdaddr(bda)) + { + BTM_TRACE_DEBUG("BDA seen before [%02x%02x %02x%02x %02x%02x]\n", + bda[0], bda[1], bda[2], bda[3], bda[4], bda[5]); + /* By default suppose no update needed */ + i_rssi = (INT8)rssi; + + /* If this new RSSI is higher than the last one */ + if(p_inq->inqparms.report_dup && (rssi != 0) && + p_i && (i_rssi > p_i->inq_info.results.rssi || p_i->inq_info.results.rssi == 0 +#if BLE_INCLUDED == TRUE + /* BR/EDR inquiry information update */ + || (p_i->inq_info.results.device_type & BT_DEVICE_TYPE_BREDR) != 0 +#endif + )) + { + p_cur = &p_i->inq_info.results; + BTM_TRACE_DEBUG("update RSSI new:%d, old:%d\n", i_rssi, p_cur->rssi); + p_cur->rssi = i_rssi; + update = TRUE; + } + /* If we received a second Extended Inq Event for an already */ + /* discovered device, this is because for the first one EIR was not received */ + else if ((inq_res_mode == BTM_INQ_RESULT_EXTENDED) && (p_i)) + { + p_cur = &p_i->inq_info.results; + update = TRUE; + } + /* If no update needed continue with next response (if any) */ + else + continue; + } + + /* If existing entry, use that, else get a new one (possibly reusing the oldest) */ + if (p_i == NULL) + { + p_i = btm_inq_db_new (bda); + is_new = TRUE; + } + + /* If an entry for the device already exists, overwrite it ONLY if it is from + a previous inquiry. (Ignore it if it is a duplicate response from the same + inquiry. + */ + else if (p_i->inq_count == p_inq->inq_counter +#if (BLE_INCLUDED == TRUE ) + && (p_i->inq_info.results.device_type == BT_DEVICE_TYPE_BREDR) +#endif + ) + is_new = FALSE; + + /* keep updating RSSI to have latest value */ + if( inq_res_mode != BTM_INQ_RESULT_STANDARD ) + p_i->inq_info.results.rssi = (INT8)rssi; + else + p_i->inq_info.results.rssi = BTM_INQ_RES_IGNORE_RSSI; + + if (is_new == TRUE) + { + /* Save the info */ + p_cur = &p_i->inq_info.results; + p_cur->page_scan_rep_mode = page_scan_rep_mode; + p_cur->page_scan_per_mode = page_scan_per_mode; + p_cur->page_scan_mode = page_scan_mode; + p_cur->dev_class[0] = dc[0]; + p_cur->dev_class[1] = dc[1]; + p_cur->dev_class[2] = dc[2]; + p_cur->clock_offset = clock_offset | BTM_CLOCK_OFFSET_VALID; + + p_i->time_of_resp = GKI_get_os_tick_count(); + + if (p_i->inq_count != p_inq->inq_counter) + p_inq->inq_cmpl_info.num_resp++; /* A new response was found */ + +#if (defined BLE_INCLUDED && BLE_INCLUDED == TRUE) + p_cur->inq_result_type = BTM_INQ_RESULT_BR; + if (p_i->inq_count != p_inq->inq_counter) + { + p_cur->device_type = BT_DEVICE_TYPE_BREDR; + p_i->scan_rsp = FALSE; + } + else + p_cur->device_type |= BT_DEVICE_TYPE_BREDR; +#endif + p_i->inq_count = p_inq->inq_counter; /* Mark entry for current inquiry */ + + /* If the number of responses found and not unlimited, issue a cancel inquiry */ + if (!(p_inq->inq_active & BTM_PERIODIC_INQUIRY_ACTIVE) && + p_inq->inqparms.max_resps && + p_inq->inq_cmpl_info.num_resp == p_inq->inqparms.max_resps +#if BLE_INCLUDED == TRUE + /* BLE scanning is active and received adv */ + && ((((p_inq->inqparms.mode & BTM_BLE_INQUIRY_MASK) != 0) && + p_cur->device_type == BT_DEVICE_TYPE_DUMO && p_i->scan_rsp) || + (p_inq->inqparms.mode & BTM_BLE_INQUIRY_MASK) == 0) +#endif + ) + { +/* BTM_TRACE_DEBUG("BTMINQ: Found devices, cancelling inquiry..."); */ + btsnd_hcic_inq_cancel(); + +#if BLE_INCLUDED == TRUE + if ((p_inq->inqparms.mode & BTM_BLE_INQUIRY_MASK) != 0) + btm_ble_stop_inquiry(); +#endif + btm_acl_update_busy_level (BTM_BLI_INQ_DONE_EVT); + } + /* Initialize flag to FALSE. This flag is set/used by application */ + p_i->inq_info.appl_knows_rem_name = FALSE; + } + + if (is_new || update) + { + if( inq_res_mode == BTM_INQ_RESULT_EXTENDED ) + { + memset( p_cur->eir_uuid, 0, + BTM_EIR_SERVICE_ARRAY_SIZE * (BTM_EIR_ARRAY_BITS/8)); + /* set bit map of UUID list from received EIR */ + btm_set_eir_uuid( p, p_cur ); + p_eir_data = p; + } + else + p_eir_data = NULL; + + /* If a callback is registered, call it with the results */ + if (p_inq_results_cb) + (p_inq_results_cb)((tBTM_INQ_RESULTS *) p_cur, p_eir_data); + } + } +} + +/******************************************************************************* +** +** Function btm_sort_inq_result +** +** Description This function is called when inquiry complete is received +** from the device to sort inquiry results based on rssi. +** +** Returns void +** +*******************************************************************************/ +void btm_sort_inq_result(void) +{ + UINT8 xx, yy, num_resp; + tINQ_DB_ENT *p_tmp = NULL; + tINQ_DB_ENT *p_ent = btm_cb.btm_inq_vars.inq_db; + tINQ_DB_ENT *p_next = btm_cb.btm_inq_vars.inq_db+1; + int size; + + num_resp = (btm_cb.btm_inq_vars.inq_cmpl_info.num_respinq_info.results.rssi < p_next->inq_info.results.rssi) + { + memcpy (p_tmp, p_next, size); + memcpy (p_next, p_ent, size); + memcpy (p_ent, p_tmp, size); + } + } + } + + GKI_freebuf(p_tmp); + } +} + +/******************************************************************************* +** +** Function btm_process_inq_complete +** +** Description This function is called when inquiry complete is received +** from the device. Call the callback if not in periodic inquiry +** mode AND it is not NULL (The caller wants the event). +** +** The callback pass back the status and the number of responses +** +** Returns void +** +*******************************************************************************/ +void btm_process_inq_complete (UINT8 status, UINT8 mode) +{ + tBTM_CMPL_CB *p_inq_cb = btm_cb.btm_inq_vars.p_inq_cmpl_cb; + tBTM_INQUIRY_VAR_ST *p_inq = &btm_cb.btm_inq_vars; + +#if (defined(BTA_HOST_INTERLEAVE_SEARCH) && BTA_HOST_INTERLEAVE_SEARCH == TRUE) + /* inquiry inactive case happens when inquiry is cancelled. + Make mode 0 for no further inquiries from the current inquiry process + */ + if(status!=HCI_SUCCESS || p_inq->next_state==BTM_FINISH || !p_inq->inq_active) + { + /* re-initialize for next inquiry request */ + p_inq->next_state=BTM_BR_ONE; + /* make the mode 0 here */ + p_inq->inqparms.mode &= ~(p_inq->inqparms.mode); + + } +#endif + +#if (!defined(BTA_HOST_INTERLEAVE_SEARCH) || BTA_HOST_INTERLEAVE_SEARCH == FALSE) + p_inq->inqparms.mode &= ~(mode); +#endif + + if(p_inq->scan_type == INQ_LE_OBSERVE && !p_inq->inq_active) + { + /*end of LE observe*/ + p_inq->p_inq_ble_results_cb = (tBTM_INQ_RESULTS_CB *) NULL; + p_inq->p_inq_ble_cmpl_cb = (tBTM_CMPL_CB *) NULL; + p_inq->scan_type=INQ_NONE; + } + + +#if (BTM_INQ_DEBUG == TRUE) + BTM_TRACE_DEBUG ("btm_process_inq_complete inq_active:0x%x state:%d inqfilt_active:%d\n", + btm_cb.btm_inq_vars.inq_active, btm_cb.btm_inq_vars.state, btm_cb.btm_inq_vars.inqfilt_active); +#endif + btm_acl_update_busy_level (BTM_BLI_INQ_DONE_EVT); + /* Ignore any stray or late complete messages if the inquiry is not active */ + if (p_inq->inq_active) + { + p_inq->inq_cmpl_info.status = (tBTM_STATUS)((status == HCI_SUCCESS) ? BTM_SUCCESS : BTM_ERR_PROCESSING); + + /* Notify caller that the inquiry has completed; (periodic inquiries do not send completion events */ + if (!(p_inq->inq_active & BTM_PERIODIC_INQUIRY_ACTIVE) && p_inq->inqparms.mode == 0) + { +#if BLE_INCLUDED == TRUE + btm_clear_all_pending_le_entry(); +#endif + p_inq->state = BTM_INQ_INACTIVE_STATE; + + /* Increment so the start of a next inquiry has a new count */ + p_inq->inq_counter++; + + btm_clr_inq_result_flt(); + + if((p_inq->inq_cmpl_info.status == BTM_SUCCESS) && + controller_get_interface()->supports_rssi_with_inquiry_results()) + { + btm_sort_inq_result(); + } + + /* Clear the results callback if set */ + p_inq->p_inq_results_cb = (tBTM_INQ_RESULTS_CB *) NULL; + p_inq->inq_active = BTM_INQUIRY_INACTIVE; + p_inq->p_inq_cmpl_cb = (tBTM_CMPL_CB *) NULL; + + /* If we have a callback registered for inquiry complete, call it */ + BTM_TRACE_DEBUG ("BTM Inq Compl Callback: status 0x%02x, num results %d\n", + p_inq->inq_cmpl_info.status, p_inq->inq_cmpl_info.num_resp); + + if (p_inq_cb) + (p_inq_cb)((tBTM_INQUIRY_CMPL *) &p_inq->inq_cmpl_info); + } +#if (defined(BTA_HOST_INTERLEAVE_SEARCH) && BTA_HOST_INTERLEAVE_SEARCH == TRUE) + if(p_inq->inqparms.mode != 0 && !(p_inq->inq_active & BTM_PERIODIC_INQUIRY_ACTIVE)) + { + /* make inquiry inactive for next iteration */ + p_inq->inq_active = BTM_INQUIRY_INACTIVE; + /* call the inquiry again */ + BTM_StartInquiry(&p_inq->inqparms,p_inq->p_inq_results_cb,p_inq->p_inq_cmpl_cb); + } +#endif + } + if(p_inq->inqparms.mode == 0 && p_inq->scan_type == INQ_GENERAL)//this inquiry is complete + { + p_inq->scan_type = INQ_NONE; +#if (defined BLE_INCLUDED && BLE_INCLUDED == TRUE) + /* check if the LE observe is pending */ + if(p_inq->p_inq_ble_results_cb != NULL) + { + BTM_TRACE_DEBUG("BTM Inq Compl: resuming a pending LE scan"); + BTM_BleObserve(1,0, p_inq->p_inq_ble_results_cb, p_inq->p_inq_ble_cmpl_cb); + } +#endif + } +#if (BTM_INQ_DEBUG == TRUE) + BTM_TRACE_DEBUG ("inq_active:0x%x state:%d inqfilt_active:%d\n", + btm_cb.btm_inq_vars.inq_active, btm_cb.btm_inq_vars.state, btm_cb.btm_inq_vars.inqfilt_active); +#endif +} + +/******************************************************************************* +** +** Function btm_process_cancel_complete +** +** Description This function is called when inquiry cancel complete is received +** from the device.This function will also call the btm_process_inq_complete +** This function is needed to differentiate a cancel_cmpl_evt from the +** inq_cmpl_evt +** +** Returns void +** +*******************************************************************************/ +void btm_process_cancel_complete(UINT8 status, UINT8 mode) +{ + btm_acl_update_busy_level (BTM_BLI_INQ_CANCEL_EVT); + btm_process_inq_complete(status, mode); +} +/******************************************************************************* +** +** Function btm_initiate_rem_name +** +** Description This function looks initiates a remote name request. It is called +** either by GAP or by the API call BTM_ReadRemoteDeviceName. +** +** Input Params: p_cur - pointer to an inquiry result structure (NULL if nonexistent) +** p_cb - callback function called when BTM_CMD_STARTED +** is returned. +** A pointer to tBTM_REMOTE_DEV_NAME is passed to the +** callback. +** +** Returns +** BTM_CMD_STARTED is returned if the request was sent to HCI. +** BTM_BUSY if already in progress +** BTM_NO_RESOURCES if could not allocate resources to start the command +** BTM_WRONG_MODE if the device is not up. +** +*******************************************************************************/ +tBTM_STATUS btm_initiate_rem_name (BD_ADDR remote_bda, tBTM_INQ_INFO *p_cur, + UINT8 origin, UINT32 timeout, tBTM_CMPL_CB *p_cb) +{ + tBTM_INQUIRY_VAR_ST *p_inq = &btm_cb.btm_inq_vars; + BOOLEAN cmd_ok; + + + /*** Make sure the device is ready ***/ + if (!BTM_IsDeviceUp()) + return (BTM_WRONG_MODE); + + + if (origin == BTM_RMT_NAME_SEC) + { + cmd_ok = btsnd_hcic_rmt_name_req (remote_bda, HCI_PAGE_SCAN_REP_MODE_R1, + HCI_MANDATARY_PAGE_SCAN_MODE, 0); + if (cmd_ok) + return BTM_CMD_STARTED; + else + return BTM_NO_RESOURCES; + } + /* Make sure there are no two remote name requests from external API in progress */ + else if (origin == BTM_RMT_NAME_EXT) + { + if (p_inq->remname_active) + { + return (BTM_BUSY); + } + else + { + /* If there is no remote name request running,call the callback function and start timer */ + p_inq->p_remname_cmpl_cb = p_cb; + memcpy(p_inq->remname_bda, remote_bda, BD_ADDR_LEN); + btu_start_timer (&p_inq->rmt_name_timer_ent, + BTU_TTYPE_BTM_RMT_NAME, + timeout); + + /* If the database entry exists for the device, use its clock offset */ + if (p_cur) + { + cmd_ok = btsnd_hcic_rmt_name_req (remote_bda, + p_cur->results.page_scan_rep_mode, + p_cur->results.page_scan_mode, + (UINT16)(p_cur->results.clock_offset | + BTM_CLOCK_OFFSET_VALID)); + } + else /* Otherwise use defaults and mark the clock offset as invalid */ + { + cmd_ok = btsnd_hcic_rmt_name_req (remote_bda, HCI_PAGE_SCAN_REP_MODE_R1, + HCI_MANDATARY_PAGE_SCAN_MODE, 0); + } + if (cmd_ok) + { + p_inq->remname_active = TRUE; + return BTM_CMD_STARTED; + } + else + return BTM_NO_RESOURCES; + } + } + else + { + return BTM_ILLEGAL_VALUE; + } +} + +/******************************************************************************* +** +** Function btm_process_remote_name +** +** Description This function is called when a remote name is received from +** the device. If remote names are cached, it updates the inquiry +** database. +** +** Returns void +** +*******************************************************************************/ +void btm_process_remote_name (BD_ADDR bda, BD_NAME bdn, UINT16 evt_len, UINT8 hci_status) +{ + tBTM_REMOTE_DEV_NAME rem_name; + tBTM_INQUIRY_VAR_ST *p_inq = &btm_cb.btm_inq_vars; + tBTM_CMPL_CB *p_cb = p_inq->p_remname_cmpl_cb; + UINT8 *p_n1; + + UINT16 temp_evt_len; + + if (bda != NULL) + { + BTM_TRACE_EVENT("BDA %02x:%02x:%02x:%02x:%02x:%02x\n",bda[0], bda[1], + bda[2], bda[3], + bda[4], bda[5]); + } + + BTM_TRACE_EVENT("Inquire BDA %02x:%02x:%02x:%02x:%02x:%02x\n",p_inq->remname_bda[0], p_inq->remname_bda[1], + p_inq->remname_bda[2], p_inq->remname_bda[3], + p_inq->remname_bda[4], p_inq->remname_bda[5]); + + + + /* If the inquire BDA and remote DBA are the same, then stop the timer and set the active to false */ + if ((p_inq->remname_active ==TRUE)&& + (((bda != NULL) && + (memcmp(bda, p_inq->remname_bda,BD_ADDR_LEN)==0)) || bda == NULL)) + + { +#if BLE_INCLUDED == TRUE + if (BTM_UseLeLink(p_inq->remname_bda)) + { + if (hci_status == HCI_ERR_UNSPECIFIED) + btm_ble_cancel_remote_name(p_inq->remname_bda); + } +#endif + btu_stop_timer (&p_inq->rmt_name_timer_ent); + p_inq->remname_active = FALSE; + /* Clean up and return the status if the command was not successful */ + /* Note: If part of the inquiry, the name is not stored, and the */ + /* inquiry complete callback is called. */ + + if (hci_status == HCI_SUCCESS) + { + /* Copy the name from the data stream into the return structure */ + /* Note that even if it is not being returned, it is used as a */ + /* temporary buffer. */ + p_n1 = (UINT8 *)rem_name.remote_bd_name; + rem_name.length = (evt_len < BD_NAME_LEN) ? evt_len : BD_NAME_LEN; + rem_name.remote_bd_name[rem_name.length] = 0; + rem_name.status = BTM_SUCCESS; + temp_evt_len = rem_name.length; + + while (temp_evt_len > 0) + { + *p_n1++ = *bdn++; + temp_evt_len--; + } + rem_name.remote_bd_name[rem_name.length] = 0; + } + + + /* If processing a stand alone remote name then report the error in the callback */ + else + { + rem_name.status = BTM_BAD_VALUE_RET; + rem_name.length = 0; + rem_name.remote_bd_name[0] = 0; + } + /* Reset the remote BAD to zero and call callback if possible */ + memset(p_inq->remname_bda, 0, BD_ADDR_LEN); + + p_inq->p_remname_cmpl_cb = NULL; + if (p_cb) + (p_cb)((tBTM_REMOTE_DEV_NAME *)&rem_name); + } +} + +/******************************************************************************* +** +** Function btm_inq_rmt_name_failed +** +** Description This function is if timeout expires while getting remote +** name. This is done for devices that incorrectly do not +** report operation failure +** +** Returns void +** +*******************************************************************************/ +void btm_inq_rmt_name_failed (void) +{ + BTM_TRACE_ERROR ("btm_inq_rmt_name_failed() remname_active=%d\n", btm_cb.btm_inq_vars.remname_active); + + if (btm_cb.btm_inq_vars.remname_active) + btm_process_remote_name (btm_cb.btm_inq_vars.remname_bda, NULL, 0, HCI_ERR_UNSPECIFIED); + else + btm_process_remote_name (NULL, NULL, 0, HCI_ERR_UNSPECIFIED); + + btm_sec_rmt_name_request_complete (NULL, NULL, HCI_ERR_UNSPECIFIED); +} +/******************************************************************************* +** +** Function btm_read_linq_tx_power_complete +** +** Description read inquiry tx power level complete callback function. +** +** Returns void +** +*******************************************************************************/ +void btm_read_linq_tx_power_complete(UINT8 *p) +{ + tBTM_CMPL_CB *p_cb = btm_cb.devcb.p_txpwer_cmpl_cb; + tBTM_INQ_TXPWR_RESULTS results; + + btu_stop_timer (&btm_cb.devcb.txpwer_timer); + /* If there was a callback registered for read inq tx power, call it */ + btm_cb.devcb.p_txpwer_cmpl_cb = NULL; + + if (p_cb) + { + STREAM_TO_UINT8 (results.hci_status, p); + + if (results.hci_status == HCI_SUCCESS) + { + results.status = BTM_SUCCESS; + + STREAM_TO_UINT8 (results.tx_power, p); + BTM_TRACE_EVENT ("BTM INQ TX POWER Complete: tx_power %d, hci status 0x%02x\n", + results.tx_power, results.hci_status); + } + else + results.status = BTM_ERR_PROCESSING; + + (*p_cb)(&results); + } + +} +/******************************************************************************* +** +** Function BTM_WriteEIR +** +** Description This function is called to write EIR data to controller. +** +** Parameters p_buff - allocated HCI command buffer including extended +** inquriry response +** +** Returns BTM_SUCCESS - if successful +** BTM_MODE_UNSUPPORTED - if local device cannot support it +** +*******************************************************************************/ +tBTM_STATUS BTM_WriteEIR( BT_HDR *p_buff ) +{ + if (controller_get_interface()->supports_extended_inquiry_response()) + { + BTM_TRACE_API("Write Extended Inquiry Response to controller\n"); + btsnd_hcic_write_ext_inquiry_response (p_buff, BTM_EIR_DEFAULT_FEC_REQUIRED); + return BTM_SUCCESS; + } + else + { + GKI_freebuf(p_buff); + return BTM_MODE_UNSUPPORTED; + } +} + +/******************************************************************************* +** +** Function BTM_CheckEirData +** +** Description This function is called to get EIR data from significant part. +** +** Parameters p_eir - pointer of EIR significant part +** type - finding EIR data type +** p_length - return the length of EIR data not including type +** +** Returns pointer of EIR data +** +*******************************************************************************/ +UINT8 *BTM_CheckEirData( UINT8 *p_eir, UINT8 type, UINT8 *p_length ) +{ + UINT8 *p = p_eir; + UINT8 length; + UINT8 eir_type; + BTM_TRACE_API("BTM_CheckEirData type=0x%02X\n", type); + + STREAM_TO_UINT8(length, p); + while( length && (p - p_eir <= HCI_EXT_INQ_RESPONSE_LEN)) + { + STREAM_TO_UINT8(eir_type, p); + if( eir_type == type ) + { + /* length doesn't include itself */ + *p_length = length - 1; /* minus the length of type */ + return p; + } + p += length - 1; /* skip the length of data */ + STREAM_TO_UINT8(length, p); + } + + *p_length = 0; + return NULL; +} + +/******************************************************************************* +** +** Function btm_convert_uuid_to_eir_service +** +** Description This function is called to get the bit position of UUID. +** +** Parameters uuid16 - UUID 16-bit +** +** Returns BTM EIR service ID if found +** BTM_EIR_MAX_SERVICES - if not found +** +*******************************************************************************/ +static UINT8 btm_convert_uuid_to_eir_service( UINT16 uuid16 ) +{ + UINT8 xx; + + for( xx = 0; xx < BTM_EIR_MAX_SERVICES; xx++ ) + { + if( uuid16 == BTM_EIR_UUID_LKUP_TBL[xx]) + { + return xx; + } + } + return BTM_EIR_MAX_SERVICES; +} + +/******************************************************************************* +** +** Function BTM_HasEirService +** +** Description This function is called to know if UUID in bit map of UUID. +** +** Parameters p_eir_uuid - bit map of UUID list +** uuid16 - UUID 16-bit +** +** Returns TRUE - if found +** FALSE - if not found +** +*******************************************************************************/ +BOOLEAN BTM_HasEirService( UINT32 *p_eir_uuid, UINT16 uuid16 ) +{ + UINT8 service_id; + + service_id = btm_convert_uuid_to_eir_service(uuid16); + if( service_id < BTM_EIR_MAX_SERVICES ) + return( BTM_EIR_HAS_SERVICE( p_eir_uuid, service_id )); + else + return( FALSE ); +} + +/******************************************************************************* +** +** Function BTM_HasInquiryEirService +** +** Description This function is called to know if UUID in bit map of UUID list. +** +** Parameters p_results - inquiry results +** uuid16 - UUID 16-bit +** +** Returns BTM_EIR_FOUND - if found +** BTM_EIR_NOT_FOUND - if not found and it is complete list +** BTM_EIR_UNKNOWN - if not found and it is not complete list +** +*******************************************************************************/ +tBTM_EIR_SEARCH_RESULT BTM_HasInquiryEirService( tBTM_INQ_RESULTS *p_results, UINT16 uuid16 ) +{ + if( BTM_HasEirService( p_results->eir_uuid, uuid16 )) + { + return BTM_EIR_FOUND; + } + else if( p_results->eir_complete_list ) + { + return BTM_EIR_NOT_FOUND; + } + else + return BTM_EIR_UNKNOWN; +} + +/******************************************************************************* +** +** Function BTM_AddEirService +** +** Description This function is called to add a service in bit map of UUID list. +** +** Parameters p_eir_uuid - bit mask of UUID list for EIR +** uuid16 - UUID 16-bit +** +** Returns None +** +*******************************************************************************/ +void BTM_AddEirService( UINT32 *p_eir_uuid, UINT16 uuid16 ) +{ + UINT8 service_id; + + service_id = btm_convert_uuid_to_eir_service(uuid16); + if( service_id < BTM_EIR_MAX_SERVICES ) + BTM_EIR_SET_SERVICE( p_eir_uuid, service_id ); +} + +/******************************************************************************* +** +** Function BTM_RemoveEirService +** +** Description This function is called to remove a service in bit map of UUID list. +** +** Parameters p_eir_uuid - bit mask of UUID list for EIR +** uuid16 - UUID 16-bit +** +** Returns None +** +*******************************************************************************/ +void BTM_RemoveEirService( UINT32 *p_eir_uuid, UINT16 uuid16 ) +{ + UINT8 service_id; + + service_id = btm_convert_uuid_to_eir_service(uuid16); + if( service_id < BTM_EIR_MAX_SERVICES ) + BTM_EIR_CLR_SERVICE( p_eir_uuid, service_id ); +} + +/******************************************************************************* +** +** Function BTM_GetEirSupportedServices +** +** Description This function is called to get UUID list from bit map of UUID list. +** +** Parameters p_eir_uuid - bit mask of UUID list for EIR +** p - reference of current pointer of EIR +** max_num_uuid16 - max number of UUID can be written in EIR +** num_uuid16 - number of UUID have been written in EIR +** +** Returns BTM_EIR_MORE_16BITS_UUID_TYPE, if it has more than max +** BTM_EIR_COMPLETE_16BITS_UUID_TYPE, otherwise +** +*******************************************************************************/ +UINT8 BTM_GetEirSupportedServices( UINT32 *p_eir_uuid, UINT8 **p, + UINT8 max_num_uuid16, UINT8 *p_num_uuid16) +{ + UINT8 service_index; + + *p_num_uuid16 = 0; + + for(service_index = 0; service_index < BTM_EIR_MAX_SERVICES; service_index++) + { + if( BTM_EIR_HAS_SERVICE( p_eir_uuid, service_index )) + { + if( *p_num_uuid16 < max_num_uuid16 ) + { + UINT16_TO_STREAM(*p, BTM_EIR_UUID_LKUP_TBL[service_index]); + (*p_num_uuid16)++; + } + /* if max number of UUIDs are stored and found one more */ + else + { + return BTM_EIR_MORE_16BITS_UUID_TYPE; + } + } + } + return BTM_EIR_COMPLETE_16BITS_UUID_TYPE; +} + +/******************************************************************************* +** +** Function BTM_GetEirUuidList +** +** Description This function parses EIR and returns UUID list. +** +** Parameters p_eir - EIR +** uuid_size - LEN_UUID_16, LEN_UUID_32, LEN_UUID_128 +** p_num_uuid - return number of UUID in found list +** p_uuid_list - return UUID list +** max_num_uuid - maximum number of UUID to be returned +** +** Returns 0 - if not found +** BTM_EIR_COMPLETE_16BITS_UUID_TYPE +** BTM_EIR_MORE_16BITS_UUID_TYPE +** BTM_EIR_COMPLETE_32BITS_UUID_TYPE +** BTM_EIR_MORE_32BITS_UUID_TYPE +** BTM_EIR_COMPLETE_128BITS_UUID_TYPE +** BTM_EIR_MORE_128BITS_UUID_TYPE +** +*******************************************************************************/ +UINT8 BTM_GetEirUuidList( UINT8 *p_eir, UINT8 uuid_size, UINT8 *p_num_uuid, + UINT8 *p_uuid_list, UINT8 max_num_uuid) +{ + UINT8 *p_uuid_data; + UINT8 type; + UINT8 yy, xx; + UINT16 *p_uuid16 = (UINT16 *)p_uuid_list; + UINT32 *p_uuid32 = (UINT32 *)p_uuid_list; + char buff[LEN_UUID_128 * 2 + 1]; + + p_uuid_data = btm_eir_get_uuid_list( p_eir, uuid_size, p_num_uuid, &type ); + if( p_uuid_data == NULL ) + { + return 0x00; + } + + if( *p_num_uuid > max_num_uuid ) + { + BTM_TRACE_WARNING("BTM_GetEirUuidList number of uuid in EIR = %d, size of uuid list = %d\n", + *p_num_uuid, max_num_uuid ); + *p_num_uuid = max_num_uuid; + } + + BTM_TRACE_DEBUG("BTM_GetEirUuidList type = %02X, number of uuid = %d\n", type, *p_num_uuid ); + + if( uuid_size == LEN_UUID_16 ) + { + for( yy = 0; yy < *p_num_uuid; yy++ ) + { + STREAM_TO_UINT16(*(p_uuid16 + yy), p_uuid_data); + BTM_TRACE_DEBUG(" 0x%04X\n", *(p_uuid16 + yy)); + } + } + else if( uuid_size == LEN_UUID_32 ) + { + for( yy = 0; yy < *p_num_uuid; yy++ ) + { + STREAM_TO_UINT32(*(p_uuid32 + yy), p_uuid_data); + BTM_TRACE_DEBUG(" 0x%08X\n", *(p_uuid32 + yy)); + } + } + else if( uuid_size == LEN_UUID_128 ) + { + for( yy = 0; yy < *p_num_uuid; yy++ ) + { + STREAM_TO_ARRAY16(p_uuid_list + yy * LEN_UUID_128, p_uuid_data); + for( xx = 0; xx < LEN_UUID_128; xx++ ) + sprintf(buff + xx*2, "%02X", *(p_uuid_list + yy * LEN_UUID_128 + xx)); + BTM_TRACE_DEBUG(" 0x%s\n", buff); + } + } + + return type; +} + + +/******************************************************************************* +** +** Function btm_eir_get_uuid_list +** +** Description This function searches UUID list in EIR. +** +** Parameters p_eir - address of EIR +** uuid_size - size of UUID to find +** p_num_uuid - number of UUIDs found +** p_uuid_list_type - EIR data type +** +** Returns NULL - if UUID list with uuid_size is not found +** beginning of UUID list in EIR - otherwise +** +*******************************************************************************/ +static UINT8 *btm_eir_get_uuid_list( UINT8 *p_eir, UINT8 uuid_size, + UINT8 *p_num_uuid, UINT8 *p_uuid_list_type ) +{ + UINT8 *p_uuid_data; + UINT8 complete_type, more_type; + UINT8 uuid_len; + + switch( uuid_size ) + { + case LEN_UUID_16: + complete_type = BTM_EIR_COMPLETE_16BITS_UUID_TYPE; + more_type = BTM_EIR_MORE_16BITS_UUID_TYPE; + break; + case LEN_UUID_32: + complete_type = BTM_EIR_COMPLETE_32BITS_UUID_TYPE; + more_type = BTM_EIR_MORE_32BITS_UUID_TYPE; + break; + case LEN_UUID_128: + complete_type = BTM_EIR_COMPLETE_128BITS_UUID_TYPE; + more_type = BTM_EIR_MORE_128BITS_UUID_TYPE; + break; + default: + *p_num_uuid = 0; + return NULL; + break; + } + + p_uuid_data = BTM_CheckEirData( p_eir, complete_type, &uuid_len ); + if(p_uuid_data == NULL) + { + p_uuid_data = BTM_CheckEirData( p_eir, more_type, &uuid_len ); + *p_uuid_list_type = more_type; + } + else + { + *p_uuid_list_type = complete_type; + } + + *p_num_uuid = uuid_len / uuid_size; + return p_uuid_data; +} + +/******************************************************************************* +** +** Function btm_convert_uuid_to_uuid16 +** +** Description This function converts UUID to UUID 16-bit. +** +** Parameters p_uuid - address of UUID +** uuid_size - size of UUID +** +** Returns 0 - if UUID cannot be converted to UUID 16-bit +** UUID 16-bit - otherwise +** +*******************************************************************************/ +static UINT16 btm_convert_uuid_to_uuid16( UINT8 *p_uuid, UINT8 uuid_size ) +{ + static const UINT8 base_uuid[LEN_UUID_128] = {0xFB, 0x34, 0x9B, 0x5F, 0x80, 0x00, 0x00, 0x80, + 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + UINT16 uuid16 = 0; + UINT32 uuid32; + BOOLEAN is_base_uuid; + UINT8 xx; + + switch (uuid_size) + { + case LEN_UUID_16: + STREAM_TO_UINT16 (uuid16, p_uuid); + break; + case LEN_UUID_32: + STREAM_TO_UINT32 (uuid32, p_uuid); + if (uuid32 < 0x10000) + uuid16 = (UINT16) uuid32; + break; + case LEN_UUID_128: + /* See if we can compress his UUID down to 16 or 32bit UUIDs */ + is_base_uuid = TRUE; + for (xx = 0; xx < LEN_UUID_128 - 4; xx++) + { + if (p_uuid[xx] != base_uuid[xx]) + { + is_base_uuid = FALSE; + break; + } + } + if (is_base_uuid) + { + if ((p_uuid[LEN_UUID_128 - 1] == 0) && (p_uuid[LEN_UUID_128 - 2] == 0)) + { + p_uuid += (LEN_UUID_128 - 4); + STREAM_TO_UINT16(uuid16, p_uuid); + } + } + break; + default: + BTM_TRACE_WARNING("btm_convert_uuid_to_uuid16 invalid uuid size\n"); + break; + } + + return( uuid16); +} + +/******************************************************************************* +** +** Function btm_set_eir_uuid +** +** Description This function is called to store received UUID into inquiry result. +** +** Parameters p_eir - pointer of EIR significant part +** p_results - pointer of inquiry result +** +** Returns None +** +*******************************************************************************/ +void btm_set_eir_uuid( UINT8 *p_eir, tBTM_INQ_RESULTS *p_results ) +{ + UINT8 *p_uuid_data; + UINT8 num_uuid; + UINT16 uuid16; + UINT8 yy; + UINT8 type = BTM_EIR_MORE_16BITS_UUID_TYPE; + + p_uuid_data = btm_eir_get_uuid_list( p_eir, LEN_UUID_16, &num_uuid, &type ); + + if(type == BTM_EIR_COMPLETE_16BITS_UUID_TYPE) + { + p_results->eir_complete_list = TRUE; + } + else + { + p_results->eir_complete_list = FALSE; + } + + BTM_TRACE_API("btm_set_eir_uuid eir_complete_list=0x%02X\n", p_results->eir_complete_list); + + if( p_uuid_data ) + { + for( yy = 0; yy < num_uuid; yy++ ) + { + STREAM_TO_UINT16(uuid16, p_uuid_data); + BTM_AddEirService( p_results->eir_uuid, uuid16 ); + } + } + + p_uuid_data = btm_eir_get_uuid_list( p_eir, LEN_UUID_32, &num_uuid, &type ); + if( p_uuid_data ) + { + for( yy = 0; yy < num_uuid; yy++ ) + { + uuid16 = btm_convert_uuid_to_uuid16( p_uuid_data, LEN_UUID_32 ); + p_uuid_data += LEN_UUID_32; + if( uuid16 ) + BTM_AddEirService( p_results->eir_uuid, uuid16 ); + } + } + + p_uuid_data = btm_eir_get_uuid_list( p_eir, LEN_UUID_128, &num_uuid, &type ); + if( p_uuid_data ) + { + for( yy = 0; yy < num_uuid; yy++ ) + { + uuid16 = btm_convert_uuid_to_uuid16( p_uuid_data, LEN_UUID_128 ); + p_uuid_data += LEN_UUID_128; + if( uuid16 ) + BTM_AddEirService( p_results->eir_uuid, uuid16 ); + } + } +} diff --git a/components/bt/bluedroid/stack/btm/btm_main.c b/components/bt/bluedroid/stack/btm/btm_main.c new file mode 100755 index 0000000000..04408a8231 --- /dev/null +++ b/components/bt/bluedroid/stack/btm/btm_main.c @@ -0,0 +1,70 @@ +/****************************************************************************** + * + * Copyright (C) 2002-2012 Broadcom Corporation + * + * 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 definition of the btm control block when + * BTM_DYNAMIC_MEMORY is used. + * + ******************************************************************************/ + +#include "bt_types.h" +#include "bt_target.h" +#include +#include "btm_int.h" + +/* Global BTM control block structure +*/ +#if BTM_DYNAMIC_MEMORY == FALSE +tBTM_CB btm_cb; +#endif + +/******************************************************************************* +** +** Function btm_init +** +** Description This function is called at BTM startup to allocate the +** control block (if using dynamic memory), and initializes the +** tracing level. It then initializes the various components of +** btm. +** +** Returns void +** +*******************************************************************************/ +void btm_init (void) +{ + /* All fields are cleared; nonzero fields are reinitialized in appropriate function */ + memset(&btm_cb, 0, sizeof(tBTM_CB)); + +#if defined(BTM_INITIAL_TRACE_LEVEL) + btm_cb.trace_level = BTM_INITIAL_TRACE_LEVEL; +#else + btm_cb.trace_level = BT_TRACE_LEVEL_NONE; +#endif + /* Initialize BTM component structures */ + btm_inq_db_init(); /* Inquiry Database and Structures */ + btm_acl_init(); /* ACL Database and Structures */ + btm_sec_init(BTM_SEC_MODE_SP); /* Security Manager Database and Structures */ +#if BTM_SCO_INCLUDED == TRUE + btm_sco_init(); /* SCO Database and Structures (If included) */ +#endif + + btm_dev_init(); /* Device Manager Structures & HCI_Reset */ +} + + diff --git a/components/bt/bluedroid/stack/btm/btm_pm.c b/components/bt/bluedroid/stack/btm/btm_pm.c new file mode 100755 index 0000000000..c49cba4e68 --- /dev/null +++ b/components/bt/bluedroid/stack/btm/btm_pm.c @@ -0,0 +1,1007 @@ +/****************************************************************************** + * + * Copyright (C) 2000-2012 Broadcom Corporation + * + * 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 functions that manages ACL link modes. + * This includes operations such as active, hold, + * park and sniff modes. + * + * This module contains both internal and external (API) + * functions. External (API) functions are distinguishable + * by their names beginning with uppercase BTM. + * + *****************************************************************************/ + +//#define LOG_TAG "bt_btm_pm" + +#include +#include +//#include +#include + +#include "bt_types.h" +#include "gki.h" +#include "hcimsgs.h" +#include "btu.h" +#include "btm_api.h" +#include "btm_int.h" +#include "l2c_int.h" +#include "hcidefs.h" +//#include "bt_utils.h" +//#include "osi/include/log.h" + +/*****************************************************************************/ +/* to handle different modes */ +/*****************************************************************************/ +#define BTM_PM_STORED_MASK 0x80 /* set this mask if the command is stored */ +#define BTM_PM_NUM_SET_MODES 3 /* only hold, sniff & park */ + +/* Usage: (ptr_features[ offset ] & mask )?TRUE:FALSE */ +/* offset to supported feature */ +const UINT8 btm_pm_mode_off[BTM_PM_NUM_SET_MODES] = {0, 0, 1}; +/* mask to supported feature */ +const UINT8 btm_pm_mode_msk[BTM_PM_NUM_SET_MODES] = {0x40, 0x80, 0x01}; + +#define BTM_PM_GET_MD1 1 +#define BTM_PM_GET_MD2 2 +#define BTM_PM_GET_COMP 3 + +const UINT8 btm_pm_md_comp_matrix[BTM_PM_NUM_SET_MODES*BTM_PM_NUM_SET_MODES] = +{ + BTM_PM_GET_COMP, + BTM_PM_GET_MD2, + BTM_PM_GET_MD2, + + BTM_PM_GET_MD1, + BTM_PM_GET_COMP, + BTM_PM_GET_MD1, + + BTM_PM_GET_MD1, + BTM_PM_GET_MD2, + BTM_PM_GET_COMP +}; + +/* function prototype */ +static int btm_pm_find_acl_ind(BD_ADDR remote_bda); +static tBTM_STATUS btm_pm_snd_md_req( UINT8 pm_id, int link_ind, tBTM_PM_PWR_MD *p_mode ); +static const char *mode_to_string(tBTM_PM_MODE mode); + +/* +#ifdef BTM_PM_DEBUG +#undef BTM_PM_DEBUG +#define BTM_PM_DEBUG TRUE +#endif +*/ + +#if BTM_PM_DEBUG == TRUE +const char * btm_pm_state_str[] = +{ + "pm_active_state", + "pm_hold_state", + "pm_sniff_state", + "pm_park_state", + "pm_pend_state" +}; + +const char * btm_pm_event_str[] = +{ + "pm_set_mode_event", + "pm_hci_sts_event", + "pm_mod_chg_event", + "pm_update_event" +}; + +const char * btm_pm_action_str[] = +{ + "pm_set_mode_action", + "pm_update_db_action", + "pm_mod_chg_action", + "pm_hci_sts_action", + "pm_update_action" +}; +#endif // BTM_PM_DEBUG + +/*****************************************************************************/ +/* P U B L I C F U N C T I O N S */ +/*****************************************************************************/ +/******************************************************************************* +** +** Function BTM_PmRegister +** +** Description register or deregister with power manager +** +** Returns BTM_SUCCESS if successful, +** BTM_NO_RESOURCES if no room to hold registration +** BTM_ILLEGAL_VALUE +** +*******************************************************************************/ +tBTM_STATUS BTM_PmRegister (UINT8 mask, UINT8 *p_pm_id, tBTM_PM_STATUS_CBACK *p_cb) +{ + int xx; + + /* de-register */ + if(mask & BTM_PM_DEREG) + { + if(*p_pm_id >= BTM_MAX_PM_RECORDS) + return BTM_ILLEGAL_VALUE; + btm_cb.pm_reg_db[*p_pm_id].mask = BTM_PM_REC_NOT_USED; + return BTM_SUCCESS; + } + + for(xx=0; xx= BTM_MAX_PM_RECORDS) + pm_id = BTM_PM_SET_ONLY_ID; + + if(p_mode == NULL) + return BTM_ILLEGAL_VALUE; + + BTM_TRACE_API( "BTM_SetPowerMode: pm_id %d BDA: %08x mode:0x%x", pm_id, + (remote_bda[2]<<24)+(remote_bda[3]<<16)+(remote_bda[4]<<8)+remote_bda[5], p_mode->mode); + + /* take out the force bit */ + mode = p_mode->mode & ~BTM_PM_MD_FORCE; + + acl_ind = btm_pm_find_acl_ind(remote_bda); + if(acl_ind == MAX_L2CAP_LINKS) + return (BTM_UNKNOWN_ADDR); + + p_cb = &(btm_cb.pm_mode_db[acl_ind]); + + if(mode != BTM_PM_MD_ACTIVE) + { + /* check if the requested mode is supported */ + ind = mode - BTM_PM_MD_HOLD; /* make it base 0 */ + p_features = BTM_ReadLocalFeatures(); + if( !(p_features[ btm_pm_mode_off[ind] ] & btm_pm_mode_msk[ind] ) ) + return BTM_MODE_UNSUPPORTED; + } + + if(mode == p_cb->state) /* the requested mode is current mode */ + { + /* already in the requested mode and the current interval has less latency than the max */ + if( (mode == BTM_PM_MD_ACTIVE) || + ((p_mode->mode & BTM_PM_MD_FORCE) && (p_mode->max >= p_cb->interval) && (p_mode->min <= p_cb->interval)) || + ((p_mode->mode & BTM_PM_MD_FORCE)==0 && (p_mode->max >= p_cb->interval)) ) + { + BTM_TRACE_DEBUG( "BTM_SetPowerMode: mode:0x%x interval %d max:%d, min:%d", p_mode->mode, p_cb->interval, p_mode->max, p_mode->min); + return BTM_SUCCESS; + } + } + + temp_pm_id = pm_id; + if(pm_id == BTM_PM_SET_ONLY_ID) + temp_pm_id = BTM_MAX_PM_RECORDS; + + /* update mode database */ + if( ((pm_id != BTM_PM_SET_ONLY_ID) && + (btm_cb.pm_reg_db[pm_id].mask & BTM_PM_REG_SET)) + || ((pm_id == BTM_PM_SET_ONLY_ID) && (btm_cb.pm_pend_link != MAX_L2CAP_LINKS)) ) + { +#if BTM_PM_DEBUG == TRUE + BTM_TRACE_DEBUG( "BTM_SetPowerMode: Saving cmd acl_ind %d temp_pm_id %d", acl_ind,temp_pm_id); +#endif // BTM_PM_DEBUG + /* Make sure mask is set to BTM_PM_REG_SET */ + btm_cb.pm_reg_db[temp_pm_id].mask |= BTM_PM_REG_SET; + *(&p_cb->req_mode[temp_pm_id]) = *((tBTM_PM_PWR_MD *)p_mode); + p_cb->chg_ind = TRUE; + } + +#if BTM_PM_DEBUG == TRUE + BTM_TRACE_DEBUG( "btm_pm state:0x%x, pm_pend_link: %d", p_cb->state, btm_cb.pm_pend_link); +#endif // BTM_PM_DEBUG + /* if mode == hold or pending, return */ + if( (p_cb->state == BTM_PM_STS_HOLD) || + (p_cb->state == BTM_PM_STS_PENDING) || + (btm_cb.pm_pend_link != MAX_L2CAP_LINKS) ) /* command pending */ + { + if(acl_ind != btm_cb.pm_pend_link) + { + /* set the stored mask */ + p_cb->state |= BTM_PM_STORED_MASK; + BTM_TRACE_DEBUG( "btm_pm state stored:%d",acl_ind); + } + return BTM_CMD_STORED; + } + + + + return btm_pm_snd_md_req(pm_id, acl_ind, p_mode); +} + +/******************************************************************************* +** +** Function BTM_ReadPowerMode +** +** Description This returns the current mode for a specific +** ACL connection. +** +** Input Param remote_bda - device address of desired ACL connection +** +** Output Param p_mode - address where the current mode is copied into. +** BTM_ACL_MODE_NORMAL +** BTM_ACL_MODE_HOLD +** BTM_ACL_MODE_SNIFF +** BTM_ACL_MODE_PARK +** (valid only if return code is BTM_SUCCESS) +** +** Returns BTM_SUCCESS if successful, +** BTM_UNKNOWN_ADDR if bd addr is not active or bad +** +*******************************************************************************/ +tBTM_STATUS BTM_ReadPowerMode (BD_ADDR remote_bda, tBTM_PM_MODE *p_mode) +{ + int acl_ind; + + if( (acl_ind = btm_pm_find_acl_ind(remote_bda)) == MAX_L2CAP_LINKS) + return (BTM_UNKNOWN_ADDR); + + *p_mode = btm_cb.pm_mode_db[acl_ind].state; + return BTM_SUCCESS; +} + +/******************************************************************************* +** +** Function BTM_SetSsrParams +** +** Description This sends the given SSR parameters for the given ACL +** connection if it is in ACTIVE mode. +** +** Input Param remote_bda - device address of desired ACL connection +** max_lat - maximum latency (in 0.625ms)(0-0xFFFE) +** min_rmt_to - minimum remote timeout +** min_loc_to - minimum local timeout +** +** +** Returns BTM_SUCCESS if the HCI command is issued successful, +** BTM_UNKNOWN_ADDR if bd addr is not active or bad +** BTM_CMD_STORED if the command is stored +** +*******************************************************************************/ +tBTM_STATUS BTM_SetSsrParams (BD_ADDR remote_bda, UINT16 max_lat, + UINT16 min_rmt_to, UINT16 min_loc_to) +{ +#if (BTM_SSR_INCLUDED == TRUE) + int acl_ind; + tBTM_PM_MCB *p_cb; + + if( (acl_ind = btm_pm_find_acl_ind(remote_bda)) == MAX_L2CAP_LINKS) + return (BTM_UNKNOWN_ADDR); + + if(BTM_PM_STS_ACTIVE == btm_cb.pm_mode_db[acl_ind].state || + BTM_PM_STS_SNIFF == btm_cb.pm_mode_db[acl_ind].state) + { + if (btsnd_hcic_sniff_sub_rate(btm_cb.acl_db[acl_ind].hci_handle, max_lat, + min_rmt_to, min_loc_to)) + return BTM_SUCCESS; + else + return BTM_NO_RESOURCES; + } + p_cb = &btm_cb.pm_mode_db[acl_ind]; + p_cb->max_lat = max_lat; + p_cb->min_rmt_to = min_rmt_to; + p_cb->min_loc_to = min_loc_to; + return BTM_CMD_STORED; +#else + return BTM_ILLEGAL_ACTION; +#endif // BTM_SSR_INCLUDED +} + +/******************************************************************************* +** +** Function btm_pm_reset +** +** Description as a part of the BTM reset process. +** +** Returns void +** +*******************************************************************************/ +void btm_pm_reset(void) +{ + int xx; + tBTM_PM_STATUS_CBACK *cb = NULL; + + /* clear the pending request for application */ + if( (btm_cb.pm_pend_id != BTM_PM_SET_ONLY_ID) && + (btm_cb.pm_reg_db[btm_cb.pm_pend_id].mask & BTM_PM_REG_NOTIF) ) + { + cb = btm_cb.pm_reg_db[btm_cb.pm_pend_id].cback; + } + + + /* clear the register record */ + for(xx=0; xxstate = BTM_PM_ST_ACTIVE; +#if BTM_PM_DEBUG == TRUE + BTM_TRACE_DEBUG( "btm_pm_sm_alloc ind:%d st:%d", ind, p_db->state); +#endif // BTM_PM_DEBUG +} + +/******************************************************************************* +** +** Function btm_pm_find_acl_ind +** +** Description This function initializes the control block of an ACL link. +** It is called when an ACL connection is created. +** +** Returns void +** +*******************************************************************************/ +static int btm_pm_find_acl_ind(BD_ADDR remote_bda) +{ + tACL_CONN *p = &btm_cb.acl_db[0]; + UINT8 xx; + + for (xx = 0; xx < MAX_L2CAP_LINKS; xx++, p++) + { + if ((p->in_use) && (!memcmp (p->remote_addr, remote_bda, BD_ADDR_LEN)) +#if (BLE_INCLUDED == TRUE) + && p->transport == BT_TRANSPORT_BR_EDR +#endif // BLE_INCLUDED + ) + { +#if BTM_PM_DEBUG == TRUE + BTM_TRACE_DEBUG( "btm_pm_find_acl_ind ind:%d, st:%d", xx, btm_cb.pm_mode_db[xx].state); +#endif // BTM_PM_DEBUG + break; + } + } + return xx; +} + +/******************************************************************************* +** +** Function btm_pm_compare_modes +** Description get the "more active" mode of the 2 +** Returns void +** +*******************************************************************************/ +static tBTM_PM_PWR_MD * btm_pm_compare_modes(tBTM_PM_PWR_MD *p_md1, tBTM_PM_PWR_MD *p_md2, tBTM_PM_PWR_MD *p_res) +{ + UINT8 res; + + if(p_md1 == NULL) + { + *p_res = *p_md2; + p_res->mode &= ~BTM_PM_MD_FORCE; + + return p_md2; + } + + if(p_md2->mode == BTM_PM_MD_ACTIVE || p_md1->mode == BTM_PM_MD_ACTIVE) + { + return NULL; + } + + /* check if force bit is involved */ + if(p_md1->mode & BTM_PM_MD_FORCE) + { + *p_res = *p_md1; + p_res->mode &= ~BTM_PM_MD_FORCE; + return p_res; + } + + if(p_md2->mode & BTM_PM_MD_FORCE) + { + *p_res = *p_md2; + p_res->mode &= ~BTM_PM_MD_FORCE; + return p_res; + } + + res = (p_md1->mode - 1) * BTM_PM_NUM_SET_MODES + (p_md2->mode - 1); + res = btm_pm_md_comp_matrix[res]; + switch(res) + { + case BTM_PM_GET_MD1: + *p_res = *p_md1; + return p_md1; + + case BTM_PM_GET_MD2: + *p_res = *p_md2; + return p_md2; + + case BTM_PM_GET_COMP: + p_res->mode = p_md1->mode; + /* min of the two */ + p_res->max = (p_md1->max < p_md2->max)? (p_md1->max) : (p_md2->max); + /* max of the two */ + p_res->min = (p_md1->min > p_md2->min)? (p_md1->min) : (p_md2->min); + + /* the intersection is NULL */ + if( p_res->max < p_res->min) + return NULL; + + if(p_res->mode == BTM_PM_MD_SNIFF) + { + /* max of the two */ + p_res->attempt = (p_md1->attempt > p_md2->attempt)? (p_md1->attempt) : (p_md2->attempt); + p_res->timeout = (p_md1->timeout > p_md2->timeout)? (p_md1->timeout) : (p_md2->timeout); + } + return p_res; + } + return NULL; +} + +/******************************************************************************* +** +** Function btm_pm_get_set_mode +** Description get the resulting mode from the registered parties, then compare it +** with the requested mode, if the command is from an unregistered party. +** Returns void +** +*******************************************************************************/ +static tBTM_PM_MODE btm_pm_get_set_mode(UINT8 pm_id, tBTM_PM_MCB *p_cb, tBTM_PM_PWR_MD *p_mode, tBTM_PM_PWR_MD *p_res) +{ + int xx, loop_max; + tBTM_PM_PWR_MD *p_md = NULL; + + if(p_mode != NULL && p_mode->mode & BTM_PM_MD_FORCE) + { + *p_res = *p_mode; + p_res->mode &= ~BTM_PM_MD_FORCE; + return p_res->mode; + } + + if(!p_mode) + loop_max = BTM_MAX_PM_RECORDS+1; + else + loop_max = BTM_MAX_PM_RECORDS; + + for( xx=0; xxreq_mode[xx].mode == BTM_PM_MD_ACTIVE) + { + /* if at least one registered (SET) party says ACTIVE, stay active */ + return BTM_PM_MD_ACTIVE; + } + else + { + /* if registered parties give conflicting information, stay active */ + if( (btm_pm_compare_modes(p_md, &p_cb->req_mode[xx], p_res)) == NULL) + return BTM_PM_MD_ACTIVE; + p_md = p_res; + } + } + } + + /* if the resulting mode is NULL(nobody registers SET), use the requested mode */ + if(p_md == NULL) + { + if(p_mode) + *p_res = *((tBTM_PM_PWR_MD *)p_mode); + else /* p_mode is NULL when btm_pm_snd_md_req is called from btm_pm_proc_mode_change */ + return BTM_PM_MD_ACTIVE; + } + else + { + /* if the command is from unregistered party, + compare the resulting mode from registered party*/ + if( (pm_id == BTM_PM_SET_ONLY_ID) && + ((btm_pm_compare_modes(p_mode, p_md, p_res)) == NULL) ) + return BTM_PM_MD_ACTIVE; + } + + return p_res->mode; +} + +/******************************************************************************* +** +** Function btm_pm_snd_md_req +** Description get the resulting mode and send the resuest to host controller +** Returns tBTM_STATUS +**, BOOLEAN *p_chg_ind +*******************************************************************************/ +static tBTM_STATUS btm_pm_snd_md_req(UINT8 pm_id, int link_ind, tBTM_PM_PWR_MD *p_mode) +{ + tBTM_PM_PWR_MD md_res; + tBTM_PM_MODE mode; + tBTM_PM_MCB *p_cb = &btm_cb.pm_mode_db[link_ind]; + BOOLEAN chg_ind = FALSE; + + mode = btm_pm_get_set_mode(pm_id, p_cb, p_mode, &md_res); + md_res.mode = mode; + +#if BTM_PM_DEBUG == TRUE + BTM_TRACE_DEBUG( "btm_pm_snd_md_req link_ind:%d, mode: %d", + link_ind, mode); +#endif // BTM_PM_DEBUG + + if( p_cb->state == mode) + { + /* already in the resulting mode */ + if( (mode == BTM_PM_MD_ACTIVE) || + ((md_res.max >= p_cb->interval) && (md_res.min <= p_cb->interval)) ) + return BTM_CMD_STORED; + /* Otherwise, needs to wake, then sleep */ + chg_ind = TRUE; + } + p_cb->chg_ind = chg_ind; + + /* cannot go directly from current mode to resulting mode. */ + if( mode != BTM_PM_MD_ACTIVE && p_cb->state != BTM_PM_MD_ACTIVE) + p_cb->chg_ind = TRUE; /* needs to wake, then sleep */ + + if(p_cb->chg_ind == TRUE) /* needs to wake first */ + md_res.mode = BTM_PM_MD_ACTIVE; +#if (BTM_SSR_INCLUDED == TRUE) + else if(BTM_PM_MD_SNIFF == md_res.mode && p_cb->max_lat) + { + btsnd_hcic_sniff_sub_rate(btm_cb.acl_db[link_ind].hci_handle, p_cb->max_lat, + p_cb->min_rmt_to, p_cb->min_loc_to); + p_cb->max_lat = 0; + } +#endif // BTM_SSR_INCLUDED + /* Default is failure */ + btm_cb.pm_pend_link = MAX_L2CAP_LINKS; + + /* send the appropriate HCI command */ + btm_cb.pm_pend_id = pm_id; + +#if BTM_PM_DEBUG == TRUE + BTM_TRACE_DEBUG("btm_pm_snd_md_req state:0x%x, link_ind: %d", p_cb->state, link_ind); +#endif // BTM_PM_DEBUG + + LOG_DEBUG("%s switching from %s to %s.", __func__, mode_to_string(p_cb->state), mode_to_string(md_res.mode)); + switch(md_res.mode) + { + case BTM_PM_MD_ACTIVE: + switch(p_cb->state) + { + case BTM_PM_MD_SNIFF: + if (btsnd_hcic_exit_sniff_mode(btm_cb.acl_db[link_ind].hci_handle)) + { + btm_cb.pm_pend_link = link_ind; + } + break; + case BTM_PM_MD_PARK: + if (btsnd_hcic_exit_park_mode(btm_cb.acl_db[link_ind].hci_handle)) + { + btm_cb.pm_pend_link = link_ind; + } + break; + default: + /* Failure btm_cb.pm_pend_link = MAX_L2CAP_LINKS */ + break; + } + break; + + case BTM_PM_MD_HOLD: + if (btsnd_hcic_hold_mode (btm_cb.acl_db[link_ind].hci_handle, + md_res.max, md_res.min)) + { + btm_cb.pm_pend_link = link_ind; + } + break; + + case BTM_PM_MD_SNIFF: + if (btsnd_hcic_sniff_mode (btm_cb.acl_db[link_ind].hci_handle, + md_res.max, md_res.min, md_res.attempt, + md_res.timeout)) + { + btm_cb.pm_pend_link = link_ind; + } + break; + + case BTM_PM_MD_PARK: + if (btsnd_hcic_park_mode (btm_cb.acl_db[link_ind].hci_handle, + md_res.max, md_res.min)) + { + btm_cb.pm_pend_link = link_ind; + } + break; + default: + /* Failure btm_cb.pm_pend_link = MAX_L2CAP_LINKS */ + break; + } + + if(btm_cb.pm_pend_link == MAX_L2CAP_LINKS) + { + /* the command was not sent */ +#if BTM_PM_DEBUG == TRUE + BTM_TRACE_DEBUG( "pm_pend_link: %d",btm_cb.pm_pend_link); +#endif // BTM_PM_DEBUG + return (BTM_NO_RESOURCES); + } + + return BTM_CMD_STARTED; +} + +/******************************************************************************* +** +** Function btm_pm_check_stored +** +** Description This function is called when an HCI command status event occurs +** to check if there's any PM command issued while waiting for +** HCI command status. +** +** Returns none. +** +*******************************************************************************/ +static void btm_pm_check_stored(void) +{ + int xx; + for(xx=0; xx= MAX_L2CAP_LINKS) + return; + + p_cb = &btm_cb.pm_mode_db[btm_cb.pm_pend_link]; + + if(status == HCI_SUCCESS) + { + p_cb->state = BTM_PM_ST_PENDING; + pm_status = BTM_PM_STS_PENDING; +#if BTM_PM_DEBUG == TRUE + BTM_TRACE_DEBUG( "btm_pm_proc_cmd_status new state:0x%x", p_cb->state); +#endif // BTM_PM_DEBUG + } + else /* the command was not successfull. Stay in the same state */ + { + pm_status = BTM_PM_STS_ERROR; + } + + /* notify the caller is appropriate */ + if( (btm_cb.pm_pend_id != BTM_PM_SET_ONLY_ID) && + (btm_cb.pm_reg_db[btm_cb.pm_pend_id].mask & BTM_PM_REG_NOTIF) ) + { + (*btm_cb.pm_reg_db[btm_cb.pm_pend_id].cback)(btm_cb.acl_db[btm_cb.pm_pend_link].remote_addr, pm_status, 0, status); + } + + /* no pending cmd now */ +#if BTM_PM_DEBUG == TRUE + BTM_TRACE_DEBUG( "btm_pm_proc_cmd_status state:0x%x, pm_pend_link: %d(new: %d)", + p_cb->state, btm_cb.pm_pend_link, MAX_L2CAP_LINKS); +#endif // BTM_PM_DEBUG + btm_cb.pm_pend_link = MAX_L2CAP_LINKS; + + btm_pm_check_stored(); +} + +/******************************************************************************* +** +** Function btm_process_mode_change +** +** Description This function is called when an HCI mode change event occurs. +** +** Input Parms hci_status - status of the event (HCI_SUCCESS if no errors) +** hci_handle - connection handle associated with the change +** mode - HCI_MODE_ACTIVE, HCI_MODE_HOLD, HCI_MODE_SNIFF, or HCI_MODE_PARK +** interval - number of baseband slots (meaning depends on mode) +** +** Returns none. +** +*******************************************************************************/ +void btm_pm_proc_mode_change (UINT8 hci_status, UINT16 hci_handle, UINT8 mode, UINT16 interval) +{ + tACL_CONN *p; + tBTM_PM_MCB *p_cb = NULL; + int xx, yy, zz; + tBTM_PM_STATE old_state; + tL2C_LCB *p_lcb; + + /* get the index to acl_db */ + if ((xx = btm_handle_to_acl_index(hci_handle)) >= MAX_L2CAP_LINKS) + return; + + p = &btm_cb.acl_db[xx]; + + /* update control block */ + p_cb = &(btm_cb.pm_mode_db[xx]); + old_state = p_cb->state; + p_cb->state = mode; + p_cb->interval = interval; + + LOG_DEBUG("%s switched from %s to %s.", __func__, mode_to_string(old_state), mode_to_string(p_cb->state)); + + if ((p_lcb = l2cu_find_lcb_by_bd_addr(p->remote_addr, BT_TRANSPORT_BR_EDR)) != NULL) + { + if ((p_cb->state == BTM_PM_ST_ACTIVE) || (p_cb->state == BTM_PM_ST_SNIFF)) + { + /* There might be any pending packets due to SNIFF or PENDING state */ + /* Trigger L2C to start transmission of the pending packets. */ + BTM_TRACE_DEBUG("btm mode change to active; check l2c_link for outgoing packets"); + l2c_link_check_send_pkts(p_lcb, NULL, NULL); + } + } + + /* notify registered parties */ + for(yy=0; yy<=BTM_MAX_PM_RECORDS; yy++) + { + /* set req_mode HOLD mode->ACTIVE */ + if( (mode == BTM_PM_MD_ACTIVE) && (p_cb->req_mode[yy].mode == BTM_PM_MD_HOLD) ) + p_cb->req_mode[yy].mode = BTM_PM_MD_ACTIVE; + } + + /* new request has been made. - post a message to BTU task */ + if(old_state & BTM_PM_STORED_MASK) + { +#if BTM_PM_DEBUG == TRUE + BTM_TRACE_DEBUG( "btm_pm_proc_mode_change: Sending stored req:%d", xx); +#endif // BTM_PM_DEBUG + btm_pm_snd_md_req(BTM_PM_SET_ONLY_ID, xx, NULL); + } + else + { + for(zz=0; zzremote_addr, mode, interval, hci_status); + } + } + + /* If mode change was because of an active role switch or change link key */ + btm_cont_rswitch(p, btm_find_dev(p->remote_addr), hci_status); +} + +/******************************************************************************* +** +** Function btm_pm_proc_ssr_evt +** +** Description This function is called when an HCI sniff subrating event occurs. +** +** Returns none. +** +*******************************************************************************/ +#if (BTM_SSR_INCLUDED == TRUE) +void btm_pm_proc_ssr_evt (UINT8 *p, UINT16 evt_len) +{ + UINT8 status; + UINT16 handle; + UINT16 max_rx_lat; + int xx, yy; + tBTM_PM_MCB *p_cb; + tACL_CONN *p_acl=NULL; + UINT16 use_ssr = TRUE; + UNUSED(evt_len); + + STREAM_TO_UINT8 (status, p); + + STREAM_TO_UINT16 (handle, p); + /* get the index to acl_db */ + if ((xx = btm_handle_to_acl_index(handle)) >= MAX_L2CAP_LINKS) + return; + + p += 2; + STREAM_TO_UINT16 (max_rx_lat, p); + p_cb = &(btm_cb.pm_mode_db[xx]); + + p_acl = &btm_cb.acl_db[xx]; + if(p_cb->interval == max_rx_lat) + { + /* using legacy sniff */ + use_ssr = FALSE; + } + + /* notify registered parties */ + for(yy=0; yyremote_addr, BTM_PM_STS_SSR, use_ssr, status); + } + } + } +} +#endif // BTM_SSR_INCLUDED + +/******************************************************************************* +** +** Function btm_pm_device_in_active_or_sniff_mode +** +** Description This function is called to check if in active or sniff mode +** +** Returns TRUE, if in active or sniff mode +** +*******************************************************************************/ +BOOLEAN btm_pm_device_in_active_or_sniff_mode(void) +{ + /* The active state is the highest state-includes connected device and sniff mode*/ + + /* Covers active and sniff modes */ + if (BTM_GetNumAclLinks() > 0) + { + BTM_TRACE_DEBUG("%s - ACL links: %d", __func__, BTM_GetNumAclLinks()); + return TRUE; + } + +#if ((defined BLE_INCLUDED) && (BLE_INCLUDED == TRUE)) + /* Check BLE states */ + if (btm_ble_get_conn_st() != BLE_CONN_IDLE) + { + BTM_TRACE_DEBUG("%s - BLE state: %x", __func__, btm_ble_get_conn_st()); + return TRUE; + } +#endif + + return FALSE; +} + +/******************************************************************************* +** +** Function btm_pm_device_in_scan_state +** +** Description This function is called to check if in paging, inquiry or connecting mode +** +** Returns TRUE, if in paging, inquiry or connecting mode +** +*******************************************************************************/ +BOOLEAN btm_pm_device_in_scan_state(void) +{ + /* Scan state-paging, inquiry, and trying to connect */ + + /* Check for paging */ + if (btm_cb.is_paging || GKI_queue_length(&btm_cb.page_queue) > 0 || + BTM_BL_PAGING_STARTED == btm_cb.busy_level) + { + BTM_TRACE_DEBUG("btm_pm_device_in_scan_state- paging"); + return TRUE; + } + + /* Check for inquiry */ + if ((btm_cb.btm_inq_vars.inq_active & (BTM_BR_INQ_ACTIVE_MASK | BTM_BLE_INQ_ACTIVE_MASK)) != 0) + { + BTM_TRACE_DEBUG("btm_pm_device_in_scan_state- Inq active"); + return TRUE; + } + + return FALSE; +} + +/******************************************************************************* +** +** Function BTM_PM_ReadControllerState +** +** Description This function is called to obtain the controller state +** +** Returns Controller State-BTM_CONTRL_ACTIVE, BTM_CONTRL_SCAN, and BTM_CONTRL_IDLE +** +*******************************************************************************/ +tBTM_CONTRL_STATE BTM_PM_ReadControllerState(void) +{ + if (TRUE == btm_pm_device_in_active_or_sniff_mode()) + return BTM_CONTRL_ACTIVE; + else + if (TRUE == btm_pm_device_in_scan_state()) + return BTM_CONTRL_SCAN; + else + return BTM_CONTRL_IDLE; +} + +static const char *mode_to_string(tBTM_PM_MODE mode) { + switch (mode) { + case BTM_PM_MD_ACTIVE: return "ACTIVE"; + case BTM_PM_MD_SNIFF: return "SNIFF"; + case BTM_PM_MD_PARK: return "PARK"; + case BTM_PM_MD_HOLD: return "HOLD"; + default: return "UNKNOWN"; + } +} diff --git a/components/bt/bluedroid/stack/btm/btm_sco.c b/components/bt/bluedroid/stack/btm/btm_sco.c new file mode 100755 index 0000000000..12ec4fe554 --- /dev/null +++ b/components/bt/bluedroid/stack/btm/btm_sco.c @@ -0,0 +1,1768 @@ +/****************************************************************************** + * + * Copyright (C) 2000-2012 Broadcom Corporation + * + * 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 functions that handle SCO connections. This includes + * operations such as connect, disconnect, change supported packet types. + * + ******************************************************************************/ + +#include +#include "bt_types.h" +#include "bt_target.h" +#include "gki.h" +#include "bt_types.h" +#include "hcimsgs.h" +#include "btu.h" +#include "btm_api.h" +#include "btm_int.h" +#include "hcidefs.h" +//#include "bt_utils.h" + +#if BTM_SCO_INCLUDED == TRUE + +/********************************************************************************/ +/* L O C A L D A T A D E F I N I T I O N S */ +/********************************************************************************/ + +#define SCO_ST_UNUSED 0 +#define SCO_ST_LISTENING 1 +#define SCO_ST_W4_CONN_RSP 2 +#define SCO_ST_CONNECTING 3 +#define SCO_ST_CONNECTED 4 +#define SCO_ST_DISCONNECTING 5 +#define SCO_ST_PEND_UNPARK 6 +#define SCO_ST_PEND_ROLECHANGE 7 + +/********************************************************************************/ +/* L O C A L F U N C T I O N P R O T O T Y P E S */ +/********************************************************************************/ + +static const tBTM_ESCO_PARAMS btm_esco_defaults = +{ + BTM_64KBITS_RATE, /* TX Bandwidth (64 kbits/sec) */ + BTM_64KBITS_RATE, /* RX Bandwidth (64 kbits/sec) */ + 0x000a, /* 10 ms (HS/HF can use EV3, 2-EV3, 3-EV3) */ + 0x0060, /* Inp Linear, Air CVSD, 2s Comp, 16bit */ + (BTM_SCO_PKT_TYPES_MASK_HV1 + /* Packet Types */ + BTM_SCO_PKT_TYPES_MASK_HV2 + + BTM_SCO_PKT_TYPES_MASK_HV3 + + BTM_SCO_PKT_TYPES_MASK_EV3 + + BTM_SCO_PKT_TYPES_MASK_EV4 + + BTM_SCO_PKT_TYPES_MASK_EV5), + BTM_ESCO_RETRANS_POWER /* Retransmission Effort (Power) */ +}; + +/******************************************************************************* +** +** Function btm_sco_flush_sco_data +** +** Description This function is called to flush the SCO data for this channel. +** +** Returns void +** +*******************************************************************************/ +void btm_sco_flush_sco_data(UINT16 sco_inx) +{ +#if BTM_SCO_HCI_INCLUDED == TRUE +#if (BTM_MAX_SCO_LINKS>0) + tSCO_CONN *p ; + BT_HDR *p_buf; + + if (sco_inx < BTM_MAX_SCO_LINKS) + { + p = &btm_cb.sco_cb.sco_db[sco_inx]; + while (p->xmit_data_q.p_first) + { + if ((p_buf = (BT_HDR *)GKI_dequeue (&p->xmit_data_q)) != NULL) + GKI_freebuf (p_buf); + } + } +#else + UNUSED(sco_inx); +#endif +#else + UNUSED(sco_inx); +#endif +} +/******************************************************************************* +** +** Function btm_sco_init +** +** Description This function is called at BTM startup to initialize +** +** Returns void +** +*******************************************************************************/ +void btm_sco_init (void) +{ +#if 0 /* cleared in btm_init; put back in if called from anywhere else! */ + memset (&btm_cb.sco_cb, 0, sizeof(tSCO_CB)); +#endif + /* Initialize nonzero defaults */ + btm_cb.sco_cb.sco_disc_reason = BTM_INVALID_SCO_DISC_REASON; + + btm_cb.sco_cb.def_esco_parms = btm_esco_defaults; /* Initialize with defaults */ + btm_cb.sco_cb.desired_sco_mode = BTM_DEFAULT_SCO_MODE; +} + +/******************************************************************************* +** +** Function btm_esco_conn_rsp +** +** Description This function is called upon receipt of an (e)SCO connection +** request event (BTM_ESCO_CONN_REQ_EVT) to accept or reject +** the request. Parameters used to negotiate eSCO links. +** If p_parms is NULL, then default values are used. +** If the link type of the incoming request is SCO, then only +** the tx_bw, max_latency, content format, and packet_types are +** valid. The hci_status parameter should be +** ([0x0] to accept, [0x0d..0x0f] to reject) +** +** Returns void +** +*******************************************************************************/ +static void btm_esco_conn_rsp (UINT16 sco_inx, UINT8 hci_status, BD_ADDR bda, + tBTM_ESCO_PARAMS *p_parms) +{ +#if (BTM_MAX_SCO_LINKS>0) + tSCO_CONN *p_sco = NULL; + tBTM_ESCO_PARAMS *p_setup; + UINT16 temp_pkt_types; + + if (sco_inx < BTM_MAX_SCO_LINKS) + p_sco = &btm_cb.sco_cb.sco_db[sco_inx]; + + /* Reject the connect request if refused by caller or wrong state */ + if (hci_status != HCI_SUCCESS || p_sco == NULL) + { + if (p_sco) + { + p_sco->state = (p_sco->state == SCO_ST_W4_CONN_RSP) ? SCO_ST_LISTENING + : SCO_ST_UNUSED; + } + + if (!btm_cb.sco_cb.esco_supported) + { + if (!btsnd_hcic_reject_conn (bda, hci_status)) + { + BTM_TRACE_ERROR("Could not reject (e)SCO conn: No Buffer!!!"); + } + } + else + { + if (!btsnd_hcic_reject_esco_conn (bda, hci_status)) + { + BTM_TRACE_ERROR("Could not reject (e)SCO conn: No Buffer!!!"); + } + } + } + else /* Connection is being accepted */ + { + p_sco->state = SCO_ST_CONNECTING; + p_setup = &p_sco->esco.setup; + /* If parameters not specified use the default */ + if (p_parms) + *p_setup = *p_parms; + else /* Use the last setup passed thru BTM_SetEscoMode (or defaults) */ + { + *p_setup = btm_cb.sco_cb.def_esco_parms; + } + + temp_pkt_types = (p_setup->packet_types & + BTM_SCO_SUPPORTED_PKTS_MASK & + btm_cb.btm_sco_pkt_types_supported); + + /* Make sure at least one eSCO packet type is sent, else might confuse peer */ + /* Taking this out to confirm with BQB tests + ** Real application would like to include this though, as many devices + ** do not retry with SCO only if an eSCO connection fails. + if (!(temp_pkt_types & BTM_ESCO_LINK_ONLY_MASK)) + { + temp_pkt_types |= BTM_SCO_PKT_TYPES_MASK_EV3; + } + */ + /* If SCO request, remove eSCO packet types (conformance) */ + if (p_sco->esco.data.link_type == BTM_LINK_TYPE_SCO) + { + temp_pkt_types &= BTM_SCO_LINK_ONLY_MASK; + temp_pkt_types |= BTM_SCO_EXCEPTION_PKTS_MASK; + } + else + { + /* OR in any exception packet types */ + temp_pkt_types |= ((p_setup->packet_types & BTM_SCO_EXCEPTION_PKTS_MASK) | + (btm_cb.btm_sco_pkt_types_supported & BTM_SCO_EXCEPTION_PKTS_MASK)); + } + + if (btsnd_hcic_accept_esco_conn (bda, p_setup->tx_bw, p_setup->rx_bw, + p_setup->max_latency, p_setup->voice_contfmt, + p_setup->retrans_effort, temp_pkt_types)) + { + p_setup->packet_types = temp_pkt_types; + } + else + { + BTM_TRACE_ERROR("Could not accept SCO conn: No Buffer!!!"); + } + } +#endif +} + + +#if BTM_SCO_HCI_INCLUDED == TRUE +/******************************************************************************* +** +** Function btm_sco_check_send_pkts +** +** Description This function is called to check if it can send packets +** to the Host Controller. +** +** Returns void +** +*******************************************************************************/ +void btm_sco_check_send_pkts (UINT16 sco_inx) +{ + BT_HDR *p_buf; + tSCO_CB *p_cb = &btm_cb.sco_cb; + tSCO_CONN *p_ccb = &p_cb->sco_db[sco_inx]; + + /* If there is data to send, send it now */ + while (p_ccb->xmit_data_q.p_first != NULL) + { + p_buf = NULL; + +#if BTM_SCO_HCI_DEBUG + BTM_TRACE_DEBUG ("btm: [%d] buf in xmit_data_q", p_ccb->xmit_data_q.count ); +#endif + p_buf = (BT_HDR *)GKI_dequeue (&p_ccb->xmit_data_q); + + HCI_SCO_DATA_TO_LOWER (p_buf); + } +} +#endif /* BTM_SCO_HCI_INCLUDED == TRUE */ + +/******************************************************************************* +** +** Function btm_route_sco_data +** +** Description Route received SCO data. +** +** Returns void +** +*******************************************************************************/ +void btm_route_sco_data(BT_HDR *p_msg) +{ +#if BTM_SCO_HCI_INCLUDED == TRUE + UINT16 sco_inx, handle; + UINT8 *p = (UINT8 *)(p_msg + 1) + p_msg->offset; + UINT8 pkt_size = 0; + UINT8 pkt_status = 0; + + /* Extract Packet_Status_Flag and handle */ + STREAM_TO_UINT16 (handle, p); + pkt_status = HCID_GET_EVENT(handle); + handle = HCID_GET_HANDLE (handle); + + STREAM_TO_UINT8 (pkt_size, p); + + if ((sco_inx = btm_find_scb_by_handle(handle)) != BTM_MAX_SCO_LINKS ) + { + /* send data callback */ + if (!btm_cb.sco_cb.p_data_cb ) + /* if no data callback registered, just free the buffer */ + GKI_freebuf (p_msg); + else + { + (*btm_cb.sco_cb.p_data_cb)(sco_inx, p_msg, (tBTM_SCO_DATA_FLAG) pkt_status); + } + } + else /* no mapping handle SCO connection is active, free the buffer */ + { + GKI_freebuf (p_msg); + } +#else + GKI_freebuf(p_msg); +#endif +} + +/******************************************************************************* +** +** Function BTM_WriteScoData +** +** Description This function write SCO data to a specified instance. The data +** to be written p_buf needs to carry an offset of +** HCI_SCO_PREAMBLE_SIZE bytes, and the data length can not +** exceed BTM_SCO_DATA_SIZE_MAX bytes, whose default value is set +** to 60 and is configurable. Data longer than the maximum bytes +** will be truncated. +** +** Returns BTM_SUCCESS: data write is successful +** BTM_ILLEGAL_VALUE: SCO data contains illegal offset value. +** BTM_SCO_BAD_LENGTH: SCO data length exceeds the max SCO packet +** size. +** BTM_NO_RESOURCES: no resources. +** BTM_UNKNOWN_ADDR: unknown SCO connection handle, or SCO is not +** routed via HCI. +** +** +*******************************************************************************/ +tBTM_STATUS BTM_WriteScoData (UINT16 sco_inx, BT_HDR *p_buf) +{ +#if (BTM_SCO_HCI_INCLUDED == TRUE) && (BTM_MAX_SCO_LINKS>0) + tSCO_CONN *p_ccb = &btm_cb.sco_cb.sco_db[sco_inx]; + UINT8 *p; + tBTM_STATUS status = BTM_SUCCESS; + + if (sco_inx < BTM_MAX_SCO_LINKS && btm_cb.sco_cb.p_data_cb && + p_ccb->state == SCO_ST_CONNECTED) + { + /* Ensure we have enough space in the buffer for the SCO and HCI headers */ + if (p_buf->offset < HCI_SCO_PREAMBLE_SIZE) + { + BTM_TRACE_ERROR ("BTM SCO - cannot send buffer, offset: %d", p_buf->offset); + GKI_freebuf (p_buf); + status = BTM_ILLEGAL_VALUE; + } + else /* write HCI header */ + { + /* Step back 3 bytes to add the headers */ + p_buf->offset -= HCI_SCO_PREAMBLE_SIZE; + /* Set the pointer to the beginning of the data */ + p = (UINT8 *)(p_buf + 1) + p_buf->offset; + /* add HCI handle */ + UINT16_TO_STREAM (p, p_ccb->hci_handle); + /* only sent the first BTM_SCO_DATA_SIZE_MAX bytes data if more than max, + and set warning status */ + if (p_buf->len > BTM_SCO_DATA_SIZE_MAX) + { + p_buf->len = BTM_SCO_DATA_SIZE_MAX; + status = BTM_SCO_BAD_LENGTH; + } + + UINT8_TO_STREAM (p, (UINT8)p_buf->len); + p_buf->len += HCI_SCO_PREAMBLE_SIZE; + + GKI_enqueue (&p_ccb->xmit_data_q, p_buf); + + btm_sco_check_send_pkts (sco_inx); + } + } + else + { + GKI_freebuf(p_buf); + + BTM_TRACE_WARNING ("BTM_WriteScoData, invalid sco index: %d at state [%d]", + sco_inx, btm_cb.sco_cb.sco_db[sco_inx].state); + status = BTM_UNKNOWN_ADDR; + } + + return (status); + +#else + UNUSED(sco_inx); + UNUSED(p_buf); + return (BTM_NO_RESOURCES); +#endif +} + +#if (BTM_MAX_SCO_LINKS>0) +/******************************************************************************* +** +** Function btm_send_connect_request +** +** Description This function is called to respond to SCO connect indications +** +** Returns void +** +*******************************************************************************/ +static tBTM_STATUS btm_send_connect_request(UINT16 acl_handle, + tBTM_ESCO_PARAMS *p_setup) +{ + UINT16 temp_pkt_types; + UINT8 xx; + tACL_CONN *p_acl; + + /* Send connect request depending on version of spec */ + if (!btm_cb.sco_cb.esco_supported) + { + if (!btsnd_hcic_add_SCO_conn (acl_handle, BTM_ESCO_2_SCO(p_setup->packet_types))) + return (BTM_NO_RESOURCES); + } + else + { + temp_pkt_types = (p_setup->packet_types & BTM_SCO_SUPPORTED_PKTS_MASK & + btm_cb.btm_sco_pkt_types_supported); + + /* OR in any exception packet types */ + temp_pkt_types |= ((p_setup->packet_types & BTM_SCO_EXCEPTION_PKTS_MASK) | + (btm_cb.btm_sco_pkt_types_supported & BTM_SCO_EXCEPTION_PKTS_MASK)); + + /* Finally, remove EDR eSCO if the remote device doesn't support it */ + /* UPF25: Only SCO was brought up in this case */ + btm_handle_to_acl_index(acl_handle); + if ((xx = btm_handle_to_acl_index(acl_handle)) < MAX_L2CAP_LINKS) + { + p_acl = &btm_cb.acl_db[xx]; + if (!HCI_EDR_ESCO_2MPS_SUPPORTED(p_acl->peer_lmp_features[HCI_EXT_FEATURES_PAGE_0])) + { + + BTM_TRACE_WARNING("BTM Remote does not support 2-EDR eSCO"); + temp_pkt_types |= (HCI_ESCO_PKT_TYPES_MASK_NO_2_EV3 | + HCI_ESCO_PKT_TYPES_MASK_NO_2_EV5); + } + if (!HCI_EDR_ESCO_3MPS_SUPPORTED(p_acl->peer_lmp_features[HCI_EXT_FEATURES_PAGE_0])) + { + + BTM_TRACE_WARNING("BTM Remote does not support 3-EDR eSCO"); + temp_pkt_types |= (HCI_ESCO_PKT_TYPES_MASK_NO_3_EV3 | + HCI_ESCO_PKT_TYPES_MASK_NO_3_EV5); + } + + /* Check to see if BR/EDR Secure Connections is being used + ** If so, we cannot use SCO-only packet types (HFP 1.7) + */ + if (BTM_BothEndsSupportSecureConnections(p_acl->remote_addr)) + { + temp_pkt_types &= ~(BTM_SCO_PKT_TYPE_MASK); + BTM_TRACE_DEBUG("%s: SCO Conn: pkt_types after removing SCO (0x%04x)", __FUNCTION__, + temp_pkt_types); + + /* Return error if no packet types left */ + if (temp_pkt_types == 0) + { + BTM_TRACE_ERROR("%s: SCO Conn (BR/EDR SC): No packet types available", + __FUNCTION__); + return (BTM_WRONG_MODE); + } + } + else + { + BTM_TRACE_DEBUG("%s: SCO Conn(BR/EDR SC):local or peer does not support BR/EDR SC", + __FUNCTION__); + } + } + + + BTM_TRACE_API(" txbw 0x%x, rxbw 0x%x, lat 0x%x, voice 0x%x, retrans 0x%02x, pkt 0x%04x", + p_setup->tx_bw, p_setup->rx_bw, + p_setup->max_latency, p_setup->voice_contfmt, + p_setup->retrans_effort, temp_pkt_types); + + if (!btsnd_hcic_setup_esco_conn(acl_handle, + p_setup->tx_bw, + p_setup->rx_bw, + p_setup->max_latency, + p_setup->voice_contfmt, + p_setup->retrans_effort, + temp_pkt_types)) + return (BTM_NO_RESOURCES); + else + p_setup->packet_types = temp_pkt_types; + } + + return (BTM_CMD_STARTED); +} +#endif + +/******************************************************************************* +** +** Function btm_set_sco_ind_cback +** +** Description This function is called to register for TCS SCO connect +** indications. +** +** Returns void +** +*******************************************************************************/ +void btm_set_sco_ind_cback( tBTM_SCO_IND_CBACK *sco_ind_cb ) +{ + btm_cb.sco_cb.app_sco_ind_cb = sco_ind_cb; +} + +/******************************************************************************* +** +** Function btm_accept_sco_link +** +** Description This function is called to respond to TCS SCO connect +** indications +** +** Returns void +** +*******************************************************************************/ +void btm_accept_sco_link(UINT16 sco_inx, tBTM_ESCO_PARAMS *p_setup, + tBTM_SCO_CB *p_conn_cb, tBTM_SCO_CB *p_disc_cb) +{ +#if (BTM_MAX_SCO_LINKS>0) + tSCO_CONN *p_sco; + + if (sco_inx >= BTM_MAX_SCO_LINKS) + { + BTM_TRACE_ERROR("btm_accept_sco_link: Invalid sco_inx(%d)", sco_inx); + return; + } + + /* Link role is ignored in for this message */ + p_sco = &btm_cb.sco_cb.sco_db[sco_inx]; + p_sco->p_conn_cb = p_conn_cb; + p_sco->p_disc_cb = p_disc_cb; + p_sco->esco.data.link_type = BTM_LINK_TYPE_ESCO; /* Accept with all supported types */ + + BTM_TRACE_DEBUG("TCS accept SCO: Packet Types 0x%04x", p_setup->packet_types); + + btm_esco_conn_rsp(sco_inx, HCI_SUCCESS, p_sco->esco.data.bd_addr, p_setup); +#else + btm_reject_sco_link(sco_inx); +#endif +} + +/******************************************************************************* +** +** Function btm_reject_sco_link +** +** Description This function is called to respond to SCO connect indications +** +** Returns void +** +*******************************************************************************/ +void btm_reject_sco_link( UINT16 sco_inx ) +{ + btm_esco_conn_rsp(sco_inx, HCI_ERR_HOST_REJECT_RESOURCES, + btm_cb.sco_cb.sco_db[sco_inx].esco.data.bd_addr, NULL); +} + +/******************************************************************************* +** +** Function BTM_CreateSco +** +** Description This function is called to create an SCO connection. If the +** "is_orig" flag is TRUE, the connection will be originated, +** otherwise BTM will wait for the other side to connect. +** +** NOTE: If BTM_IGNORE_SCO_PKT_TYPE is passed in the pkt_types +** parameter the default packet types is used. +** +** Returns BTM_UNKNOWN_ADDR if the ACL connection is not up +** BTM_BUSY if another SCO being set up to +** the same BD address +** BTM_NO_RESOURCES if the max SCO limit has been reached +** BTM_CMD_STARTED if the connection establishment is started. +** In this case, "*p_sco_inx" is filled in +** with the sco index used for the connection. +** +*******************************************************************************/ +tBTM_STATUS BTM_CreateSco (BD_ADDR remote_bda, BOOLEAN is_orig, UINT16 pkt_types, + UINT16 *p_sco_inx, tBTM_SCO_CB *p_conn_cb, + tBTM_SCO_CB *p_disc_cb) +{ +#if (BTM_MAX_SCO_LINKS > 0) + tBTM_ESCO_PARAMS *p_setup; + tSCO_CONN *p = &btm_cb.sco_cb.sco_db[0]; + UINT16 xx; + UINT16 acl_handle = 0; + UINT16 temp_pkt_types; + tACL_CONN *p_acl; + +#if (BTM_SCO_WAKE_PARKED_LINK == TRUE) + tBTM_PM_MODE md; + tBTM_PM_PWR_MD pm; +#else // BTM_SCO_WAKE_PARKED_LINK + UINT8 mode; +#endif // BTM_SCO_WAKE_PARKED_LINK + + *p_sco_inx = BTM_INVALID_SCO_INDEX; + + /* If originating, ensure that there is an ACL connection to the BD Address */ + if (is_orig) + { + if ((!remote_bda) || ((acl_handle = BTM_GetHCIConnHandle (remote_bda, BT_TRANSPORT_BR_EDR)) == 0xFFFF)) + return (BTM_UNKNOWN_ADDR); + } + + if (remote_bda) + { + /* If any SCO is being established to the remote BD address, refuse this */ + for (xx = 0; xx < BTM_MAX_SCO_LINKS; xx++, p++) + { + if (((p->state == SCO_ST_CONNECTING) || (p->state == SCO_ST_LISTENING) + || (p->state == SCO_ST_PEND_UNPARK)) + && (!memcmp (p->esco.data.bd_addr, remote_bda, BD_ADDR_LEN))) + { + return (BTM_BUSY); + } + } + } + else + { + /* Support only 1 wildcard BD address at a time */ + for (xx = 0; xx < BTM_MAX_SCO_LINKS; xx++, p++) + { + if ((p->state == SCO_ST_LISTENING) && (!p->rem_bd_known)) + return (BTM_BUSY); + } + } + + /* Now, try to find an unused control block, and kick off the SCO establishment */ + for (xx = 0, p = &btm_cb.sco_cb.sco_db[0]; xx < BTM_MAX_SCO_LINKS; xx++, p++) + { + if (p->state == SCO_ST_UNUSED) + { + if (remote_bda) + { + if (is_orig) + { + /* can not create SCO link if in park mode */ +#if BTM_SCO_WAKE_PARKED_LINK == TRUE + if(BTM_ReadPowerMode(remote_bda, &md) == BTM_SUCCESS) + { + if (md == BTM_PM_MD_PARK || md == BTM_PM_MD_SNIFF) + { + memset( (void*)&pm, 0, sizeof(pm)); + pm.mode = BTM_PM_MD_ACTIVE; + BTM_SetPowerMode(BTM_PM_SET_ONLY_ID, remote_bda, &pm); + p->state = SCO_ST_PEND_UNPARK; + } + } +#else // BTM_SCO_WAKE_PARKED_LINK + if( (BTM_ReadPowerMode(remote_bda, &mode) == BTM_SUCCESS) && (mode == BTM_PM_MD_PARK) ) + return (BTM_WRONG_MODE); +#endif // BTM_SCO_WAKE_PARKED_LINK + } + memcpy (p->esco.data.bd_addr, remote_bda, BD_ADDR_LEN); + p->rem_bd_known = TRUE; + } + else + p->rem_bd_known = FALSE; + + /* Link role is ignored in for this message */ + if (pkt_types == BTM_IGNORE_SCO_PKT_TYPE) + pkt_types = btm_cb.sco_cb.def_esco_parms.packet_types; + + p_setup = &p->esco.setup; + *p_setup = btm_cb.sco_cb.def_esco_parms; + p_setup->packet_types = (btm_cb.sco_cb.desired_sco_mode == BTM_LINK_TYPE_SCO) + ? (pkt_types & BTM_SCO_LINK_ONLY_MASK) : pkt_types; + + temp_pkt_types = (p_setup->packet_types & BTM_SCO_SUPPORTED_PKTS_MASK & + btm_cb.btm_sco_pkt_types_supported); + + /* OR in any exception packet types */ + if (btm_cb.sco_cb.desired_sco_mode == HCI_LINK_TYPE_ESCO) + { + temp_pkt_types |= ((p_setup->packet_types & BTM_SCO_EXCEPTION_PKTS_MASK) | + (btm_cb.btm_sco_pkt_types_supported & BTM_SCO_EXCEPTION_PKTS_MASK)); + } + else /* Only using SCO packet types; turn off EDR also */ + { + temp_pkt_types |= BTM_SCO_EXCEPTION_PKTS_MASK; + } + + p_setup->packet_types = temp_pkt_types; + p->p_conn_cb = p_conn_cb; + p->p_disc_cb = p_disc_cb; + p->hci_handle = BTM_INVALID_HCI_HANDLE; + p->is_orig = is_orig; + + if( p->state != SCO_ST_PEND_UNPARK ) + { + if (is_orig) + { + /* If role change is in progress, do not proceed with SCO setup + * Wait till role change is complete */ + p_acl = btm_bda_to_acl(remote_bda, BT_TRANSPORT_BR_EDR); + if (p_acl && p_acl->switch_role_state != BTM_ACL_SWKEY_STATE_IDLE) + { + BTM_TRACE_API("Role Change is in progress for ACL handle 0x%04x",acl_handle); + p->state = SCO_ST_PEND_ROLECHANGE; + + } + } + } + + if( p->state != SCO_ST_PEND_UNPARK && p->state != SCO_ST_PEND_ROLECHANGE ) + { + if (is_orig) + { + BTM_TRACE_API("BTM_CreateSco -> (e)SCO Link for ACL handle 0x%04x, Desired Type %d", + acl_handle, btm_cb.sco_cb.desired_sco_mode); + + if ((btm_send_connect_request(acl_handle, p_setup)) != BTM_CMD_STARTED) + return (BTM_NO_RESOURCES); + + p->state = SCO_ST_CONNECTING; + } + else + p->state = SCO_ST_LISTENING; + } + + *p_sco_inx = xx; + + return (BTM_CMD_STARTED); + } + } + +#endif + /* If here, all SCO blocks in use */ + return (BTM_NO_RESOURCES); +} + +#if (BTM_SCO_WAKE_PARKED_LINK == TRUE) +/******************************************************************************* +** +** Function btm_sco_chk_pend_unpark +** +** Description This function is called by BTIF when there is a mode change +** event to see if there are SCO commands waiting for the unpark. +** +** Returns void +** +*******************************************************************************/ +void btm_sco_chk_pend_unpark (UINT8 hci_status, UINT16 hci_handle) +{ +#if (BTM_MAX_SCO_LINKS>0) + UINT16 xx; + UINT16 acl_handle; + tSCO_CONN *p = &btm_cb.sco_cb.sco_db[0]; + + for (xx = 0; xx < BTM_MAX_SCO_LINKS; xx++, p++) + { + if ((p->state == SCO_ST_PEND_UNPARK) && + ((acl_handle = BTM_GetHCIConnHandle (p->esco.data.bd_addr, BT_TRANSPORT_BR_EDR)) == hci_handle)) + + { + BTM_TRACE_API("btm_sco_chk_pend_unpark -> (e)SCO Link for ACL handle 0x%04x, Desired Type %d, hci_status 0x%02x", + acl_handle, btm_cb.sco_cb.desired_sco_mode, hci_status); + + if ((btm_send_connect_request(acl_handle, &p->esco.setup)) == BTM_CMD_STARTED) + p->state = SCO_ST_CONNECTING; + } + } +#endif // BTM_MAX_SCO_LINKS +} +#endif // BTM_SCO_WAKE_PARKED_LINK + +/******************************************************************************* +** +** Function btm_sco_chk_pend_rolechange +** +** Description This function is called by BTIF when there is a role change +** event to see if there are SCO commands waiting for the role change. +** +** Returns void +** +*******************************************************************************/ +void btm_sco_chk_pend_rolechange (UINT16 hci_handle) +{ +#if (BTM_MAX_SCO_LINKS>0) + UINT16 xx; + UINT16 acl_handle; + tSCO_CONN *p = &btm_cb.sco_cb.sco_db[0]; + + for (xx = 0; xx < BTM_MAX_SCO_LINKS; xx++, p++) + { + if ((p->state == SCO_ST_PEND_ROLECHANGE) && + ((acl_handle = BTM_GetHCIConnHandle (p->esco.data.bd_addr, BT_TRANSPORT_BR_EDR)) == hci_handle)) + + { + BTM_TRACE_API("btm_sco_chk_pend_rolechange -> (e)SCO Link for ACL handle 0x%04x", acl_handle); + + if ((btm_send_connect_request(acl_handle, &p->esco.setup)) == BTM_CMD_STARTED) + p->state = SCO_ST_CONNECTING; + } + } +#endif +} + +/******************************************************************************* +** +** Function btm_sco_conn_req +** +** Description This function is called by BTIF when an SCO connection +** request is received from a remote. +** +** Returns void +** +*******************************************************************************/ +void btm_sco_conn_req (BD_ADDR bda, DEV_CLASS dev_class, UINT8 link_type) +{ +#if (BTM_MAX_SCO_LINKS>0) + tSCO_CB *p_sco = &btm_cb.sco_cb; + tSCO_CONN *p = &p_sco->sco_db[0]; + UINT16 xx; + tBTM_ESCO_CONN_REQ_EVT_DATA evt_data; + + for (xx = 0; xx < BTM_MAX_SCO_LINKS; xx++, p++) + { + /* + * If the sco state is in the SCO_ST_CONNECTING state, we still need + * to return accept sco to avoid race conditon for sco creation + */ + int rem_bd_matches = p->rem_bd_known && + !memcmp (p->esco.data.bd_addr, bda, BD_ADDR_LEN); + if (((p->state == SCO_ST_CONNECTING) && rem_bd_matches) || + ((p->state == SCO_ST_LISTENING) && (rem_bd_matches || !p->rem_bd_known))) + { + /* If this guy was a wildcard, he is not one any more */ + p->rem_bd_known = TRUE; + p->esco.data.link_type = link_type; + p->state = SCO_ST_W4_CONN_RSP; + memcpy (p->esco.data.bd_addr, bda, BD_ADDR_LEN); + + /* If no callback, auto-accept the connection if packet types match */ + if (!p->esco.p_esco_cback) + { + /* If requesting eSCO reject if default parameters are SCO only */ + if ((link_type == BTM_LINK_TYPE_ESCO + && !(p_sco->def_esco_parms.packet_types & BTM_ESCO_LINK_ONLY_MASK) + && ((p_sco->def_esco_parms.packet_types & BTM_SCO_EXCEPTION_PKTS_MASK) + == BTM_SCO_EXCEPTION_PKTS_MASK)) + + /* Reject request if SCO is desired but no SCO packets delected */ + || (link_type == BTM_LINK_TYPE_SCO + && !(p_sco->def_esco_parms.packet_types & BTM_SCO_LINK_ONLY_MASK))) + { + btm_esco_conn_rsp(xx, HCI_ERR_HOST_REJECT_RESOURCES, bda, NULL); + } + else /* Accept the request */ + { + btm_esco_conn_rsp(xx, HCI_SUCCESS, bda, NULL); + } + } + else /* Notify upper layer of connect indication */ + { + memcpy(evt_data.bd_addr, bda, BD_ADDR_LEN); + memcpy(evt_data.dev_class, dev_class, DEV_CLASS_LEN); + evt_data.link_type = link_type; + evt_data.sco_inx = xx; + p->esco.p_esco_cback(BTM_ESCO_CONN_REQ_EVT, (tBTM_ESCO_EVT_DATA *)&evt_data); + } + + return; + } + } + + /* TCS usage */ + if (btm_cb.sco_cb.app_sco_ind_cb) + { + /* Now, try to find an unused control block */ + for (xx = 0, p = &btm_cb.sco_cb.sco_db[0]; xx < BTM_MAX_SCO_LINKS; xx++, p++) + { + if (p->state == SCO_ST_UNUSED) + { + p->is_orig = FALSE; + p->state = SCO_ST_LISTENING; + + p->esco.data.link_type = link_type; + memcpy (p->esco.data.bd_addr, bda, BD_ADDR_LEN); + p->rem_bd_known = TRUE; + break; + } + } + if( xx < BTM_MAX_SCO_LINKS) + { + btm_cb.sco_cb.app_sco_ind_cb(xx); + return; + } + } + +#endif + /* If here, no one wants the SCO connection. Reject it */ + BTM_TRACE_WARNING("btm_sco_conn_req: No one wants this SCO connection; rejecting it"); + btm_esco_conn_rsp(BTM_MAX_SCO_LINKS, HCI_ERR_HOST_REJECT_RESOURCES, bda, NULL); +} + +/******************************************************************************* +** +** Function btm_sco_connected +** +** Description This function is called by BTIF when an (e)SCO connection +** is connected. +** +** Returns void +** +*******************************************************************************/ +void btm_sco_connected (UINT8 hci_status, BD_ADDR bda, UINT16 hci_handle, + tBTM_ESCO_DATA *p_esco_data) +{ +#if (BTM_MAX_SCO_LINKS>0) + tSCO_CONN *p = &btm_cb.sco_cb.sco_db[0]; + UINT16 xx; + BOOLEAN spt = FALSE; + tBTM_CHG_ESCO_PARAMS parms; +#endif + + btm_cb.sco_cb.sco_disc_reason = hci_status; + +#if (BTM_MAX_SCO_LINKS>0) + for (xx = 0; xx < BTM_MAX_SCO_LINKS; xx++, p++) + { + if (((p->state == SCO_ST_CONNECTING) || + (p->state == SCO_ST_LISTENING) || + (p->state == SCO_ST_W4_CONN_RSP)) + && (p->rem_bd_known) + && (!bda || !memcmp (p->esco.data.bd_addr, bda, BD_ADDR_LEN))) + { + if (hci_status != HCI_SUCCESS) + { + /* Report the error if originator, otherwise remain in Listen mode */ + if (p->is_orig) + { + /* If role switch is pending, we need try again after role switch is complete */ + if(hci_status == HCI_ERR_ROLE_SWITCH_PENDING) + { + BTM_TRACE_API("Role Change pending for HCI handle 0x%04x",hci_handle); + p->state = SCO_ST_PEND_ROLECHANGE; + } + /* avoid calling disconnect callback because of sco creation race */ + else if (hci_status != HCI_ERR_LMP_ERR_TRANS_COLLISION) + { + p->state = SCO_ST_UNUSED; + (*p->p_disc_cb)(xx); + } + } + else + { + /* Notify the upper layer that incoming sco connection has failed. */ + if (p->state == SCO_ST_CONNECTING) + { + p->state = SCO_ST_UNUSED; + (*p->p_disc_cb)(xx); + } + else + p->state = SCO_ST_LISTENING; + } + + return; + } + + if (p->state == SCO_ST_LISTENING) + spt = TRUE; + + p->state = SCO_ST_CONNECTED; + p->hci_handle = hci_handle; + + if (!btm_cb.sco_cb.esco_supported) + { + p->esco.data.link_type = BTM_LINK_TYPE_SCO; + if (spt) + { + parms.packet_types = p->esco.setup.packet_types; + /* Keep the other parameters the same for SCO */ + parms.max_latency = p->esco.setup.max_latency; + parms.retrans_effort = p->esco.setup.retrans_effort; + + BTM_ChangeEScoLinkParms(xx, &parms); + } + } + else + { + if (p_esco_data) + p->esco.data = *p_esco_data; + } + + (*p->p_conn_cb)(xx); + + return; + } + } +#endif +} + + +/******************************************************************************* +** +** Function btm_find_scb_by_handle +** +** Description Look through all active SCO connection for a match based on the +** HCI handle. +** +** Returns index to matched SCO connection CB, or BTM_MAX_SCO_LINKS if +** no match. +** +*******************************************************************************/ +UINT16 btm_find_scb_by_handle (UINT16 handle) +{ + int xx; + tSCO_CONN *p = &btm_cb.sco_cb.sco_db[0]; + + for (xx = 0; xx < BTM_MAX_SCO_LINKS; xx++, p++) + { + if ((p->state == SCO_ST_CONNECTED) && (p->hci_handle == handle)) + { + return (xx); + } + } + + /* If here, no match found */ + return (xx); +} + +/******************************************************************************* +** +** Function BTM_RemoveSco +** +** Description This function is called to remove a specific SCO connection. +** +** Returns status of the operation +** +*******************************************************************************/ +tBTM_STATUS BTM_RemoveSco (UINT16 sco_inx) +{ +#if (BTM_MAX_SCO_LINKS>0) + tSCO_CONN *p = &btm_cb.sco_cb.sco_db[sco_inx]; + UINT16 tempstate; + + /* Validity check */ + if ((sco_inx >= BTM_MAX_SCO_LINKS) || (p->state == SCO_ST_UNUSED)) + return (BTM_UNKNOWN_ADDR); + + /* If no HCI handle, simply drop the connection and return */ + if (p->hci_handle == BTM_INVALID_HCI_HANDLE || p->state == SCO_ST_PEND_UNPARK) + { + p->hci_handle = BTM_INVALID_HCI_HANDLE; + p->state = SCO_ST_UNUSED; + p->esco.p_esco_cback = NULL; /* Deregister the eSCO event callback */ + return (BTM_SUCCESS); + } + + tempstate = p->state; + p->state = SCO_ST_DISCONNECTING; + + if (!btsnd_hcic_disconnect (p->hci_handle, HCI_ERR_PEER_USER)) + { + p->state = tempstate; + return (BTM_NO_RESOURCES); + } + + return (BTM_CMD_STARTED); +#else + return (BTM_NO_RESOURCES); +#endif +} + +/******************************************************************************* +** +** Function btm_remove_sco_links +** +** Description This function is called to remove all sco links for an ACL link. +** +** Returns void +** +*******************************************************************************/ +void btm_remove_sco_links (BD_ADDR bda) +{ +#if (BTM_MAX_SCO_LINKS>0) + tSCO_CONN *p = &btm_cb.sco_cb.sco_db[0]; + UINT16 xx; + + for (xx = 0; xx < BTM_MAX_SCO_LINKS; xx++, p++) + { + if (p->rem_bd_known && (!memcmp (p->esco.data.bd_addr, bda, BD_ADDR_LEN))) + { + BTM_RemoveSco(xx); + } + } +#endif +} + +/******************************************************************************* +** +** Function btm_sco_removed +** +** Description This function is called by BTIF when an SCO connection +** is removed. +** +** Returns void +** +*******************************************************************************/ +void btm_sco_removed (UINT16 hci_handle, UINT8 reason) +{ +#if (BTM_MAX_SCO_LINKS>0) + tSCO_CONN *p = &btm_cb.sco_cb.sco_db[0]; + UINT16 xx; +#endif + + btm_cb.sco_cb.sco_disc_reason = reason; + +#if (BTM_MAX_SCO_LINKS>0) + p = &btm_cb.sco_cb.sco_db[0]; + for (xx = 0; xx < BTM_MAX_SCO_LINKS; xx++, p++) + { + if ((p->state != SCO_ST_UNUSED) && (p->state != SCO_ST_LISTENING) && (p->hci_handle == hci_handle)) + { + btm_sco_flush_sco_data(xx); + + p->state = SCO_ST_UNUSED; + p->hci_handle = BTM_INVALID_HCI_HANDLE; + p->rem_bd_known = FALSE; + p->esco.p_esco_cback = NULL; /* Deregister eSCO callback */ + (*p->p_disc_cb)(xx); + + return; + } + } +#endif +} + + +/******************************************************************************* +** +** Function btm_sco_acl_removed +** +** Description This function is called when an ACL connection is +** removed. If the BD address is NULL, it is assumed that +** the local device is down, and all SCO links are removed. +** If a specific BD address is passed, only SCO connections +** to that BD address are removed. +** +** Returns void +** +*******************************************************************************/ +void btm_sco_acl_removed (BD_ADDR bda) +{ +#if (BTM_MAX_SCO_LINKS>0) + tSCO_CONN *p = &btm_cb.sco_cb.sco_db[0]; + UINT16 xx; + + for (xx = 0; xx < BTM_MAX_SCO_LINKS; xx++, p++) + { + if (p->state != SCO_ST_UNUSED) + { + if ((!bda) || (!memcmp (p->esco.data.bd_addr, bda, BD_ADDR_LEN) && p->rem_bd_known)) + { + btm_sco_flush_sco_data(xx); + + p->state = SCO_ST_UNUSED; + p->esco.p_esco_cback = NULL; /* Deregister eSCO callback */ + (*p->p_disc_cb)(xx); + } + } + } +#endif +} + + +/******************************************************************************* +** +** Function BTM_SetScoPacketTypes +** +** Description This function is called to set the packet types used for +** a specific SCO connection, +** +** Parameters pkt_types - One or more of the following +** BTM_SCO_PKT_TYPES_MASK_HV1 +** BTM_SCO_PKT_TYPES_MASK_HV2 +** BTM_SCO_PKT_TYPES_MASK_HV3 +** BTM_SCO_PKT_TYPES_MASK_EV3 +** BTM_SCO_PKT_TYPES_MASK_EV4 +** BTM_SCO_PKT_TYPES_MASK_EV5 +** BTM_SCO_PKT_TYPES_MASK_NO_2_EV3 +** BTM_SCO_PKT_TYPES_MASK_NO_3_EV3 +** BTM_SCO_PKT_TYPES_MASK_NO_2_EV5 +** BTM_SCO_PKT_TYPES_MASK_NO_3_EV5 +** +** BTM_SCO_LINK_ALL_MASK - enables all supported types +** +** Returns status of the operation +** +*******************************************************************************/ +tBTM_STATUS BTM_SetScoPacketTypes (UINT16 sco_inx, UINT16 pkt_types) +{ +#if (BTM_MAX_SCO_LINKS>0) + tBTM_CHG_ESCO_PARAMS parms; + tSCO_CONN *p; + + /* Validity check */ + if (sco_inx >= BTM_MAX_SCO_LINKS) + return (BTM_UNKNOWN_ADDR); + + p = &btm_cb.sco_cb.sco_db[sco_inx]; + parms.packet_types = pkt_types; + + /* Keep the other parameters the same for SCO */ + parms.max_latency = p->esco.setup.max_latency; + parms.retrans_effort = p->esco.setup.retrans_effort; + + return (BTM_ChangeEScoLinkParms(sco_inx, &parms)); +#else + return (BTM_UNKNOWN_ADDR); +#endif +} + + +/******************************************************************************* +** +** Function BTM_ReadScoPacketTypes +** +** Description This function is read the packet types used for a specific +** SCO connection. +** +** Returns Packet types supported for the connection +** One or more of the following (bitmask): +** BTM_SCO_PKT_TYPES_MASK_HV1 +** BTM_SCO_PKT_TYPES_MASK_HV2 +** BTM_SCO_PKT_TYPES_MASK_HV3 +** BTM_SCO_PKT_TYPES_MASK_EV3 +** BTM_SCO_PKT_TYPES_MASK_EV4 +** BTM_SCO_PKT_TYPES_MASK_EV5 +** BTM_SCO_PKT_TYPES_MASK_NO_2_EV3 +** BTM_SCO_PKT_TYPES_MASK_NO_3_EV3 +** BTM_SCO_PKT_TYPES_MASK_NO_2_EV5 +** BTM_SCO_PKT_TYPES_MASK_NO_3_EV5 +** +*******************************************************************************/ +UINT16 BTM_ReadScoPacketTypes (UINT16 sco_inx) +{ +#if (BTM_MAX_SCO_LINKS>0) + tSCO_CONN *p = &btm_cb.sco_cb.sco_db[sco_inx]; + + /* Validity check */ + if ((sco_inx < BTM_MAX_SCO_LINKS) && (p->state == SCO_ST_CONNECTED)) + return (p->esco.setup.packet_types); + else + return (0); +#else + return (0); +#endif +} + +/******************************************************************************* +** +** Function BTM_ReadScoDiscReason +** +** Description This function is returns the reason why an (e)SCO connection +** has been removed. It contains the value until read, or until +** another (e)SCO connection has disconnected. +** +** Returns HCI reason or BTM_INVALID_SCO_DISC_REASON if not set. +** +*******************************************************************************/ +UINT16 BTM_ReadScoDiscReason (void) +{ + UINT16 res = btm_cb.sco_cb.sco_disc_reason; + btm_cb.sco_cb.sco_disc_reason = BTM_INVALID_SCO_DISC_REASON; + return (res); +} + +/******************************************************************************* +** +** Function BTM_ReadDeviceScoPacketTypes +** +** Description This function is read the SCO packet types that +** the device supports. +** +** Returns Packet types supported by the device. +** One or more of the following (bitmask): +** BTM_SCO_PKT_TYPES_MASK_HV1 +** BTM_SCO_PKT_TYPES_MASK_HV2 +** BTM_SCO_PKT_TYPES_MASK_HV3 +** BTM_SCO_PKT_TYPES_MASK_EV3 +** BTM_SCO_PKT_TYPES_MASK_EV4 +** BTM_SCO_PKT_TYPES_MASK_EV5 +** BTM_SCO_PKT_TYPES_MASK_NO_2_EV3 +** BTM_SCO_PKT_TYPES_MASK_NO_3_EV3 +** BTM_SCO_PKT_TYPES_MASK_NO_2_EV5 +** BTM_SCO_PKT_TYPES_MASK_NO_3_EV5 +** +*******************************************************************************/ +UINT16 BTM_ReadDeviceScoPacketTypes (void) +{ + return (btm_cb.btm_sco_pkt_types_supported); +} + +/******************************************************************************* +** +** Function BTM_ReadScoHandle +** +** Description This function is used to read the HCI handle used for a specific +** SCO connection, +** +** Returns handle for the connection, or 0xFFFF if invalid SCO index. +** +*******************************************************************************/ +UINT16 BTM_ReadScoHandle (UINT16 sco_inx) +{ +#if (BTM_MAX_SCO_LINKS>0) + tSCO_CONN *p = &btm_cb.sco_cb.sco_db[sco_inx]; + + /* Validity check */ + if ((sco_inx < BTM_MAX_SCO_LINKS) && (p->state == SCO_ST_CONNECTED)) + return (p->hci_handle); + else + return (BTM_INVALID_HCI_HANDLE); +#else + return (BTM_INVALID_HCI_HANDLE); +#endif +} + +/******************************************************************************* +** +** Function BTM_ReadScoBdAddr +** +** Description This function is read the remote BD Address for a specific +** SCO connection, +** +** Returns pointer to BD address or NULL if not known +** +*******************************************************************************/ +UINT8 *BTM_ReadScoBdAddr (UINT16 sco_inx) +{ +#if (BTM_MAX_SCO_LINKS>0) + tSCO_CONN *p = &btm_cb.sco_cb.sco_db[sco_inx]; + + /* Validity check */ + if ((sco_inx < BTM_MAX_SCO_LINKS) && (p->rem_bd_known)) + return (p->esco.data.bd_addr); + else + return (NULL); +#else + return (NULL); +#endif +} + +/******************************************************************************* +** +** Function BTM_SetEScoMode +** +** Description This function sets up the negotiated parameters for SCO or +** eSCO, and sets as the default mode used for outgoing calls to +** BTM_CreateSco. It does not change any currently active (e)SCO links. +** Note: Incoming (e)SCO connections will always use packet types +** supported by the controller. If eSCO is not desired the +** feature should be disabled in the controller's feature mask. +** +** Returns BTM_SUCCESS if the successful. +** BTM_BUSY if there are one or more active (e)SCO links. +** +*******************************************************************************/ +tBTM_STATUS BTM_SetEScoMode (tBTM_SCO_TYPE sco_mode, tBTM_ESCO_PARAMS *p_parms) +{ + tSCO_CB *p_esco = &btm_cb.sco_cb; + tBTM_ESCO_PARAMS *p_def = &p_esco->def_esco_parms; + + if (p_esco->esco_supported) + { + if (p_parms) + { + if (sco_mode == BTM_LINK_TYPE_ESCO) + *p_def = *p_parms; /* Save as the default parameters */ + else /* Load only the SCO packet types */ + { + p_def->packet_types = p_parms->packet_types; + p_def->tx_bw = BTM_64KBITS_RATE; + p_def->rx_bw = BTM_64KBITS_RATE; + p_def->max_latency = 0x000a; + p_def->voice_contfmt = 0x0060; + p_def->retrans_effort = 0; + + /* OR in any exception packet types */ + p_def->packet_types |= BTM_SCO_EXCEPTION_PKTS_MASK; + } + } + p_esco->desired_sco_mode = sco_mode; + BTM_TRACE_API("BTM_SetEScoMode -> mode %d", sco_mode); + } + else + { + p_esco->desired_sco_mode = BTM_LINK_TYPE_SCO; + p_def->packet_types &= BTM_SCO_LINK_ONLY_MASK; + p_def->retrans_effort = 0; + BTM_TRACE_API("BTM_SetEScoMode -> mode SCO (eSCO not supported)"); + } + + BTM_TRACE_DEBUG(" txbw 0x%08x, rxbw 0x%08x, max_lat 0x%04x, voice 0x%04x, pkt 0x%04x, rtx effort 0x%02x", + p_def->tx_bw, p_def->rx_bw, p_def->max_latency, + p_def->voice_contfmt, p_def->packet_types, + p_def->retrans_effort); + + return (BTM_SUCCESS); +} + + + +/******************************************************************************* +** +** Function BTM_RegForEScoEvts +** +** Description This function registers a SCO event callback with the +** specified instance. It should be used to received +** connection indication events and change of link parameter +** events. +** +** Returns BTM_SUCCESS if the successful. +** BTM_ILLEGAL_VALUE if there is an illegal sco_inx +** BTM_MODE_UNSUPPORTED if controller version is not BT1.2 or +** later or does not support eSCO. +** +*******************************************************************************/ +tBTM_STATUS BTM_RegForEScoEvts (UINT16 sco_inx, tBTM_ESCO_CBACK *p_esco_cback) +{ +#if (BTM_MAX_SCO_LINKS>0) + if (!btm_cb.sco_cb.esco_supported) + { + btm_cb.sco_cb.sco_db[sco_inx].esco.p_esco_cback = NULL; + return (BTM_MODE_UNSUPPORTED); + } + + if (sco_inx < BTM_MAX_SCO_LINKS && + btm_cb.sco_cb.sco_db[sco_inx].state != SCO_ST_UNUSED) + { + btm_cb.sco_cb.sco_db[sco_inx].esco.p_esco_cback = p_esco_cback; + return (BTM_SUCCESS); + } + return (BTM_ILLEGAL_VALUE); +#else + return (BTM_MODE_UNSUPPORTED); +#endif +} + +/******************************************************************************* +** +** Function BTM_ReadEScoLinkParms +** +** Description This function returns the current eSCO link parameters for +** the specified handle. This can be called anytime a connection +** is active, but is typically called after receiving the SCO +** opened callback. +** +** Note: If called over a 1.1 controller, only the packet types +** field has meaning. +** +** Returns BTM_SUCCESS if returned data is valid connection. +** BTM_WRONG_MODE if no connection with a peer device or bad sco_inx. +** +*******************************************************************************/ +tBTM_STATUS BTM_ReadEScoLinkParms (UINT16 sco_inx, tBTM_ESCO_DATA *p_parms) +{ +#if (BTM_MAX_SCO_LINKS>0) + UINT8 index; + + BTM_TRACE_API("BTM_ReadEScoLinkParms -> sco_inx 0x%04x", sco_inx); + + if (sco_inx < BTM_MAX_SCO_LINKS && + btm_cb.sco_cb.sco_db[sco_inx].state >= SCO_ST_CONNECTED) + { + *p_parms = btm_cb.sco_cb.sco_db[sco_inx].esco.data; + return (BTM_SUCCESS); + } + + if (sco_inx == BTM_FIRST_ACTIVE_SCO_INDEX) + { + for (index = 0; index < BTM_MAX_SCO_LINKS; index++) + { + if (btm_cb.sco_cb.sco_db[index].state >= SCO_ST_CONNECTED) + { + BTM_TRACE_API("BTM_ReadEScoLinkParms the first active SCO index is %d",index); + *p_parms = btm_cb.sco_cb.sco_db[index].esco.data; + return (BTM_SUCCESS); + } + } + } + +#endif + + BTM_TRACE_API("BTM_ReadEScoLinkParms cannot find the SCO index!"); + memset(p_parms, 0, sizeof(tBTM_ESCO_DATA)); + return (BTM_WRONG_MODE); +} + +/******************************************************************************* +** +** Function BTM_ChangeEScoLinkParms +** +** Description This function requests renegotiation of the parameters on +** the current eSCO Link. If any of the changes are accepted +** by the controllers, the BTM_ESCO_CHG_EVT event is sent in +** the tBTM_ESCO_CBACK function with the current settings of +** the link. The callback is registered through the call to +** BTM_SetEScoMode. +** +** Note: If called over a SCO link (including 1.1 controller), +** a change packet type request is sent out instead. +** +** Returns BTM_CMD_STARTED if command is successfully initiated. +** BTM_NO_RESOURCES - not enough resources to initiate command. +** BTM_WRONG_MODE if no connection with a peer device or bad sco_inx. +** +*******************************************************************************/ +tBTM_STATUS BTM_ChangeEScoLinkParms (UINT16 sco_inx, tBTM_CHG_ESCO_PARAMS *p_parms) +{ +#if (BTM_MAX_SCO_LINKS>0) + tBTM_ESCO_PARAMS *p_setup; + tSCO_CONN *p_sco; + UINT16 temp_pkt_types; + + /* Make sure sco handle is valid and on an active link */ + if (sco_inx >= BTM_MAX_SCO_LINKS || + btm_cb.sco_cb.sco_db[sco_inx].state != SCO_ST_CONNECTED) + return (BTM_WRONG_MODE); + + p_sco = &btm_cb.sco_cb.sco_db[sco_inx]; + p_setup = &p_sco->esco.setup; + + /* If SCO connection OR eSCO not supported just send change packet types */ + if (p_sco->esco.data.link_type == BTM_LINK_TYPE_SCO || + !btm_cb.sco_cb.esco_supported) + { + p_setup->packet_types = p_parms->packet_types & + (btm_cb.btm_sco_pkt_types_supported & BTM_SCO_LINK_ONLY_MASK); + + + BTM_TRACE_API("BTM_ChangeEScoLinkParms -> SCO Link for handle 0x%04x, pkt 0x%04x", + p_sco->hci_handle, p_setup->packet_types); + + if (!btsnd_hcic_change_conn_type (p_sco->hci_handle, + BTM_ESCO_2_SCO(p_setup->packet_types))) + return (BTM_NO_RESOURCES); + } + else + { + temp_pkt_types = (p_parms->packet_types & BTM_SCO_SUPPORTED_PKTS_MASK & + btm_cb.btm_sco_pkt_types_supported); + + /* OR in any exception packet types */ + temp_pkt_types |= ((p_parms->packet_types & BTM_SCO_EXCEPTION_PKTS_MASK) | + (btm_cb.btm_sco_pkt_types_supported & BTM_SCO_EXCEPTION_PKTS_MASK)); + + BTM_TRACE_API("BTM_ChangeEScoLinkParms -> eSCO Link for handle 0x%04x", p_sco->hci_handle); + BTM_TRACE_API(" txbw 0x%x, rxbw 0x%x, lat 0x%x, voice 0x%x, retrans 0x%02x, pkt 0x%04x", + p_setup->tx_bw, p_setup->rx_bw, p_parms->max_latency, + p_setup->voice_contfmt, p_parms->retrans_effort, temp_pkt_types); + + /* When changing an existing link, only change latency, retrans, and pkts */ + if (!btsnd_hcic_setup_esco_conn(p_sco->hci_handle, p_setup->tx_bw, + p_setup->rx_bw, p_parms->max_latency, + p_setup->voice_contfmt, + p_parms->retrans_effort, + temp_pkt_types)) + return (BTM_NO_RESOURCES); + else + p_parms->packet_types = temp_pkt_types; + } + + return (BTM_CMD_STARTED); +#else + return (BTM_WRONG_MODE); +#endif +} + +/******************************************************************************* +** +** Function BTM_EScoConnRsp +** +** Description This function is called upon receipt of an (e)SCO connection +** request event (BTM_ESCO_CONN_REQ_EVT) to accept or reject +** the request. Parameters used to negotiate eSCO links. +** If p_parms is NULL, then values set through BTM_SetEScoMode +** are used. +** If the link type of the incoming request is SCO, then only +** the tx_bw, max_latency, content format, and packet_types are +** valid. The hci_status parameter should be +** ([0x0] to accept, [0x0d..0x0f] to reject) +** +** +** Returns void +** +*******************************************************************************/ +void BTM_EScoConnRsp (UINT16 sco_inx, UINT8 hci_status, tBTM_ESCO_PARAMS *p_parms) +{ +#if (BTM_MAX_SCO_LINKS>0) + if (sco_inx < BTM_MAX_SCO_LINKS && + btm_cb.sco_cb.sco_db[sco_inx].state == SCO_ST_W4_CONN_RSP) + { + btm_esco_conn_rsp(sco_inx, hci_status, + btm_cb.sco_cb.sco_db[sco_inx].esco.data.bd_addr, + p_parms); + } +#endif +} + +/******************************************************************************* +** +** Function btm_read_def_esco_mode +** +** Description This function copies the current default esco settings into +** the return buffer. +** +** Returns tBTM_SCO_TYPE +** +*******************************************************************************/ +tBTM_SCO_TYPE btm_read_def_esco_mode (tBTM_ESCO_PARAMS *p_parms) +{ +#if (BTM_MAX_SCO_LINKS>0) + *p_parms = btm_cb.sco_cb.def_esco_parms; + return btm_cb.sco_cb.desired_sco_mode; +#else + return BTM_LINK_TYPE_SCO; +#endif +} + +/******************************************************************************* +** +** Function btm_esco_proc_conn_chg +** +** Description This function is called by BTIF when an SCO connection +** is changed. +** +** Returns void +** +*******************************************************************************/ +void btm_esco_proc_conn_chg (UINT8 status, UINT16 handle, UINT8 tx_interval, + UINT8 retrans_window, UINT16 rx_pkt_len, + UINT16 tx_pkt_len) +{ +#if (BTM_MAX_SCO_LINKS>0) + tSCO_CONN *p = &btm_cb.sco_cb.sco_db[0]; + tBTM_CHG_ESCO_EVT_DATA data; + UINT16 xx; + + BTM_TRACE_EVENT("btm_esco_proc_conn_chg -> handle 0x%04x, status 0x%02x", + handle, status); + + for (xx = 0; xx < BTM_MAX_SCO_LINKS; xx++, p++) + { + if (p->state == SCO_ST_CONNECTED && handle == p->hci_handle) + { + /* If upper layer wants notification */ + if (p->esco.p_esco_cback) + { + memcpy(data.bd_addr, p->esco.data.bd_addr, BD_ADDR_LEN); + data.hci_status = status; + data.sco_inx = xx; + data.rx_pkt_len = p->esco.data.rx_pkt_len = rx_pkt_len; + data.tx_pkt_len = p->esco.data.tx_pkt_len = tx_pkt_len; + data.tx_interval = p->esco.data.tx_interval = tx_interval; + data.retrans_window = p->esco.data.retrans_window = retrans_window; + + (*p->esco.p_esco_cback)(BTM_ESCO_CHG_EVT, + (tBTM_ESCO_EVT_DATA *)&data); + } + return; + } + } +#endif +} + +/******************************************************************************* +** +** Function btm_is_sco_active +** +** Description This function is called to see if a SCO handle is already in +** use. +** +** Returns BOOLEAN +** +*******************************************************************************/ +BOOLEAN btm_is_sco_active (UINT16 handle) +{ +#if (BTM_MAX_SCO_LINKS>0) + UINT16 xx; + tSCO_CONN *p = &btm_cb.sco_cb.sco_db[0]; + + for (xx = 0; xx < BTM_MAX_SCO_LINKS; xx++, p++) + { + if (handle == p->hci_handle && p->state == SCO_ST_CONNECTED) + return (TRUE); + } +#endif + return (FALSE); +} + +/******************************************************************************* +** +** Function BTM_GetNumScoLinks +** +** Description This function returns the number of active sco links. +** +** Returns UINT8 +** +*******************************************************************************/ +UINT8 BTM_GetNumScoLinks (void) +{ +#if (BTM_MAX_SCO_LINKS>0) + tSCO_CONN *p = &btm_cb.sco_cb.sco_db[0]; + UINT16 xx; + UINT8 num_scos = 0; + + for (xx = 0; xx < BTM_MAX_SCO_LINKS; xx++, p++) + { + switch (p->state) + { + case SCO_ST_W4_CONN_RSP: + case SCO_ST_CONNECTING: + case SCO_ST_CONNECTED: + case SCO_ST_DISCONNECTING: + case SCO_ST_PEND_UNPARK: + num_scos++; + } + } + return (num_scos); +#else + return (0); +#endif +} + + +/******************************************************************************* +** +** Function btm_is_sco_active_by_bdaddr +** +** Description This function is called to see if a SCO active to a bd address. +** +** Returns BOOLEAN +** +*******************************************************************************/ +BOOLEAN btm_is_sco_active_by_bdaddr (BD_ADDR remote_bda) +{ +#if (BTM_MAX_SCO_LINKS>0) + UINT8 xx; + tSCO_CONN *p = &btm_cb.sco_cb.sco_db[0]; + + /* If any SCO is being established to the remote BD address, refuse this */ + for (xx = 0; xx < BTM_MAX_SCO_LINKS; xx++, p++) + { + if ((!memcmp (p->esco.data.bd_addr, remote_bda, BD_ADDR_LEN)) && (p->state == SCO_ST_CONNECTED)) + { + return (TRUE); + } + } +#endif + return (FALSE); +} +#else /* SCO_EXCLUDED == TRUE (Link in stubs) */ + +tBTM_STATUS BTM_CreateSco (BD_ADDR remote_bda, BOOLEAN is_orig, + UINT16 pkt_types, UINT16 *p_sco_inx, + tBTM_SCO_CB *p_conn_cb, + tBTM_SCO_CB *p_disc_cb) {return (BTM_NO_RESOURCES);} +tBTM_STATUS BTM_RemoveSco (UINT16 sco_inx) {return (BTM_NO_RESOURCES);} +tBTM_STATUS BTM_SetScoPacketTypes (UINT16 sco_inx, UINT16 pkt_types) {return (BTM_NO_RESOURCES);} +UINT16 BTM_ReadScoPacketTypes (UINT16 sco_inx) {return (0);} +UINT16 BTM_ReadDeviceScoPacketTypes (void) {return (0);} +UINT16 BTM_ReadScoHandle (UINT16 sco_inx) {return (BTM_INVALID_HCI_HANDLE);} +UINT8 *BTM_ReadScoBdAddr(UINT16 sco_inx) {return((UINT8 *) NULL);} +UINT16 BTM_ReadScoDiscReason (void) {return (BTM_INVALID_SCO_DISC_REASON);} +tBTM_STATUS BTM_SetEScoMode (tBTM_SCO_TYPE sco_mode, tBTM_ESCO_PARAMS *p_parms) {return (BTM_MODE_UNSUPPORTED);} +tBTM_STATUS BTM_RegForEScoEvts (UINT16 sco_inx, tBTM_ESCO_CBACK *p_esco_cback) { return (BTM_ILLEGAL_VALUE);} +tBTM_STATUS BTM_ReadEScoLinkParms (UINT16 sco_inx, tBTM_ESCO_DATA *p_parms) { return (BTM_MODE_UNSUPPORTED);} +tBTM_STATUS BTM_ChangeEScoLinkParms (UINT16 sco_inx, tBTM_CHG_ESCO_PARAMS *p_parms) { return (BTM_MODE_UNSUPPORTED);} +void BTM_EScoConnRsp (UINT16 sco_inx, UINT8 hci_status, tBTM_ESCO_PARAMS *p_parms) {} +UINT8 BTM_GetNumScoLinks (void) {return (0);} + +#endif /* If SCO is being used */ diff --git a/components/bt/bluedroid/stack/btm/btm_sec.c b/components/bt/bluedroid/stack/btm/btm_sec.c new file mode 100755 index 0000000000..4ba8f2847b --- /dev/null +++ b/components/bt/bluedroid/stack/btm/btm_sec.c @@ -0,0 +1,6499 @@ +/****************************************************************************** + * + * Copyright (C) 1999-2012 Broadcom Corporation + * + * 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 functions for the Bluetooth Security Manager + * + ******************************************************************************/ + +//#define LOG_TAG "bt_btm_sec" + +#include +#include + +#include "bt_types.h" +#include "controller.h" +#include "hcimsgs.h" +#include "btu.h" +#include "btm_int.h" +#include "l2c_int.h" +//#include "bt_utils.h" +//#include "osi/include/log.h" + +#if (BT_USE_TRACES == TRUE && BT_TRACE_VERBOSE == FALSE) +/* needed for sprintf() */ +#include +#endif + +#if BLE_INCLUDED == TRUE + #include "gatt_int.h" +#endif + +#define BTM_SEC_MAX_COLLISION_DELAY (5000) + +#ifdef APPL_AUTH_WRITE_EXCEPTION +BOOLEAN (APPL_AUTH_WRITE_EXCEPTION)(BD_ADDR bd_addr); +#endif + + +/******************************************************************************** +** L O C A L F U N C T I O N P R O T O T Y P E S * +*********************************************************************************/ +static tBTM_SEC_SERV_REC *btm_sec_find_first_serv (BOOLEAN is_originator, UINT16 psm); +static tBTM_SEC_SERV_REC *btm_sec_find_next_serv (tBTM_SEC_SERV_REC *p_cur); +static tBTM_SEC_SERV_REC *btm_sec_find_mx_serv (UINT8 is_originator, UINT16 psm, + UINT32 mx_proto_id, + UINT32 mx_chan_id); + +static tBTM_STATUS btm_sec_execute_procedure (tBTM_SEC_DEV_REC *p_dev_rec); +static BOOLEAN btm_sec_start_get_name (tBTM_SEC_DEV_REC *p_dev_rec); +static BOOLEAN btm_sec_start_authentication (tBTM_SEC_DEV_REC *p_dev_rec); +static BOOLEAN btm_sec_start_encryption (tBTM_SEC_DEV_REC *p_dev_rec); +static void btm_sec_collision_timeout (TIMER_LIST_ENT *p_tle); +static void btm_restore_mode(void); +static void btm_sec_pairing_timeout (TIMER_LIST_ENT *p_tle); +static tBTM_STATUS btm_sec_dd_create_conn (tBTM_SEC_DEV_REC *p_dev_rec); +static void btm_sec_change_pairing_state (tBTM_PAIRING_STATE new_state); + +#if (BT_USE_TRACES == TRUE) +static char *btm_pair_state_descr (tBTM_PAIRING_STATE state); +#endif + +static void btm_sec_check_pending_reqs(void); +static BOOLEAN btm_sec_queue_mx_request (BD_ADDR bd_addr, UINT16 psm, BOOLEAN is_orig, + UINT32 mx_proto_id, UINT32 mx_chan_id, + tBTM_SEC_CALLBACK *p_callback, void *p_ref_data); +static void btm_sec_bond_cancel_complete (void); +static void btm_send_link_key_notif (tBTM_SEC_DEV_REC *p_dev_rec); +static BOOLEAN btm_sec_check_prefetch_pin (tBTM_SEC_DEV_REC *p_dev_rec); + +static UINT8 btm_sec_start_authorization (tBTM_SEC_DEV_REC *p_dev_rec); +BOOLEAN btm_sec_are_all_trusted(UINT32 p_mask[]); + +static tBTM_STATUS btm_sec_send_hci_disconnect (tBTM_SEC_DEV_REC *p_dev_rec, UINT8 reason, UINT16 conn_handle); +UINT8 btm_sec_start_role_switch (tBTM_SEC_DEV_REC *p_dev_rec); +tBTM_SEC_DEV_REC *btm_sec_find_dev_by_sec_state (UINT8 state); + +static BOOLEAN btm_sec_set_security_level ( CONNECTION_TYPE conn_type, char *p_name, UINT8 service_id, + UINT16 sec_level, UINT16 psm, UINT32 mx_proto_id, + UINT32 mx_chan_id); + +static BOOLEAN btm_dev_authenticated(tBTM_SEC_DEV_REC *p_dev_rec); +static BOOLEAN btm_dev_encrypted(tBTM_SEC_DEV_REC *p_dev_rec); +static BOOLEAN btm_dev_authorized(tBTM_SEC_DEV_REC *p_dev_rec); +static BOOLEAN btm_serv_trusted(tBTM_SEC_DEV_REC *p_dev_rec, tBTM_SEC_SERV_REC *p_serv_rec); +static BOOLEAN btm_sec_is_serv_level0 (UINT16 psm); +static UINT16 btm_sec_set_serv_level4_flags (UINT16 cur_security, BOOLEAN is_originator); + +static BOOLEAN btm_sec_queue_encrypt_request (BD_ADDR bd_addr, tBT_TRANSPORT transport, + tBTM_SEC_CALLBACK *p_callback, void *p_ref_data); +static void btm_sec_clean_pending_req_queue (BD_ADDR remote_bda, tBT_TRANSPORT transport) ; +static void btm_sec_check_pending_enc_req (tBTM_SEC_DEV_REC *p_dev_rec, tBT_TRANSPORT transport, + UINT8 encr_enable); +static BOOLEAN btm_sec_acceptor_rejects_bonding (tBTM_SEC_DEV_REC *p_dev_rec); + +static BOOLEAN btm_sec_use_smp_br_chnl(tBTM_SEC_DEV_REC *p_dev_rec); +static BOOLEAN btm_sec_is_master(tBTM_SEC_DEV_REC *p_dev_rec); + +/* TRUE - authenticated link key is possible */ +static const BOOLEAN btm_sec_io_map [BTM_IO_CAP_MAX][BTM_IO_CAP_MAX] = +{ + /* OUT, IO, IN, NONE */ +/* OUT */ {FALSE, FALSE, TRUE, FALSE}, +/* IO */ {FALSE, TRUE, TRUE, FALSE}, +/* IN */ {TRUE, TRUE, TRUE, FALSE}, +/* NONE */ {FALSE, FALSE, FALSE, FALSE} +}; +/* BTM_IO_CAP_OUT 0 DisplayOnly */ +/* BTM_IO_CAP_IO 1 DisplayYesNo */ +/* BTM_IO_CAP_IN 2 KeyboardOnly */ +/* BTM_IO_CAP_NONE 3 NoInputNoOutput */ + +/******************************************************************************* +** +** Function btm_dev_authenticated +** +** Description check device is authenticated +** +** Returns BOOLEAN TRUE or FALSE +** +*******************************************************************************/ +static BOOLEAN btm_dev_authenticated (tBTM_SEC_DEV_REC *p_dev_rec) +{ + if(p_dev_rec->sec_flags & BTM_SEC_AUTHENTICATED) + { + return(TRUE); + } + return(FALSE); +} + +/******************************************************************************* +** +** Function btm_dev_encrypted +** +** Description check device is encrypted +** +** Returns BOOLEAN TRUE or FALSE +** +*******************************************************************************/ +static BOOLEAN btm_dev_encrypted (tBTM_SEC_DEV_REC *p_dev_rec) +{ + if(p_dev_rec->sec_flags & BTM_SEC_ENCRYPTED) + { + return(TRUE); + } + return(FALSE); +} + +/******************************************************************************* +** +** Function btm_dev_authorized +** +** Description check device is authorized +** +** Returns BOOLEAN TRUE or FALSE +** +*******************************************************************************/ +static BOOLEAN btm_dev_authorized (tBTM_SEC_DEV_REC *p_dev_rec) +{ + if(p_dev_rec->sec_flags & BTM_SEC_AUTHORIZED) + { + return(TRUE); + } + return(FALSE); +} + +/******************************************************************************* +** +** Function btm_dev_16_digit_authenticated +** +** Description check device is authenticated by using 16 digit pin or MITM +** +** Returns BOOLEAN TRUE or FALSE +** +*******************************************************************************/ +static BOOLEAN btm_dev_16_digit_authenticated(tBTM_SEC_DEV_REC *p_dev_rec) +{ + // BTM_SEC_16_DIGIT_PIN_AUTHED is set if MITM or 16 digit pin is used + if(p_dev_rec->sec_flags & BTM_SEC_16_DIGIT_PIN_AUTHED) + { + return(TRUE); + } + return(FALSE); +} + +/******************************************************************************* +** +** Function btm_serv_trusted +** +** Description check service is trusted +** +** Returns BOOLEAN TRUE or FALSE +** +*******************************************************************************/ +static BOOLEAN btm_serv_trusted(tBTM_SEC_DEV_REC *p_dev_rec, tBTM_SEC_SERV_REC *p_serv_rec) +{ + if(BTM_SEC_IS_SERVICE_TRUSTED(p_dev_rec->trusted_mask, p_serv_rec->service_id)) + { + return(TRUE); + } + return(FALSE); +} + +/******************************************************************************* +** +** Function BTM_SecRegister +** +** Description Application manager calls this function to register for +** security services. There can be one and only one application +** saving link keys. BTM allows only first registration. +** +** Returns TRUE if registered OK, else FALSE +** +*******************************************************************************/ +BOOLEAN BTM_SecRegister(tBTM_APPL_INFO *p_cb_info) +{ +#if BLE_INCLUDED == TRUE + BT_OCTET16 temp_value = {0}; +#endif + + BTM_TRACE_EVENT("%s application registered", __func__); + +#if BLE_INCLUDED == TRUE && SMP_INCLUDED == TRUE + LOG_INFO("%s p_cb_info->p_le_callback == 0x%p", __func__, p_cb_info->p_le_callback); + if (p_cb_info->p_le_callback) + { +#if SMP_INCLUDED == TRUE + BTM_TRACE_EVENT("%s SMP_Register( btm_proc_smp_cback )", __func__); + SMP_Register(btm_proc_smp_cback); +#endif + /* if no IR is loaded, need to regenerate all the keys */ + if (memcmp(btm_cb.devcb.id_keys.ir, &temp_value, sizeof(BT_OCTET16)) == 0) + { + btm_ble_reset_id(); + } + } + else + { + LOG_WARN("%s p_cb_info->p_le_callback == NULL", __func__); + } +#endif + + btm_cb.api = *p_cb_info; +#if BLE_INCLUDED == TRUE && SMP_INCLUDED == TRUE + LOG_INFO("%s btm_cb.api.p_le_callback = 0x%p ", __func__, btm_cb.api.p_le_callback); +#endif + BTM_TRACE_EVENT("%s application registered", __func__); + return(TRUE); +} + +/******************************************************************************* +** +** Function BTM_SecRegisterLinkKeyNotificationCallback +** +** Description Application manager calls this function to register for +** link key notification. When there is nobody registered +** we should avoid changing link key +** +** Returns TRUE if registered OK, else FALSE +** +*******************************************************************************/ +BOOLEAN BTM_SecRegisterLinkKeyNotificationCallback (tBTM_LINK_KEY_CALLBACK *p_callback) +{ + btm_cb.api.p_link_key_callback = p_callback; + return TRUE; +} + +/******************************************************************************* +** +** Function BTM_SecAddRmtNameNotifyCallback +** +** Description Any profile can register to be notified when name of the +** remote device is resolved. +** +** Returns TRUE if registered OK, else FALSE +** +*******************************************************************************/ +BOOLEAN BTM_SecAddRmtNameNotifyCallback (tBTM_RMT_NAME_CALLBACK *p_callback) +{ + int i; + + for (i = 0; i < BTM_SEC_MAX_RMT_NAME_CALLBACKS; i++) + { + if (btm_cb.p_rmt_name_callback[i] == NULL) + { + btm_cb.p_rmt_name_callback[i] = p_callback; + return(TRUE); + } + } + + return(FALSE); +} + + +/******************************************************************************* +** +** Function BTM_SecDeleteRmtNameNotifyCallback +** +** Description Any profile can deregister notification when a new Link Key +** is generated per connection. +** +** Returns TRUE if OK, else FALSE +** +*******************************************************************************/ +BOOLEAN BTM_SecDeleteRmtNameNotifyCallback (tBTM_RMT_NAME_CALLBACK *p_callback) +{ + int i; + + for (i = 0; i < BTM_SEC_MAX_RMT_NAME_CALLBACKS; i++) + { + if (btm_cb.p_rmt_name_callback[i] == p_callback) + { + btm_cb.p_rmt_name_callback[i] = NULL; + return(TRUE); + } + } + + return(FALSE); +} + +/******************************************************************************* +** +** Function BTM_GetSecurityFlags +** +** Description Get security flags for the device +** +** Returns BOOLEAN TRUE or FALSE is device found +** +*******************************************************************************/ +BOOLEAN BTM_GetSecurityFlags (BD_ADDR bd_addr, UINT8 * p_sec_flags) +{ + tBTM_SEC_DEV_REC *p_dev_rec; + + if ((p_dev_rec = btm_find_dev (bd_addr)) != NULL) + { + *p_sec_flags = (UINT8) p_dev_rec->sec_flags; + return(TRUE); + } + BTM_TRACE_ERROR ("BTM_GetSecurityFlags false"); + return(FALSE); +} + +/******************************************************************************* +** +** Function BTM_GetSecurityFlagsByTransport +** +** Description Get security flags for the device on a particular transport +** +** Returns BOOLEAN TRUE or FALSE is device found +** +*******************************************************************************/ +BOOLEAN BTM_GetSecurityFlagsByTransport (BD_ADDR bd_addr, UINT8 * p_sec_flags, + tBT_TRANSPORT transport) +{ + tBTM_SEC_DEV_REC *p_dev_rec; + + if ((p_dev_rec = btm_find_dev (bd_addr)) != NULL) + { + if (transport == BT_TRANSPORT_BR_EDR) + *p_sec_flags = (UINT8) p_dev_rec->sec_flags; + else + *p_sec_flags = (UINT8) (p_dev_rec->sec_flags >> 8); + + return(TRUE); + } + BTM_TRACE_ERROR ("BTM_GetSecurityFlags false"); + return(FALSE); +} + +/******************************************************************************* +** +** Function BTM_SetPinType +** +** Description Set PIN type for the device. +** +** Returns void +** +*******************************************************************************/ +void BTM_SetPinType (UINT8 pin_type, PIN_CODE pin_code, UINT8 pin_code_len) +{ + BTM_TRACE_API ("BTM_SetPinType: pin type %d [variable-0, fixed-1], code %s, length %d", + pin_type, (char *) pin_code, pin_code_len); + + /* If device is not up security mode will be set as a part of startup */ + if ( (btm_cb.cfg.pin_type != pin_type) + && controller_get_interface()->get_is_ready() ) + { + btsnd_hcic_write_pin_type (pin_type); + } + + btm_cb.cfg.pin_type = pin_type; + btm_cb.cfg.pin_code_len = pin_code_len; + memcpy (btm_cb.cfg.pin_code, pin_code, pin_code_len); +} + +/******************************************************************************* +** +** Function BTM_SetPairableMode +** +** Description Enable or disable pairing +** +** Parameters allow_pairing - (TRUE or FALSE) whether or not the device +** allows pairing. +** connect_only_paired - (TRUE or FALSE) whether or not to +** only allow paired devices to connect. +** +** Returns void +** +*******************************************************************************/ +void BTM_SetPairableMode (BOOLEAN allow_pairing, BOOLEAN connect_only_paired) +{ + BTM_TRACE_API ("BTM_SetPairableMode() allow_pairing: %u connect_only_paired: %u", allow_pairing, connect_only_paired); + + btm_cb.pairing_disabled = !allow_pairing; + btm_cb.connect_only_paired = connect_only_paired; +} + +/******************************************************************************* +** +** Function BTM_SetSecureConnectionsOnly +** +** Description Enable or disable default treatment for Mode 4 Level 0 services +** +** Parameter secure_connections_only_mode - (TRUE or FALSE) whether or not the device +** TRUE means that the device should treat Mode 4 Level 0 services as +** services of other levels. (Secure_connections_only_mode) +** FALSE means that the device should provide default treatment for +** Mode 4 Level 0 services. +** +** Returns void +** +*******************************************************************************/ +void BTM_SetSecureConnectionsOnly (BOOLEAN secure_connections_only_mode) +{ + BTM_TRACE_API("%s: Mode : %u", __FUNCTION__, + secure_connections_only_mode); + + btm_cb.devcb.secure_connections_only = secure_connections_only_mode; + btm_cb.security_mode = BTM_SEC_MODE_SC; +} +#define BTM_NO_AVAIL_SEC_SERVICES ((UINT16) 0xffff) + +/******************************************************************************* +** +** Function BTM_SetSecurityLevel +** +** Description Register service security level with Security Manager +** +** Parameters: is_originator - TRUE if originating the connection, FALSE if not +** p_name - Name of the service relevant only if +** authorization will show this name to user. ignored +** if BTM_SEC_SERVICE_NAME_LEN is 0. +** service_id - service ID for the service passed to authorization callback +** sec_level - bit mask of the security features +** psm - L2CAP PSM +** mx_proto_id - protocol ID of multiplexing proto below +** mx_chan_id - channel ID of multiplexing proto below +** +** Returns TRUE if registered OK, else FALSE +** +*******************************************************************************/ +BOOLEAN BTM_SetSecurityLevel (BOOLEAN is_originator, char *p_name, UINT8 service_id, + UINT16 sec_level, UINT16 psm, UINT32 mx_proto_id, + UINT32 mx_chan_id) +{ +#if (L2CAP_UCD_INCLUDED == TRUE) + CONNECTION_TYPE conn_type; + + if (is_originator) + conn_type = CONN_ORIENT_ORIG; + else + conn_type = CONN_ORIENT_TERM; + + return(btm_sec_set_security_level (conn_type, p_name, service_id, + sec_level, psm, mx_proto_id, mx_chan_id)); +#else + return(btm_sec_set_security_level (is_originator, p_name, service_id, + sec_level, psm, mx_proto_id, mx_chan_id)); +#endif +} + +/******************************************************************************* +** +** Function btm_sec_set_security_level +** +** Description Register service security level with Security Manager +** +** Parameters: conn_type - TRUE if originating the connection, FALSE if not +** p_name - Name of the service relevant only if +** authorization will show this name to user. ignored +** if BTM_SEC_SERVICE_NAME_LEN is 0. +** service_id - service ID for the service passed to authorization callback +** sec_level - bit mask of the security features +** psm - L2CAP PSM +** mx_proto_id - protocol ID of multiplexing proto below +** mx_chan_id - channel ID of multiplexing proto below +** +** Returns TRUE if registered OK, else FALSE +** +*******************************************************************************/ +static BOOLEAN btm_sec_set_security_level (CONNECTION_TYPE conn_type, char *p_name, UINT8 service_id, + UINT16 sec_level, UINT16 psm, UINT32 mx_proto_id, + UINT32 mx_chan_id) +{ + tBTM_SEC_SERV_REC *p_srec; + UINT16 index; + UINT16 first_unused_record = BTM_NO_AVAIL_SEC_SERVICES; + BOOLEAN record_allocated = FALSE; + BOOLEAN is_originator; +#if (L2CAP_UCD_INCLUDED == TRUE) + BOOLEAN is_ucd; + + if (conn_type & CONNECTION_TYPE_ORIG_MASK) + is_originator = TRUE; + else + is_originator = FALSE; + + if (conn_type & CONNECTION_TYPE_CONNLESS_MASK ) + { + is_ucd = TRUE; + } + else + { + is_ucd = FALSE; + } +#else + is_originator = conn_type; +#endif + + BTM_TRACE_API("%s : sec: 0x%x", __func__, sec_level); + + /* See if the record can be reused (same service name, psm, mx_proto_id, + service_id, and mx_chan_id), or obtain the next unused record */ + + p_srec = &btm_cb.sec_serv_rec[0]; + + + for (index = 0; index < BTM_SEC_MAX_SERVICE_RECORDS; index++, p_srec++) + { + /* Check if there is already a record for this service */ + if (p_srec->security_flags & BTM_SEC_IN_USE) + { +#if BTM_SEC_SERVICE_NAME_LEN > 0 + if (p_srec->psm == psm && + p_srec->mx_proto_id == mx_proto_id && + service_id == p_srec->service_id && + (!strncmp (p_name, (char *) p_srec->orig_service_name, + BTM_SEC_SERVICE_NAME_LEN) || + !strncmp (p_name, (char *) p_srec->term_service_name, + BTM_SEC_SERVICE_NAME_LEN))) +#else + if (p_srec->psm == psm && + p_srec->mx_proto_id == mx_proto_id && + service_id == p_srec->service_id) +#endif + { + record_allocated = TRUE; + break; + } + } + /* Mark the first available service record */ + else if (!record_allocated) + { + memset (p_srec, 0, sizeof(tBTM_SEC_SERV_REC)); + record_allocated = TRUE; + first_unused_record = index; + } + } + + if (!record_allocated) + { + BTM_TRACE_WARNING("BTM_SEC_REG: Out of Service Records (%d)", BTM_SEC_MAX_SERVICE_RECORDS); + return(record_allocated); + } + + /* Process the request if service record is valid */ + /* If a duplicate service wasn't found, use the first available */ + if (index >= BTM_SEC_MAX_SERVICE_RECORDS) + { + index = first_unused_record; + p_srec = &btm_cb.sec_serv_rec[index]; + } + + p_srec->psm = psm; + p_srec->service_id = service_id; + p_srec->mx_proto_id = mx_proto_id; + + if (is_originator) + { + p_srec->orig_mx_chan_id = mx_chan_id; +#if BTM_SEC_SERVICE_NAME_LEN > 0 + BCM_STRNCPY_S ((char *)p_srec->orig_service_name, sizeof(p_srec->orig_service_name), p_name, BTM_SEC_SERVICE_NAME_LEN); +#endif + /* clear out the old setting, just in case it exists */ +#if (L2CAP_UCD_INCLUDED == TRUE) + if ( is_ucd ) + { + p_srec->ucd_security_flags &= + ~(BTM_SEC_OUT_AUTHORIZE | BTM_SEC_OUT_ENCRYPT | BTM_SEC_OUT_AUTHENTICATE | BTM_SEC_OUT_MITM | + BTM_SEC_FORCE_MASTER | BTM_SEC_ATTEMPT_MASTER | BTM_SEC_FORCE_SLAVE | BTM_SEC_ATTEMPT_SLAVE); + } + else +#endif + { + p_srec->security_flags &= + ~(BTM_SEC_OUT_AUTHORIZE | BTM_SEC_OUT_ENCRYPT | BTM_SEC_OUT_AUTHENTICATE | BTM_SEC_OUT_MITM | + BTM_SEC_FORCE_MASTER | BTM_SEC_ATTEMPT_MASTER | BTM_SEC_FORCE_SLAVE | BTM_SEC_ATTEMPT_SLAVE); + } + + /* Parameter validation. Originator should not set requirements for incoming connections */ + sec_level &= ~(BTM_SEC_IN_AUTHORIZE | BTM_SEC_IN_ENCRYPT | BTM_SEC_IN_AUTHENTICATE + | BTM_SEC_IN_MITM | BTM_SEC_IN_MIN_16_DIGIT_PIN ); + + if (btm_cb.security_mode == BTM_SEC_MODE_SP || + btm_cb.security_mode == BTM_SEC_MODE_SP_DEBUG || + btm_cb.security_mode == BTM_SEC_MODE_SC) + { + if (sec_level & BTM_SEC_OUT_AUTHENTICATE) + sec_level |= BTM_SEC_OUT_MITM; + } + + /* Make sure the authenticate bit is set, when encrypt bit is set */ + if (sec_level & BTM_SEC_OUT_ENCRYPT) + sec_level |= BTM_SEC_OUT_AUTHENTICATE; + + /* outgoing connections usually set the security level right before + * the connection is initiated. + * set it to be the outgoing service */ +#if (L2CAP_UCD_INCLUDED == TRUE) + if ( is_ucd == FALSE ) +#endif + { + btm_cb.p_out_serv = p_srec; + } + } + else + { + p_srec->term_mx_chan_id = mx_chan_id; +#if BTM_SEC_SERVICE_NAME_LEN > 0 + BCM_STRNCPY_S ((char *)p_srec->term_service_name, sizeof(p_srec->term_service_name), p_name, BTM_SEC_SERVICE_NAME_LEN); +#endif + /* clear out the old setting, just in case it exists */ +#if (L2CAP_UCD_INCLUDED == TRUE) + if ( is_ucd ) + { + p_srec->ucd_security_flags &= + ~(BTM_SEC_IN_AUTHORIZE | BTM_SEC_IN_ENCRYPT | BTM_SEC_IN_AUTHENTICATE | BTM_SEC_IN_MITM | + BTM_SEC_FORCE_MASTER | BTM_SEC_ATTEMPT_MASTER | BTM_SEC_FORCE_SLAVE | BTM_SEC_ATTEMPT_SLAVE + | BTM_SEC_IN_MIN_16_DIGIT_PIN); + } + else +#endif + { + p_srec->security_flags &= + ~(BTM_SEC_IN_AUTHORIZE | BTM_SEC_IN_ENCRYPT | BTM_SEC_IN_AUTHENTICATE | BTM_SEC_IN_MITM | + BTM_SEC_FORCE_MASTER | BTM_SEC_ATTEMPT_MASTER | BTM_SEC_FORCE_SLAVE | BTM_SEC_ATTEMPT_SLAVE + | BTM_SEC_IN_MIN_16_DIGIT_PIN); + } + + /* Parameter validation. Acceptor should not set requirements for outgoing connections */ + sec_level &= ~(BTM_SEC_OUT_AUTHORIZE | BTM_SEC_OUT_ENCRYPT | BTM_SEC_OUT_AUTHENTICATE | BTM_SEC_OUT_MITM); + + if (btm_cb.security_mode == BTM_SEC_MODE_SP || + btm_cb.security_mode == BTM_SEC_MODE_SP_DEBUG || + btm_cb.security_mode == BTM_SEC_MODE_SC) + { + if (sec_level & BTM_SEC_IN_AUTHENTICATE) + sec_level |= BTM_SEC_IN_MITM; + } + + /* Make sure the authenticate bit is set, when encrypt bit is set */ + if (sec_level & BTM_SEC_IN_ENCRYPT) + sec_level |= BTM_SEC_IN_AUTHENTICATE; + } + +#if (L2CAP_UCD_INCLUDED == TRUE) + if ( is_ucd ) + { + p_srec->security_flags |= (UINT16)(BTM_SEC_IN_USE); + p_srec->ucd_security_flags |= (UINT16)(sec_level | BTM_SEC_IN_USE); + } + else + { + p_srec->security_flags |= (UINT16)(sec_level | BTM_SEC_IN_USE); + } + + BTM_TRACE_API("BTM_SEC_REG[%d]: id %d, conn_type 0x%x, psm 0x%04x, proto_id %d, chan_id %d", + index, service_id, conn_type, psm, mx_proto_id, mx_chan_id); + + BTM_TRACE_API(" : security_flags: 0x%04x, ucd_security_flags: 0x%04x", + p_srec->security_flags, p_srec->ucd_security_flags); + +#if BTM_SEC_SERVICE_NAME_LEN > 0 + BTM_TRACE_API(" : service name [%s] (up to %d chars saved)", + p_name, BTM_SEC_SERVICE_NAME_LEN); +#endif +#else + p_srec->security_flags |= (UINT16)(sec_level | BTM_SEC_IN_USE); + + BTM_TRACE_API("BTM_SEC_REG[%d]: id %d, is_orig %d, psm 0x%04x, proto_id %d, chan_id %d", + index, service_id, is_originator, psm, mx_proto_id, mx_chan_id); + +#if BTM_SEC_SERVICE_NAME_LEN > 0 + BTM_TRACE_API(" : sec: 0x%x, service name [%s] (up to %d chars saved)", + p_srec->security_flags, p_name, BTM_SEC_SERVICE_NAME_LEN); +#endif +#endif + + + return(record_allocated); +} + +/******************************************************************************* +** +** Function BTM_SecClrService +** +** Description Removes specified service record(s) from the security database. +** All service records with the specified name are removed. +** Typically used only by devices with limited RAM so that it can +** reuse an old security service record. +** +** Note: Unpredictable results may occur if a service is cleared +** that is still in use by an application/profile. +** +** Parameters Service ID - Id of the service to remove. ('0' removes all service +** records (except SDP). +** +** Returns Number of records that were freed. +** +*******************************************************************************/ +UINT8 BTM_SecClrService (UINT8 service_id) +{ + tBTM_SEC_SERV_REC *p_srec = &btm_cb.sec_serv_rec[0]; + UINT8 num_freed = 0; + int i; + + for (i = 0; i < BTM_SEC_MAX_SERVICE_RECORDS; i++, p_srec++) + { + /* Delete services with specified name (if in use and not SDP) */ + if ((p_srec->security_flags & BTM_SEC_IN_USE) && (p_srec->psm != BT_PSM_SDP) && + (!service_id || (service_id == p_srec->service_id))) + { + BTM_TRACE_API("BTM_SEC_CLR[%d]: id %d", i, service_id); + p_srec->security_flags = 0; +#if (L2CAP_UCD_INCLUDED == TRUE) + p_srec->ucd_security_flags = 0; +#endif + num_freed++; + } + } + + return(num_freed); +} + +/******************************************************************************* +** +** Function btm_sec_clr_service_by_psm +** +** Description Removes specified service record from the security database. +** All service records with the specified psm are removed. +** Typically used by L2CAP to free up the service record used +** by dynamic PSM clients when the channel is closed. +** The given psm must be a virtual psm. +** +** Parameters Service ID - Id of the service to remove. ('0' removes all service +** records (except SDP). +** +** Returns Number of records that were freed. +** +*******************************************************************************/ +UINT8 btm_sec_clr_service_by_psm (UINT16 psm) +{ + tBTM_SEC_SERV_REC *p_srec = &btm_cb.sec_serv_rec[0]; + UINT8 num_freed = 0; + int i; + + for (i = 0; i < BTM_SEC_MAX_SERVICE_RECORDS; i++, p_srec++) + { + /* Delete services with specified name (if in use and not SDP) */ + if ((p_srec->security_flags & BTM_SEC_IN_USE) && (p_srec->psm == psm) ) + { + BTM_TRACE_API("BTM_SEC_CLR[%d]: id %d ", i, p_srec->service_id); + p_srec->security_flags = 0; + num_freed++; + } + } + BTM_TRACE_API("btm_sec_clr_service_by_psm psm:0x%x num_freed:%d", psm, num_freed); + + return(num_freed); +} + +/******************************************************************************* +** +** Function btm_sec_clr_temp_auth_service +** +** Description Removes specified device record's temporary authorization +** flag from the security database. +** +** Parameters Device address to be cleared +** +** Returns void. +** +*******************************************************************************/ +void btm_sec_clr_temp_auth_service (BD_ADDR bda) +{ + tBTM_SEC_DEV_REC *p_dev_rec; + + if ((p_dev_rec = btm_find_dev (bda)) == NULL) + { + BTM_TRACE_WARNING ("btm_sec_clr_temp_auth_service() - no dev CB"); + return; + } + + /* Reset the temporary authorized flag so that next time (untrusted) service is accessed autorization will take place */ + if (p_dev_rec->last_author_service_id != BTM_SEC_NO_LAST_SERVICE_ID && p_dev_rec->p_cur_service) + { + BTM_TRACE_DEBUG ("btm_sec_clr_auth_service_by_psm [clearing device: %02x:%02x:%02x:%02x:%02x:%02x]", + bda[0], bda[1], bda[2], bda[3], bda[4], bda[5]); + + p_dev_rec->last_author_service_id = BTM_SEC_NO_LAST_SERVICE_ID; + } +} + +/******************************************************************************* +** +** Function BTM_PINCodeReply +** +** Description This function is called after Security Manager submitted +** PIN code request to the UI. +** +** Parameters: bd_addr - Address of the device for which PIN was requested +** res - result of the operation BTM_SUCCESS if success +** pin_len - length in bytes of the PIN Code +** p_pin - pointer to array with the PIN Code +** trusted_mask - bitwise OR of trusted services (array of UINT32) +** +*******************************************************************************/ +void BTM_PINCodeReply (BD_ADDR bd_addr, UINT8 res, UINT8 pin_len, UINT8 *p_pin, UINT32 trusted_mask[]) +{ + tBTM_SEC_DEV_REC *p_dev_rec; + + BTM_TRACE_API ("BTM_PINCodeReply(): PairState: %s PairFlags: 0x%02x PinLen:%d Result:%d", + btm_pair_state_descr(btm_cb.pairing_state), btm_cb.pairing_flags, pin_len, res); + + /* If timeout already expired or has been canceled, ignore the reply */ + if (btm_cb.pairing_state != BTM_PAIR_STATE_WAIT_LOCAL_PIN) + { + BTM_TRACE_WARNING ("BTM_PINCodeReply() - Wrong State: %d", btm_cb.pairing_state); + return; + } + + if (memcmp (bd_addr, btm_cb.pairing_bda, BD_ADDR_LEN) != 0) + { + BTM_TRACE_ERROR ("BTM_PINCodeReply() - Wrong BD Addr"); + return; + } + + if ((p_dev_rec = btm_find_dev (bd_addr)) == NULL) + { + BTM_TRACE_ERROR ("BTM_PINCodeReply() - no dev CB"); + return; + } + + if ( (pin_len > PIN_CODE_LEN) || (pin_len == 0) || (p_pin == NULL) ) + res = BTM_ILLEGAL_VALUE; + + if (res != BTM_SUCCESS) + { + /* if peer started dd OR we started dd and pre-fetch pin was not used send negative reply */ + if ((btm_cb.pairing_flags & BTM_PAIR_FLAGS_PEER_STARTED_DD) || + ((btm_cb.pairing_flags & BTM_PAIR_FLAGS_WE_STARTED_DD) && + (btm_cb.pairing_flags & BTM_PAIR_FLAGS_DISC_WHEN_DONE)) ) + { + /* use BTM_PAIR_STATE_WAIT_AUTH_COMPLETE to report authentication failed event */ + btm_sec_change_pairing_state (BTM_PAIR_STATE_WAIT_AUTH_COMPLETE); + btm_cb.acl_disc_reason = HCI_ERR_HOST_REJECT_SECURITY; + + btsnd_hcic_pin_code_neg_reply (bd_addr); + } + else + { + p_dev_rec->security_required = BTM_SEC_NONE; + btm_sec_change_pairing_state (BTM_PAIR_STATE_IDLE); + } + return; + } + if (trusted_mask) + BTM_SEC_COPY_TRUSTED_DEVICE(trusted_mask, p_dev_rec->trusted_mask); + p_dev_rec->sec_flags |= BTM_SEC_LINK_KEY_AUTHED; + if (pin_len >= 16) { + p_dev_rec->sec_flags |= BTM_SEC_16_DIGIT_PIN_AUTHED; + } + + if ( (btm_cb.pairing_flags & BTM_PAIR_FLAGS_WE_STARTED_DD) + && (p_dev_rec->hci_handle == BTM_SEC_INVALID_HANDLE) + && (btm_cb.security_mode_changed == FALSE) ) + { + /* This is start of the dedicated bonding if local device is 2.0 */ + btm_cb.pin_code_len = pin_len; + p_dev_rec->pin_code_length = pin_len; + memcpy (btm_cb.pin_code, p_pin, pin_len); + + btm_cb.security_mode_changed = TRUE; +#ifdef APPL_AUTH_WRITE_EXCEPTION + if(!(APPL_AUTH_WRITE_EXCEPTION)(p_dev_rec->bd_addr)) +#endif + btsnd_hcic_write_auth_enable (TRUE); + + btm_cb.acl_disc_reason = 0xff ; + + /* if we rejected incoming connection request, we have to wait HCI_Connection_Complete event */ + /* before originating */ + if (btm_cb.pairing_flags & BTM_PAIR_FLAGS_REJECTED_CONNECT) + { + BTM_TRACE_WARNING ("BTM_PINCodeReply(): waiting HCI_Connection_Complete after rejected incoming connection"); + /* we change state little bit early so btm_sec_connected() will originate connection */ + /* when existing ACL link is down completely */ + btm_sec_change_pairing_state (BTM_PAIR_STATE_WAIT_PIN_REQ); + } + /* if we already accepted incoming connection from pairing device */ + else if (p_dev_rec->sm4 & BTM_SM4_CONN_PEND) + { + BTM_TRACE_WARNING ("BTM_PINCodeReply(): link is connecting so wait pin code request from peer"); + btm_sec_change_pairing_state (BTM_PAIR_STATE_WAIT_PIN_REQ); + } + else if (btm_sec_dd_create_conn(p_dev_rec) != BTM_CMD_STARTED) + { + btm_sec_change_pairing_state (BTM_PAIR_STATE_IDLE); + p_dev_rec->sec_flags &= ~BTM_SEC_LINK_KEY_AUTHED; + + if (btm_cb.api.p_auth_complete_callback) + (*btm_cb.api.p_auth_complete_callback) (p_dev_rec->bd_addr, p_dev_rec->dev_class, + p_dev_rec->sec_bd_name, HCI_ERR_AUTH_FAILURE); + } + return; + } + + btm_sec_change_pairing_state (BTM_PAIR_STATE_WAIT_AUTH_COMPLETE); + btm_cb.acl_disc_reason = HCI_SUCCESS; + +#ifdef PORCHE_PAIRING_CONFLICT + BTM_TRACE_EVENT("BTM_PINCodeReply(): Saving pin_len: %d btm_cb.pin_code_len: %d", pin_len, btm_cb.pin_code_len); + /* if this was not pre-fetched, save the PIN */ + if (btm_cb.pin_code_len == 0) + memcpy (btm_cb.pin_code, p_pin, pin_len); + btm_cb.pin_code_len_saved = pin_len; +#endif + btsnd_hcic_pin_code_req_reply (bd_addr, pin_len, p_pin); +} + +/******************************************************************************* +** +** Function btm_sec_bond_by_transport +** +** Description this is the bond function that will start either SSP or SMP. +** +** Parameters: bd_addr - Address of the device to bond +** pin_len - length in bytes of the PIN Code +** p_pin - pointer to array with the PIN Code +** trusted_mask - bitwise OR of trusted services (array of UINT32) +** +** Note: After 2.1 parameters are not used and preserved here not to change API +*******************************************************************************/ +tBTM_STATUS btm_sec_bond_by_transport (BD_ADDR bd_addr, tBT_TRANSPORT transport, + UINT8 pin_len, UINT8 *p_pin, UINT32 trusted_mask[]) +{ + tBTM_SEC_DEV_REC *p_dev_rec; + tBTM_STATUS status; + UINT8 *p_features; + UINT8 ii; + tACL_CONN *p= btm_bda_to_acl(bd_addr, transport); + BTM_TRACE_API ("btm_sec_bond_by_transport BDA: %02x:%02x:%02x:%02x:%02x:%02x", + bd_addr[0], bd_addr[1], bd_addr[2], bd_addr[3], bd_addr[4], bd_addr[5]); + + BTM_TRACE_DEBUG("btm_sec_bond_by_transport: Transport used %d" , transport); + + + /* Other security process is in progress */ + if (btm_cb.pairing_state != BTM_PAIR_STATE_IDLE) + { + BTM_TRACE_ERROR ("BTM_SecBond: already busy in state: %s", btm_pair_state_descr(btm_cb.pairing_state)); + return(BTM_WRONG_MODE); + } + + if ((p_dev_rec = btm_find_or_alloc_dev (bd_addr)) == NULL) + { + return(BTM_NO_RESOURCES); + } + + BTM_TRACE_DEBUG ("before update sec_flags=0x%x", p_dev_rec->sec_flags); + + /* Finished if connection is active and already paired */ + if ( ((p_dev_rec->hci_handle != BTM_SEC_INVALID_HANDLE) && transport == BT_TRANSPORT_BR_EDR + && (p_dev_rec->sec_flags & BTM_SEC_AUTHENTICATED)) +#if (BLE_INCLUDED == TRUE) + ||((p_dev_rec->ble_hci_handle != BTM_SEC_INVALID_HANDLE) && transport == BT_TRANSPORT_LE + && (p_dev_rec->sec_flags & BTM_SEC_LE_AUTHENTICATED)) +#endif + + ) + { + BTM_TRACE_WARNING("BTM_SecBond -> Already Paired"); + return(BTM_SUCCESS); + } + + /* Tell controller to get rid of the link key if it has one stored */ + if ((BTM_DeleteStoredLinkKey (bd_addr, NULL)) != BTM_SUCCESS) + return(BTM_NO_RESOURCES); + + /* Save the PIN code if we got a valid one */ + if (p_pin && (pin_len <= PIN_CODE_LEN) && (pin_len != 0)) + { + btm_cb.pin_code_len = pin_len; + p_dev_rec->pin_code_length = pin_len; + memcpy (btm_cb.pin_code, p_pin, PIN_CODE_LEN); + } + + memcpy (btm_cb.pairing_bda, bd_addr, BD_ADDR_LEN); + + btm_cb.pairing_flags = BTM_PAIR_FLAGS_WE_STARTED_DD; + + p_dev_rec->security_required = BTM_SEC_OUT_AUTHENTICATE; + p_dev_rec->is_originator = TRUE; + if (trusted_mask) + BTM_SEC_COPY_TRUSTED_DEVICE(trusted_mask, p_dev_rec->trusted_mask); + +#if BLE_INCLUDED == TRUE && SMP_INCLUDED == TRUE + if (transport == BT_TRANSPORT_LE) + { + btm_ble_init_pseudo_addr (p_dev_rec, bd_addr); + p_dev_rec->sec_flags &= ~ BTM_SEC_LE_MASK; + + if (SMP_Pair(bd_addr) == SMP_STARTED) + { + btm_cb.pairing_flags |= BTM_PAIR_FLAGS_LE_ACTIVE; + p_dev_rec->sec_state = BTM_SEC_STATE_AUTHENTICATING; + btm_sec_change_pairing_state (BTM_PAIR_STATE_WAIT_AUTH_COMPLETE); + return BTM_CMD_STARTED; + } + + btm_cb.pairing_flags = 0; + return(BTM_NO_RESOURCES); + } +#endif + + p_dev_rec->sec_flags &= ~(BTM_SEC_LINK_KEY_KNOWN | BTM_SEC_AUTHENTICATED | BTM_SEC_ENCRYPTED + | BTM_SEC_ROLE_SWITCHED | BTM_SEC_LINK_KEY_AUTHED); + + + BTM_TRACE_DEBUG ("after update sec_flags=0x%x", p_dev_rec->sec_flags); + if (!controller_get_interface()->supports_simple_pairing()) + { + /* The special case when we authenticate keyboard. Set pin type to fixed */ + /* It would be probably better to do it from the application, but it is */ + /* complicated */ + if (((p_dev_rec->dev_class[1] & BTM_COD_MAJOR_CLASS_MASK) == BTM_COD_MAJOR_PERIPHERAL) + && (p_dev_rec->dev_class[2] & BTM_COD_MINOR_KEYBOARD) + && (btm_cb.cfg.pin_type != HCI_PIN_TYPE_FIXED)) + { + btm_cb.pin_type_changed = TRUE; + btsnd_hcic_write_pin_type (HCI_PIN_TYPE_FIXED); + } + } + + for (ii = 0; ii <= HCI_EXT_FEATURES_PAGE_MAX; ii++) + { + p_features = p_dev_rec->features[ii]; + BTM_TRACE_EVENT(" remote_features page[%1d] = %02x-%02x-%02x-%02x", + ii, p_features[0], p_features[1], p_features[2], p_features[3]); + BTM_TRACE_EVENT(" %02x-%02x-%02x-%02x", + p_features[4], p_features[5], p_features[6], p_features[7]); + } + + BTM_TRACE_EVENT ("BTM_SecBond: Remote sm4: 0x%x HCI Handle: 0x%04x", p_dev_rec->sm4, p_dev_rec->hci_handle); + +#if BTM_SEC_FORCE_RNR_FOR_DBOND == TRUE + p_dev_rec->sec_flags &= ~BTM_SEC_NAME_KNOWN; +#endif + + /* If connection already exists... */ + if (p && p->hci_handle != BTM_SEC_INVALID_HANDLE) + { + if (!btm_sec_start_authentication (p_dev_rec)) + return(BTM_NO_RESOURCES); + + btm_sec_change_pairing_state (BTM_PAIR_STATE_WAIT_PIN_REQ); + + /* Mark lcb as bonding */ + l2cu_update_lcb_4_bonding (bd_addr, TRUE); + return(BTM_CMD_STARTED); + } + + BTM_TRACE_DEBUG ("sec mode: %d sm4:x%x", btm_cb.security_mode, p_dev_rec->sm4); + if (!controller_get_interface()->supports_simple_pairing() + || (p_dev_rec->sm4 == BTM_SM4_KNOWN)) + { + if ( btm_sec_check_prefetch_pin (p_dev_rec) ) + return (BTM_CMD_STARTED); + } + if ((btm_cb.security_mode == BTM_SEC_MODE_SP || + btm_cb.security_mode == BTM_SEC_MODE_SP_DEBUG || + btm_cb.security_mode == BTM_SEC_MODE_SC) && + BTM_SEC_IS_SM4_UNKNOWN(p_dev_rec->sm4)) + { + /* local is 2.1 and peer is unknown */ + if ((p_dev_rec->sm4 & BTM_SM4_CONN_PEND) == 0) + { + /* we are not accepting connection request from peer + * -> RNR (to learn if peer is 2.1) + * RNR when no ACL causes HCI_RMT_HOST_SUP_FEAT_NOTIFY_EVT */ + btm_sec_change_pairing_state (BTM_PAIR_STATE_GET_REM_NAME); + BTM_ReadRemoteDeviceName(bd_addr, NULL, BT_TRANSPORT_BR_EDR); + } + else + { + /* We are accepting connection request from peer */ + btm_sec_change_pairing_state (BTM_PAIR_STATE_WAIT_PIN_REQ); + } + BTM_TRACE_DEBUG ("State:%s sm4: 0x%x sec_state:%d", + btm_pair_state_descr (btm_cb.pairing_state), p_dev_rec->sm4, p_dev_rec->sec_state); + return BTM_CMD_STARTED; + } + + /* both local and peer are 2.1 */ + status = btm_sec_dd_create_conn(p_dev_rec); + + if (status != BTM_CMD_STARTED) + { + btm_sec_change_pairing_state (BTM_PAIR_STATE_IDLE); + } + + return status; +} + +/******************************************************************************* +** +** Function BTM_SecBondByTransport +** +** Description This function is called to perform bonding with peer device. +** If the connection is already up, but not secure, pairing +** is attempted. If already paired BTM_SUCCESS is returned. +** +** Parameters: bd_addr - Address of the device to bond +** transport - doing SSP over BR/EDR or SMP over LE +** pin_len - length in bytes of the PIN Code +** p_pin - pointer to array with the PIN Code +** trusted_mask - bitwise OR of trusted services (array of UINT32) +** +** Note: After 2.1 parameters are not used and preserved here not to change API +*******************************************************************************/ +tBTM_STATUS BTM_SecBondByTransport (BD_ADDR bd_addr, tBT_TRANSPORT transport, + UINT8 pin_len, UINT8 *p_pin, UINT32 trusted_mask[]) +{ +#if SMP_INCLUDED == TRUE + tBT_DEVICE_TYPE dev_type; + tBLE_ADDR_TYPE addr_type; + + BTM_ReadDevInfo(bd_addr, &dev_type, &addr_type); + /* LE device, do SMP pairing */ + if ((transport == BT_TRANSPORT_LE && (dev_type & BT_DEVICE_TYPE_BLE) == 0) || + (transport == BT_TRANSPORT_BR_EDR && (dev_type & BT_DEVICE_TYPE_BREDR) == 0)) + { + return BTM_ILLEGAL_ACTION; + } +#endif + return btm_sec_bond_by_transport(bd_addr, transport, pin_len, p_pin, trusted_mask); +} + +/******************************************************************************* +** +** Function BTM_SecBond +** +** Description This function is called to perform bonding with peer device. +** If the connection is already up, but not secure, pairing +** is attempted. If already paired BTM_SUCCESS is returned. +** +** Parameters: bd_addr - Address of the device to bond +** pin_len - length in bytes of the PIN Code +** p_pin - pointer to array with the PIN Code +** trusted_mask - bitwise OR of trusted services (array of UINT32) +** +** Note: After 2.1 parameters are not used and preserved here not to change API +*******************************************************************************/ +tBTM_STATUS BTM_SecBond (BD_ADDR bd_addr, UINT8 pin_len, UINT8 *p_pin, UINT32 trusted_mask[]) +{ + tBT_TRANSPORT transport = BT_TRANSPORT_BR_EDR; +#if BLE_INCLUDED == TRUE + if (BTM_UseLeLink(bd_addr)) + transport = BT_TRANSPORT_LE; +#endif + return btm_sec_bond_by_transport(bd_addr, transport, pin_len, p_pin, trusted_mask); +} +/******************************************************************************* +** +** Function BTM_SecBondCancel +** +** Description This function is called to cancel ongoing bonding process +** with peer device. +** +** Parameters: bd_addr - Address of the peer device +** transport - FALSE for BR/EDR link; TRUE for LE link +** +*******************************************************************************/ +tBTM_STATUS BTM_SecBondCancel (BD_ADDR bd_addr) +{ + tBTM_SEC_DEV_REC *p_dev_rec; + + BTM_TRACE_API ("BTM_SecBondCancel() State: %s flags:0x%x", + btm_pair_state_descr (btm_cb.pairing_state), btm_cb.pairing_flags); + + if (((p_dev_rec = btm_find_dev (bd_addr)) == NULL) + || (memcmp (btm_cb.pairing_bda, bd_addr, BD_ADDR_LEN) != 0) ) + return BTM_UNKNOWN_ADDR; + +#if SMP_INCLUDED == TRUE + if (btm_cb.pairing_flags & BTM_PAIR_FLAGS_LE_ACTIVE) + { + if (p_dev_rec->sec_state == BTM_SEC_STATE_AUTHENTICATING) + { + BTM_TRACE_DEBUG ("Cancel LE pairing"); + if (SMP_PairCancel(bd_addr)) + { + return BTM_CMD_STARTED; + } + } + return BTM_WRONG_MODE; + } + +#endif + BTM_TRACE_DEBUG ("hci_handle:0x%x sec_state:%d", p_dev_rec->hci_handle, p_dev_rec->sec_state ); + if (BTM_PAIR_STATE_WAIT_LOCAL_PIN == btm_cb.pairing_state && + BTM_PAIR_FLAGS_WE_STARTED_DD & btm_cb.pairing_flags) + { + /* pre-fetching pin for dedicated bonding */ + btm_sec_bond_cancel_complete(); + return BTM_SUCCESS; + } + + /* If this BDA is in a bonding procedure */ + if ( (btm_cb.pairing_state != BTM_PAIR_STATE_IDLE) + && (btm_cb.pairing_flags & BTM_PAIR_FLAGS_WE_STARTED_DD)) + { + /* If the HCI link is up */ + if (p_dev_rec->hci_handle != BTM_SEC_INVALID_HANDLE) + { + /* If some other thread disconnecting, we do not send second command */ + if ((p_dev_rec->sec_state == BTM_SEC_STATE_DISCONNECTING) || + (p_dev_rec->sec_state == BTM_SEC_STATE_DISCONNECTING_BOTH)) + return(BTM_CMD_STARTED); + + /* If the HCI link was set up by Bonding process */ + if (btm_cb.pairing_flags & BTM_PAIR_FLAGS_DISC_WHEN_DONE) + return btm_sec_send_hci_disconnect(p_dev_rec, HCI_ERR_PEER_USER, p_dev_rec->hci_handle); + else + l2cu_update_lcb_4_bonding(bd_addr, FALSE); + + return BTM_NOT_AUTHORIZED; + } + else /*HCI link is not up */ + { + /* If the HCI link creation was started by Bonding process */ + if (btm_cb.pairing_flags & BTM_PAIR_FLAGS_DISC_WHEN_DONE) + { + if (btsnd_hcic_create_conn_cancel(bd_addr)) + return BTM_CMD_STARTED; + + return BTM_NO_RESOURCES; + } + if (btm_cb.pairing_state == BTM_PAIR_STATE_GET_REM_NAME) + { + BTM_CancelRemoteDeviceName(); + btm_cb.pairing_flags |= BTM_PAIR_FLAGS_WE_CANCEL_DD; + return BTM_CMD_STARTED; + } + return BTM_NOT_AUTHORIZED; + } + } + + return BTM_WRONG_MODE; +} + +/******************************************************************************* +** +** Function BTM_SecGetDeviceLinkKey +** +** Description This function is called to obtain link key for the device +** it returns BTM_SUCCESS if link key is available, or +** BTM_UNKNOWN_ADDR if Security Manager does not know about +** the device or device record does not contain link key info +** +** Parameters: bd_addr - Address of the device +** link_key - Link Key is copied into this array +** +*******************************************************************************/ +tBTM_STATUS BTM_SecGetDeviceLinkKey (BD_ADDR bd_addr, LINK_KEY link_key) +{ + tBTM_SEC_DEV_REC *p_dev_rec; + + if (((p_dev_rec = btm_find_dev (bd_addr)) != NULL) + && (p_dev_rec->sec_flags & BTM_SEC_LINK_KEY_KNOWN)) + { + memcpy (link_key, p_dev_rec->link_key, LINK_KEY_LEN); + return(BTM_SUCCESS); + } + return(BTM_UNKNOWN_ADDR); +} + +/******************************************************************************* +** +** Function BTM_SecGetDeviceLinkKeyType +** +** Description This function is called to obtain link key type for the +** device. +** it returns BTM_SUCCESS if link key is available, or +** BTM_UNKNOWN_ADDR if Security Manager does not know about +** the device or device record does not contain link key info +** +** Returns BTM_LKEY_TYPE_IGNORE if link key is unknown, link type +** otherwise. +** +*******************************************************************************/ +tBTM_LINK_KEY_TYPE BTM_SecGetDeviceLinkKeyType (BD_ADDR bd_addr) +{ + tBTM_SEC_DEV_REC *p_dev_rec = btm_find_dev (bd_addr); + + if ((p_dev_rec != NULL) && (p_dev_rec->sec_flags & BTM_SEC_LINK_KEY_KNOWN)) + { + return p_dev_rec->link_key_type; + } + return BTM_LKEY_TYPE_IGNORE; +} + +/******************************************************************************* +** +** Function BTM_SetEncryption +** +** Description This function is called to ensure that connection is +** encrypted. Should be called only on an open connection. +** Typically only needed for connections that first want to +** bring up unencrypted links, then later encrypt them. +** +** Parameters: bd_addr - Address of the peer device +** p_callback - Pointer to callback function called if +** this function returns PENDING after required +** procedures are completed. Can be set to NULL +** if status is not desired. +** p_ref_data - pointer to any data the caller wishes to receive +** in the callback function upon completion. +* can be set to NULL if not used. +** transport - TRUE to encryption the link over LE transport +** or FALSE for BR/EDR transport +** +** Returns BTM_SUCCESS - already encrypted +** BTM_PENDING - command will be returned in the callback +** BTM_WRONG_MODE- connection not up. +** BTM_BUSY - security procedures are currently active +** BTM_MODE_UNSUPPORTED - if security manager not linked in. +** +*******************************************************************************/ +tBTM_STATUS BTM_SetEncryption (BD_ADDR bd_addr, tBT_TRANSPORT transport, tBTM_SEC_CBACK *p_callback, + void *p_ref_data) +{ + tBTM_STATUS rc = 0; + + tBTM_SEC_DEV_REC *p_dev_rec = btm_find_dev (bd_addr); + if (!p_dev_rec || + (transport == BT_TRANSPORT_BR_EDR && p_dev_rec->hci_handle == BTM_SEC_INVALID_HANDLE) +#if BLE_INCLUDED == TRUE + || (transport == BT_TRANSPORT_LE && p_dev_rec->ble_hci_handle == BTM_SEC_INVALID_HANDLE) +#endif + ) + { + /* Connection should be up and runnning */ + BTM_TRACE_WARNING ("Security Manager: BTM_SetEncryption not connected"); + + if (p_callback) + (*p_callback) (bd_addr, transport, p_ref_data, BTM_WRONG_MODE); + + return(BTM_WRONG_MODE); + } + + if ((transport == BT_TRANSPORT_BR_EDR && + (p_dev_rec->sec_flags & BTM_SEC_ENCRYPTED)) +#if BLE_INCLUDED == TRUE && SMP_INCLUDED == TRUE + || (transport == BT_TRANSPORT_LE && + (p_dev_rec->sec_flags & BTM_SEC_LE_ENCRYPTED)) +#endif + ) + { + BTM_TRACE_EVENT ("Security Manager: BTM_SetEncryption already encrypted"); + + if (p_callback) + (*p_callback) (bd_addr, transport, p_ref_data, BTM_SUCCESS); + + return(BTM_SUCCESS); + } + + /* enqueue security request if security is active */ + if (p_dev_rec->p_callback || (p_dev_rec->sec_state != BTM_SEC_STATE_IDLE)) + { + BTM_TRACE_WARNING ("Security Manager: BTM_SetEncryption busy, enqueue request"); + + if (btm_sec_queue_encrypt_request(bd_addr, transport, p_callback, p_ref_data)) + { + return BTM_CMD_STARTED; + } + else + { + if (p_callback) + (*p_callback) (bd_addr, transport, p_ref_data, BTM_NO_RESOURCES); + return BTM_NO_RESOURCES; + } + } + + p_dev_rec->p_callback = p_callback; + p_dev_rec->p_ref_data = p_ref_data; + p_dev_rec->security_required |= (BTM_SEC_IN_AUTHENTICATE | BTM_SEC_IN_ENCRYPT); + p_dev_rec->is_originator = FALSE; + + BTM_TRACE_API ("Security Manager: BTM_SetEncryption Handle:%d State:%d Flags:0x%x Required:0x%x", + p_dev_rec->hci_handle, p_dev_rec->sec_state, p_dev_rec->sec_flags, + p_dev_rec->security_required); + +#if BLE_INCLUDED == TRUE && SMP_INCLUDED == TRUE + if (transport == BT_TRANSPORT_LE) + { + tACL_CONN *p = btm_bda_to_acl(bd_addr, transport); + if (p) + { + rc = btm_ble_set_encryption(bd_addr, p_ref_data, p->link_role); + } + else + { + rc = BTM_WRONG_MODE; + BTM_TRACE_WARNING("%s: cannot call btm_ble_set_encryption, p is NULL", __FUNCTION__); + } + } + else +#endif + rc = btm_sec_execute_procedure (p_dev_rec); + + if (rc != BTM_CMD_STARTED && rc != BTM_BUSY) + { + if (p_callback) + { + p_dev_rec->p_callback = NULL; + (*p_callback) (bd_addr, transport, p_dev_rec->p_ref_data, rc); + } + } + + return(rc); +} + +/******************************************************************************* + * disconnect the ACL link, if it's not done yet. +*******************************************************************************/ +static tBTM_STATUS btm_sec_send_hci_disconnect (tBTM_SEC_DEV_REC *p_dev_rec, UINT8 reason, UINT16 conn_handle) +{ + UINT8 old_state = p_dev_rec->sec_state; + tBTM_STATUS status = BTM_CMD_STARTED; + + BTM_TRACE_EVENT ("btm_sec_send_hci_disconnect: handle:0x%x, reason=0x%x", + conn_handle, reason); + + /* send HCI_Disconnect on a transport only once */ + switch (old_state) + { + case BTM_SEC_STATE_DISCONNECTING: + if (conn_handle == p_dev_rec->hci_handle) + return status; + + p_dev_rec->sec_state = BTM_SEC_STATE_DISCONNECTING_BOTH; + break; + +#if BLE_INCLUDED == TRUE && SMP_INCLUDED == TRUE + case BTM_SEC_STATE_DISCONNECTING_BLE: + if (conn_handle == p_dev_rec->ble_hci_handle) + return status; + + p_dev_rec->sec_state = BTM_SEC_STATE_DISCONNECTING_BOTH; + break; + + case BTM_SEC_STATE_DISCONNECTING_BOTH: + return status; +#endif + + default: + p_dev_rec->sec_state = (conn_handle == p_dev_rec->hci_handle) ? + BTM_SEC_STATE_DISCONNECTING : BTM_SEC_STATE_DISCONNECTING_BLE; + + break; + } + + /* If a role switch is in progress, delay the HCI Disconnect to avoid controller problem */ + if (p_dev_rec->rs_disc_pending == BTM_SEC_RS_PENDING && p_dev_rec->hci_handle == conn_handle) + { + BTM_TRACE_DEBUG("RS in progress - Set DISC Pending flag in btm_sec_send_hci_disconnect to delay disconnect"); + p_dev_rec->rs_disc_pending = BTM_SEC_DISC_PENDING; + status = BTM_SUCCESS; + } + /* Tear down the HCI link */ + else if (!btsnd_hcic_disconnect (conn_handle, reason)) + { + /* could not send disconnect. restore old state */ + p_dev_rec->sec_state = old_state; + status = BTM_NO_RESOURCES; + } + + return status; +} + +/******************************************************************************* +** +** Function BTM_ConfirmReqReply +** +** Description This function is called to confirm the numeric value for +** Simple Pairing in response to BTM_SP_CFM_REQ_EVT +** +** Parameters: res - result of the operation BTM_SUCCESS if success +** bd_addr - Address of the peer device +** +*******************************************************************************/ +void BTM_ConfirmReqReply(tBTM_STATUS res, BD_ADDR bd_addr) +{ + tBTM_SEC_DEV_REC *p_dev_rec; + + BTM_TRACE_EVENT ("BTM_ConfirmReqReply() State: %s Res: %u", + btm_pair_state_descr(btm_cb.pairing_state), res); + + /* If timeout already expired or has been canceled, ignore the reply */ + if ( (btm_cb.pairing_state != BTM_PAIR_STATE_WAIT_NUMERIC_CONFIRM) + || (memcmp (btm_cb.pairing_bda, bd_addr, BD_ADDR_LEN) != 0) ) + return; + + btm_sec_change_pairing_state (BTM_PAIR_STATE_WAIT_AUTH_COMPLETE); + + if ( (res == BTM_SUCCESS) || (res == BTM_SUCCESS_NO_SECURITY) ) + { + btm_cb.acl_disc_reason = HCI_SUCCESS; + + if (res == BTM_SUCCESS) + { + if ((p_dev_rec = btm_find_dev (bd_addr)) != NULL) + p_dev_rec->sec_flags |= BTM_SEC_LINK_KEY_AUTHED; + p_dev_rec->sec_flags |= BTM_SEC_16_DIGIT_PIN_AUTHED; + } + + btsnd_hcic_user_conf_reply (bd_addr, TRUE); + } + else + { + /* Report authentication failed event from state BTM_PAIR_STATE_WAIT_AUTH_COMPLETE */ + btm_cb.acl_disc_reason = HCI_ERR_HOST_REJECT_SECURITY; + btsnd_hcic_user_conf_reply (bd_addr, FALSE); + } +} + +/******************************************************************************* +** +** Function BTM_PasskeyReqReply +** +** Description This function is called to provide the passkey for +** Simple Pairing in response to BTM_SP_KEY_REQ_EVT +** +** Parameters: res - result of the operation BTM_SUCCESS if success +** bd_addr - Address of the peer device +** passkey - numeric value in the range of +** BTM_MIN_PASSKEY_VAL(0) - BTM_MAX_PASSKEY_VAL(999999(0xF423F)). +** +*******************************************************************************/ +#if (BTM_LOCAL_IO_CAPS != BTM_IO_CAP_NONE) +void BTM_PasskeyReqReply(tBTM_STATUS res, BD_ADDR bd_addr, UINT32 passkey) +{ + BTM_TRACE_API ("BTM_PasskeyReqReply: State: %s res:%d", + btm_pair_state_descr(btm_cb.pairing_state), res); + + if ( (btm_cb.pairing_state == BTM_PAIR_STATE_IDLE) + || (memcmp (btm_cb.pairing_bda, bd_addr, BD_ADDR_LEN) != 0) ) + { + return; + } + + /* If timeout already expired or has been canceled, ignore the reply */ + if ( (btm_cb.pairing_state == BTM_PAIR_STATE_WAIT_AUTH_COMPLETE) && (res != BTM_SUCCESS) ) + { + tBTM_SEC_DEV_REC *p_dev_rec = btm_find_dev (bd_addr); + if (p_dev_rec != NULL) + { + btm_cb.acl_disc_reason = HCI_ERR_HOST_REJECT_SECURITY; + + if (p_dev_rec->hci_handle != BTM_SEC_INVALID_HANDLE) + btm_sec_send_hci_disconnect (p_dev_rec, HCI_ERR_AUTH_FAILURE, p_dev_rec->hci_handle); + else + BTM_SecBondCancel(bd_addr); + + p_dev_rec->sec_flags &= ~(BTM_SEC_LINK_KEY_AUTHED | BTM_SEC_LINK_KEY_KNOWN); + + btm_sec_change_pairing_state (BTM_PAIR_STATE_IDLE); + return; + } + } + else if (btm_cb.pairing_state != BTM_PAIR_STATE_KEY_ENTRY) + return; + + if (passkey > BTM_MAX_PASSKEY_VAL) + res = BTM_ILLEGAL_VALUE; + + btm_sec_change_pairing_state (BTM_PAIR_STATE_WAIT_AUTH_COMPLETE); + + if (res != BTM_SUCCESS) + { + /* use BTM_PAIR_STATE_WAIT_AUTH_COMPLETE to report authentication failed event */ + btm_cb.acl_disc_reason = HCI_ERR_HOST_REJECT_SECURITY; + btsnd_hcic_user_passkey_neg_reply (bd_addr); + } else { + btm_cb.acl_disc_reason = HCI_SUCCESS; + btsnd_hcic_user_passkey_reply (bd_addr, passkey); + } +} +#endif + +/******************************************************************************* +** +** Function BTM_SendKeypressNotif +** +** Description This function is used during the passkey entry model +** by a device with KeyboardOnly IO capabilities +** (very likely to be a HID Device). +** It is called by a HID Device to inform the remote device when +** a key has been entered or erased. +** +** Parameters: bd_addr - Address of the peer device +** type - notification type +** +*******************************************************************************/ +#if (BTM_LOCAL_IO_CAPS != BTM_IO_CAP_NONE) +void BTM_SendKeypressNotif(BD_ADDR bd_addr, tBTM_SP_KEY_TYPE type) +{ + /* This API only make sense between PASSKEY_REQ and SP complete */ + if (btm_cb.pairing_state == BTM_PAIR_STATE_KEY_ENTRY) + btsnd_hcic_send_keypress_notif (bd_addr, type); +} +#endif + +#if BTM_OOB_INCLUDED == TRUE +/******************************************************************************* +** +** Function BTM_IoCapRsp +** +** Description This function is called in response to BTM_SP_IO_REQ_EVT +** When the event data io_req.oob_data is set to BTM_OOB_UNKNOWN +** by the tBTM_SP_CALLBACK implementation, this function is +** called to provide the actual response +** +** Parameters: bd_addr - Address of the peer device +** io_cap - The IO capability of local device. +** oob - BTM_OOB_NONE or BTM_OOB_PRESENT. +** auth_req- MITM protection required or not. +** +*******************************************************************************/ +void BTM_IoCapRsp(BD_ADDR bd_addr, tBTM_IO_CAP io_cap, tBTM_OOB_DATA oob, tBTM_AUTH_REQ auth_req) +{ + BTM_TRACE_EVENT ("BTM_IoCapRsp: state: %s oob: %d io_cap: %d", + btm_pair_state_descr(btm_cb.pairing_state), oob, io_cap); + + if ( (btm_cb.pairing_state != BTM_PAIR_STATE_WAIT_LOCAL_IOCAPS) + || (memcmp (btm_cb.pairing_bda, bd_addr, BD_ADDR_LEN) != 0) ) + return; + + if (oob < BTM_OOB_UNKNOWN && io_cap < BTM_IO_CAP_MAX) + { + btm_cb.devcb.loc_auth_req = auth_req; + btm_cb.devcb.loc_io_caps = io_cap; + + if (btm_cb.pairing_flags & BTM_PAIR_FLAGS_WE_STARTED_DD) + auth_req = (BTM_AUTH_DD_BOND | (auth_req&BTM_AUTH_YN_BIT)); + + btsnd_hcic_io_cap_req_reply (bd_addr, io_cap, oob, auth_req); + } +} + +/******************************************************************************* +** +** Function BTM_ReadLocalOobData +** +** Description This function is called to read the local OOB data from +** LM +** +*******************************************************************************/ +tBTM_STATUS BTM_ReadLocalOobData(void) +{ + tBTM_STATUS status = BTM_SUCCESS; + + if (btsnd_hcic_read_local_oob_data() == FALSE) + status = BTM_NO_RESOURCES; + + return status; +} + +/******************************************************************************* +** +** Function BTM_RemoteOobDataReply +** +** Description This function is called to provide the remote OOB data for +** Simple Pairing in response to BTM_SP_RMT_OOB_EVT +** +** Parameters: bd_addr - Address of the peer device +** c - simple pairing Hash C. +** r - simple pairing Randomizer C. +** +*******************************************************************************/ +void BTM_RemoteOobDataReply(tBTM_STATUS res, BD_ADDR bd_addr, BT_OCTET16 c, BT_OCTET16 r) +{ + BTM_TRACE_EVENT ("%s() - State: %s res: %d", __func__, + btm_pair_state_descr(btm_cb.pairing_state), res); + + /* If timeout already expired or has been canceled, ignore the reply */ + if (btm_cb.pairing_state != BTM_PAIR_STATE_WAIT_LOCAL_OOB_RSP) + return; + + btm_sec_change_pairing_state (BTM_PAIR_STATE_WAIT_AUTH_COMPLETE); + + if (res != BTM_SUCCESS) + { + /* use BTM_PAIR_STATE_WAIT_AUTH_COMPLETE to report authentication failed event */ + btm_cb.acl_disc_reason = HCI_ERR_HOST_REJECT_SECURITY; + btsnd_hcic_rem_oob_neg_reply (bd_addr); + } else { + btm_cb.acl_disc_reason = HCI_SUCCESS; + btsnd_hcic_rem_oob_reply (bd_addr, c, r); + } +} + +/******************************************************************************* +** +** Function BTM_BuildOobData +** +** Description This function is called to build the OOB data payload to +** be sent over OOB (non-Bluetooth) link +** +** Parameters: p_data - the location for OOB data +** max_len - p_data size. +** c - simple pairing Hash C. +** r - simple pairing Randomizer C. +** name_len- 0, local device name would not be included. +** otherwise, the local device name is included for +** up to this specified length +** +** Returns Number of bytes in p_data. +** +*******************************************************************************/ +UINT16 BTM_BuildOobData(UINT8 *p_data, UINT16 max_len, BT_OCTET16 c, + BT_OCTET16 r, UINT8 name_len) +{ + UINT8 *p = p_data; + UINT16 len = 0; +#if BTM_MAX_LOC_BD_NAME_LEN > 0 + UINT16 name_size; + UINT8 name_type = BTM_EIR_SHORTENED_LOCAL_NAME_TYPE; +#endif + + if (p_data && max_len >= BTM_OOB_MANDATORY_SIZE) + { + /* add mandatory part */ + UINT16_TO_STREAM(p, len); + BDADDR_TO_STREAM(p, controller_get_interface()->get_address()->address); + + len = BTM_OOB_MANDATORY_SIZE; + max_len -= len; + + /* now optional part */ + + /* add Hash C */ + UINT16 delta = BTM_OOB_HASH_C_SIZE + 2; + if (max_len >= delta) + { + *p++ = BTM_OOB_HASH_C_SIZE + 1; + *p++ = BTM_EIR_OOB_SSP_HASH_C_TYPE; + ARRAY_TO_STREAM(p, c, BTM_OOB_HASH_C_SIZE); + len += delta; + max_len -= delta; + } + + /* add Rand R */ + delta = BTM_OOB_RAND_R_SIZE + 2; + if (max_len >= delta) + { + *p++ = BTM_OOB_RAND_R_SIZE + 1; + *p++ = BTM_EIR_OOB_SSP_RAND_R_TYPE; + ARRAY_TO_STREAM(p, r, BTM_OOB_RAND_R_SIZE); + len += delta; + max_len -= delta; + } + + /* add class of device */ + delta = BTM_OOB_COD_SIZE + 2; + if (max_len >= delta) + { + *p++ = BTM_OOB_COD_SIZE + 1; + *p++ = BTM_EIR_OOB_COD_TYPE; + DEVCLASS_TO_STREAM(p, btm_cb.devcb.dev_class); + len += delta; + max_len -= delta; + } +#if BTM_MAX_LOC_BD_NAME_LEN > 0 + name_size = name_len; + if (name_size > strlen(btm_cb.cfg.bd_name)) + { + name_type = BTM_EIR_COMPLETE_LOCAL_NAME_TYPE; + name_size = (UINT16)strlen(btm_cb.cfg.bd_name); + } + delta = name_size + 2; + if (max_len >= delta) + { + *p++ = name_size + 1; + *p++ = name_type; + ARRAY_TO_STREAM (p, btm_cb.cfg.bd_name, name_size); + len += delta; + max_len -= delta; + } +#endif + /* update len */ + p = p_data; + UINT16_TO_STREAM(p, len); + } + return len; +} + +/******************************************************************************* +** +** Function BTM_BothEndsSupportSecureConnections +** +** Description This function is called to check if both the local device and the peer device +** specified by bd_addr support BR/EDR Secure Connections. +** +** Parameters: bd_addr - address of the peer +** +** Returns TRUE if BR/EDR Secure Connections are supported by both local +** and the remote device. +** else FALSE. +** +*******************************************************************************/ +BOOLEAN BTM_BothEndsSupportSecureConnections(BD_ADDR bd_addr) +{ + return ((controller_get_interface()->supports_secure_connections()) && + (BTM_PeerSupportsSecureConnections(bd_addr))); +} + +/******************************************************************************* +** +** Function BTM_PeerSupportsSecureConnections +** +** Description This function is called to check if the peer supports +** BR/EDR Secure Connections. +** +** Parameters: bd_addr - address of the peer +** +** Returns TRUE if BR/EDR Secure Connections are supported by the peer, +** else FALSE. +** +*******************************************************************************/ +BOOLEAN BTM_PeerSupportsSecureConnections(BD_ADDR bd_addr) +{ + tBTM_SEC_DEV_REC *p_dev_rec; + + if ((p_dev_rec = btm_find_dev(bd_addr)) == NULL) + { + BTM_TRACE_WARNING("%s: unknown BDA: %08x%04x", __FUNCTION__, + (bd_addr[0]<<24) + (bd_addr[1]<<16) + (bd_addr[2]<<8) + bd_addr[3], + (bd_addr[4]<< 8) + bd_addr[5]); + return FALSE; + } + + return (p_dev_rec->remote_supports_secure_connections); +} + +/******************************************************************************* +** +** Function BTM_ReadOobData +** +** Description This function is called to parse the OOB data payload +** received over OOB (non-Bluetooth) link +** +** Parameters: p_data - the location for OOB data +** eir_tag - The associated EIR tag to read the data. +** *p_len(output) - the length of the data with the given tag. +** +** Returns the beginning of the data with the given tag. +** NULL, if the tag is not found. +** +*******************************************************************************/ +UINT8 * BTM_ReadOobData(UINT8 *p_data, UINT8 eir_tag, UINT8 *p_len) +{ + UINT8 *p = p_data; + UINT16 max_len; + UINT8 len, type; + UINT8 *p_ret = NULL; + UINT8 ret_len = 0; + + if (p_data) + { + STREAM_TO_UINT16(max_len, p); + if (max_len >= BTM_OOB_MANDATORY_SIZE) + { + if (BTM_EIR_OOB_BD_ADDR_TYPE == eir_tag) + { + p_ret = p; /* the location for bd_addr */ + ret_len = BTM_OOB_BD_ADDR_SIZE; + } + else + { + p += BD_ADDR_LEN; + max_len -= BTM_OOB_MANDATORY_SIZE; + /* now the optional data in EIR format */ + while (max_len > 0) + { + len = *p++; /* tag data len + 1 */ + type = *p++; + if (eir_tag == type) + { + p_ret = p; + ret_len = len - 1; + break; + } + /* the data size of this tag is len + 1 (tag data len + 2) */ + if (max_len > len) + { + max_len -= len; + max_len--; + len--; + p += len; + } + else + max_len = 0; + } + } + } + } + + if (p_len) + *p_len = ret_len; + + return p_ret; +} +#endif + +/******************************************************************************* +** +** Function BTM_SetOutService +** +** Description This function is called to set the service for +** outgoing connections. +** +** If the profile/application calls BTM_SetSecurityLevel +** before initiating a connection, this function does not +** need to be called. +** +** Returns void +** +*******************************************************************************/ +void BTM_SetOutService(BD_ADDR bd_addr, UINT8 service_id, UINT32 mx_chan_id) +{ + tBTM_SEC_DEV_REC *p_dev_rec; + tBTM_SEC_SERV_REC *p_serv_rec = &btm_cb.sec_serv_rec[0]; + + btm_cb.p_out_serv = p_serv_rec; + p_dev_rec = btm_find_dev (bd_addr); + + for (int i = 0; i < BTM_SEC_MAX_SERVICE_RECORDS; i++, p_serv_rec++) + { + if ((p_serv_rec->security_flags & BTM_SEC_IN_USE) + && (p_serv_rec->service_id == service_id) + && (p_serv_rec->orig_mx_chan_id == mx_chan_id)) + { + BTM_TRACE_API("BTM_SetOutService p_out_serv id %d, psm 0x%04x, proto_id %d, chan_id %d", + p_serv_rec->service_id, p_serv_rec->psm, p_serv_rec->mx_proto_id, p_serv_rec->orig_mx_chan_id); + btm_cb.p_out_serv = p_serv_rec; + if (p_dev_rec) + p_dev_rec->p_cur_service = p_serv_rec; + break; + } + } +} + +/************************************************************************ +** I N T E R N A L F U N C T I O N S +*************************************************************************/ +/******************************************************************************* +** +** Function btm_sec_is_upgrade_possible +** +** Description This function returns TRUE if the existing link key +** can be upgraded or if the link key does not exist. +** +** Returns BOOLEAN +** +*******************************************************************************/ +static BOOLEAN btm_sec_is_upgrade_possible(tBTM_SEC_DEV_REC *p_dev_rec, BOOLEAN is_originator) +{ + UINT16 mtm_check = is_originator ? BTM_SEC_OUT_MITM : BTM_SEC_IN_MITM; + BOOLEAN is_possible = TRUE; + + if (p_dev_rec->sec_flags & BTM_SEC_LINK_KEY_KNOWN) + { + is_possible = FALSE; + if(p_dev_rec->p_cur_service) + { + BTM_TRACE_DEBUG ("%s() id: %d, link_key_typet: %d, rmt_io_caps: %d, chk flags: 0x%x, flags: 0x%x", + __func__, p_dev_rec->p_cur_service->service_id, p_dev_rec->link_key_type, + p_dev_rec->rmt_io_caps, mtm_check, p_dev_rec->p_cur_service->security_flags); + } + else + { + BTM_TRACE_DEBUG ("%s() link_key_typet: %d, rmt_io_caps: %d, chk flags: 0x%x", + __func__, p_dev_rec->link_key_type, p_dev_rec->rmt_io_caps, mtm_check); + } + /* Already have a link key to the connected peer. Is the link key secure enough? + ** Is a link key upgrade even possible? + */ + if ((p_dev_rec->security_required & mtm_check) /* needs MITM */ + && ((p_dev_rec->link_key_type == BTM_LKEY_TYPE_UNAUTH_COMB) || + (p_dev_rec->link_key_type == BTM_LKEY_TYPE_UNAUTH_COMB_P_256)) + /* has unauthenticated + link key */ + && (p_dev_rec->rmt_io_caps < BTM_IO_CAP_MAX) /* a valid peer IO cap */ + && (btm_sec_io_map[p_dev_rec->rmt_io_caps][btm_cb.devcb.loc_io_caps])) + /* authenticated + link key is possible */ + { + /* upgrade is possible: check if the application wants the upgrade. + * If the application is configured to use a global MITM flag, + * it probably would not want to upgrade the link key based on the security level database */ + is_possible = TRUE; + } + } + BTM_TRACE_DEBUG ("%s() is_possible: %d sec_flags: 0x%x", __func__, is_possible, p_dev_rec->sec_flags); + return is_possible; +} + +/******************************************************************************* +** +** Function btm_sec_check_upgrade +** +** Description This function is called to check if the existing link key +** needs to be upgraded. +** +** Returns void +** +*******************************************************************************/ +static void btm_sec_check_upgrade(tBTM_SEC_DEV_REC *p_dev_rec, BOOLEAN is_originator) +{ + + BTM_TRACE_DEBUG ("%s()", __func__); + + /* Only check if link key already exists */ + if (!(p_dev_rec->sec_flags & BTM_SEC_LINK_KEY_KNOWN)) + return; + + if (btm_sec_is_upgrade_possible (p_dev_rec, is_originator) == TRUE) + { + BTM_TRACE_DEBUG ("need upgrade!! sec_flags:0x%x", p_dev_rec->sec_flags); + /* upgrade is possible: check if the application wants the upgrade. + * If the application is configured to use a global MITM flag, + * it probably would not want to upgrade the link key based on the security level database */ + tBTM_SP_UPGRADE evt_data; + memcpy (evt_data.bd_addr, p_dev_rec->bd_addr, BD_ADDR_LEN); + evt_data.upgrade = TRUE; + if (btm_cb.api.p_sp_callback) + (*btm_cb.api.p_sp_callback) (BTM_SP_UPGRADE_EVT, (tBTM_SP_EVT_DATA *)&evt_data); + + BTM_TRACE_DEBUG ("evt_data.upgrade:0x%x", evt_data.upgrade); + if (evt_data.upgrade) + { + /* if the application confirms the upgrade, set the upgrade bit */ + p_dev_rec->sm4 |= BTM_SM4_UPGRADE; + + /* Clear the link key known to go through authentication/pairing again */ + p_dev_rec->sec_flags &= ~(BTM_SEC_LINK_KEY_KNOWN | BTM_SEC_LINK_KEY_AUTHED); + p_dev_rec->sec_flags &= ~BTM_SEC_AUTHENTICATED; + BTM_TRACE_DEBUG ("sec_flags:0x%x", p_dev_rec->sec_flags); + } + } +} + +/******************************************************************************* +** +** Function btm_sec_l2cap_access_req +** +** Description This function is called by the L2CAP to grant permission to +** establish L2CAP connection to or from the peer device. +** +** Parameters: bd_addr - Address of the peer device +** psm - L2CAP PSM +** is_originator - TRUE if protocol above L2CAP originates +** connection +** p_callback - Pointer to callback function called if +** this function returns PENDING after required +** procedures are complete. MUST NOT BE NULL. +** +** Returns tBTM_STATUS +** +*******************************************************************************/ +#define BTM_SEC_OUT_FLAGS (BTM_SEC_OUT_AUTHENTICATE | BTM_SEC_OUT_ENCRYPT | BTM_SEC_OUT_AUTHORIZE) +#define BTM_SEC_IN_FLAGS (BTM_SEC_IN_AUTHENTICATE | BTM_SEC_IN_ENCRYPT | BTM_SEC_IN_AUTHORIZE) + +#define BTM_SEC_OUT_LEVEL4_FLAGS (BTM_SEC_OUT_AUTHENTICATE | BTM_SEC_OUT_ENCRYPT | \ + BTM_SEC_OUT_MITM | BTM_SEC_MODE4_LEVEL4) + +#define BTM_SEC_IN_LEVEL4_FLAGS (BTM_SEC_IN_AUTHENTICATE | BTM_SEC_IN_ENCRYPT | \ + BTM_SEC_IN_MITM | BTM_SEC_MODE4_LEVEL4) + +tBTM_STATUS btm_sec_l2cap_access_req (BD_ADDR bd_addr, UINT16 psm, UINT16 handle, + CONNECTION_TYPE conn_type, + tBTM_SEC_CALLBACK *p_callback, + void *p_ref_data) +{ + tBTM_SEC_DEV_REC *p_dev_rec; + tBTM_SEC_SERV_REC *p_serv_rec; + UINT16 security_required; + UINT16 old_security_required; + BOOLEAN old_is_originator; + tBTM_STATUS rc = BTM_SUCCESS; + BOOLEAN chk_acp_auth_done = FALSE; + BOOLEAN is_originator; + BOOLEAN transport = FALSE; /* should check PSM range in LE connection oriented L2CAP connection */ + +#if (L2CAP_UCD_INCLUDED == TRUE) + if (conn_type & CONNECTION_TYPE_ORIG_MASK) + is_originator = TRUE; + else + is_originator = FALSE; + + BTM_TRACE_DEBUG ("%s() conn_type: 0x%x, 0x%x", __func__, conn_type, p_ref_data); +#else + is_originator = conn_type; + + BTM_TRACE_DEBUG ("%s() is_originator:%d, 0x%x", __func__, is_originator, p_ref_data); +#endif + + /* Find or get oldest record */ + p_dev_rec = btm_find_or_alloc_dev (bd_addr); + + p_dev_rec->hci_handle = handle; + + /* Find the service record for the PSM */ + p_serv_rec = btm_sec_find_first_serv (conn_type, psm); + + /* If there is no application registered with this PSM do not allow connection */ + if (!p_serv_rec) + { + BTM_TRACE_WARNING ("%s() PSM: %d no application registerd", __func__, psm); + (*p_callback) (bd_addr, transport, p_ref_data, BTM_MODE_UNSUPPORTED); + return(BTM_MODE_UNSUPPORTED); + } + + /* Services level0 by default have no security */ + if ((btm_sec_is_serv_level0(psm)) && (!btm_cb.devcb.secure_connections_only)) + { + (*p_callback) (bd_addr,transport, p_ref_data, BTM_SUCCESS_NO_SECURITY); + return(BTM_SUCCESS); + } +#if (L2CAP_UCD_INCLUDED == TRUE) + if ( conn_type & CONNECTION_TYPE_CONNLESS_MASK ) + { + if (btm_cb.security_mode == BTM_SEC_MODE_SC) + { + security_required = btm_sec_set_serv_level4_flags (p_serv_rec->ucd_security_flags, + is_originator); + } + else + { + security_required = p_serv_rec->ucd_security_flags; + } + + rc = BTM_CMD_STARTED; + if (is_originator) + { + if (((security_required & BTM_SEC_OUT_FLAGS) == 0) || + ((((security_required & BTM_SEC_OUT_FLAGS) == BTM_SEC_OUT_AUTHENTICATE) && (p_dev_rec->sec_flags & BTM_SEC_AUTHENTICATED))) || + ((((security_required & BTM_SEC_OUT_FLAGS) == (BTM_SEC_OUT_AUTHENTICATE | BTM_SEC_OUT_ENCRYPT)) && (p_dev_rec->sec_flags & BTM_SEC_ENCRYPTED))) || + ((((security_required & BTM_SEC_OUT_FLAGS) == BTM_SEC_OUT_FLAGS) && (p_dev_rec->sec_flags & BTM_SEC_AUTHORIZED))) ) + { + rc = BTM_SUCCESS; + } + } + else + { + if (((security_required & BTM_SEC_IN_FLAGS) == 0) || + ((((security_required & BTM_SEC_IN_FLAGS) == BTM_SEC_IN_AUTHENTICATE) && (p_dev_rec->sec_flags & BTM_SEC_AUTHENTICATED))) || + ((((security_required & BTM_SEC_IN_FLAGS) == (BTM_SEC_IN_AUTHENTICATE | BTM_SEC_IN_ENCRYPT)) && (p_dev_rec->sec_flags & BTM_SEC_ENCRYPTED))) || + ((((security_required & BTM_SEC_IN_FLAGS) == BTM_SEC_IN_FLAGS) && (p_dev_rec->sec_flags & BTM_SEC_AUTHORIZED))) ) + { + // Check for 16 digits (or MITM) + if (((security_required & BTM_SEC_IN_MIN_16_DIGIT_PIN) == 0) || + (((security_required & BTM_SEC_IN_MIN_16_DIGIT_PIN) == BTM_SEC_IN_MIN_16_DIGIT_PIN) && + btm_dev_16_digit_authenticated(p_dev_rec))) { + rc = BTM_SUCCESS; + } + } + } + + if ((rc == BTM_SUCCESS) && (security_required & BTM_SEC_MODE4_LEVEL4) && + (p_dev_rec->link_key_type != BTM_LKEY_TYPE_AUTH_COMB_P_256)) + { + rc = BTM_CMD_STARTED; + } + + if (rc == BTM_SUCCESS) + { + if (p_callback) + (*p_callback) (bd_addr, transport, (void *)p_ref_data, BTM_SUCCESS); + + return(BTM_SUCCESS); + } + } + else +#endif + { + if (btm_cb.security_mode == BTM_SEC_MODE_SC) + { + security_required = btm_sec_set_serv_level4_flags (p_serv_rec->security_flags, + is_originator); + } + else + { + security_required = p_serv_rec->security_flags; + } + } + + BTM_TRACE_DEBUG("%s: security_required 0x%04x, is_originator 0x%02x, psm 0x%04x", + __FUNCTION__, security_required, is_originator, psm); + + if ((!is_originator) && (security_required & BTM_SEC_MODE4_LEVEL4)) + { + BOOLEAN local_supports_sc = controller_get_interface()->supports_secure_connections(); + /* acceptor receives L2CAP Channel Connect Request for Secure Connections Only service */ + if (!(local_supports_sc) || !(p_dev_rec->remote_supports_secure_connections)) + { + BTM_TRACE_DEBUG("%s: SC only service, local_support_for_sc %d", + "rmt_support_for_sc : %d -> fail pairing", __FUNCTION__, + local_supports_sc, + p_dev_rec->remote_supports_secure_connections); + if (p_callback) + (*p_callback) (bd_addr, transport, (void *)p_ref_data, + BTM_MODE4_LEVEL4_NOT_SUPPORTED); + + return (BTM_MODE4_LEVEL4_NOT_SUPPORTED); + } + } + + /* there are some devices (moto KRZR) which connects to several services at the same time */ + /* we will process one after another */ + if ( (p_dev_rec->p_callback) || (btm_cb.pairing_state != BTM_PAIR_STATE_IDLE) ) + { + BTM_TRACE_EVENT ("%s() - busy - PSM:%d delayed state: %s mode:%d, sm4:0x%x", __func__, + psm, btm_pair_state_descr(btm_cb.pairing_state), btm_cb.security_mode, p_dev_rec->sm4); + BTM_TRACE_EVENT ("security_flags:x%x, sec_flags:x%x", security_required, p_dev_rec->sec_flags); + rc = BTM_CMD_STARTED; + if ((btm_cb.security_mode == BTM_SEC_MODE_UNDEFINED || + btm_cb.security_mode == BTM_SEC_MODE_NONE || + btm_cb.security_mode == BTM_SEC_MODE_SERVICE || + btm_cb.security_mode == BTM_SEC_MODE_LINK) || + (BTM_SM4_KNOWN == p_dev_rec->sm4) || (BTM_SEC_IS_SM4(p_dev_rec->sm4) && + (btm_sec_is_upgrade_possible(p_dev_rec, is_originator) == FALSE))) + { + /* legacy mode - local is legacy or local is lisbon/peer is legacy + * or SM4 with no possibility of link key upgrade */ + if (is_originator) + { + if (((security_required & BTM_SEC_OUT_FLAGS) == 0) || + ((((security_required & BTM_SEC_OUT_FLAGS) == BTM_SEC_OUT_AUTHENTICATE) && btm_dev_authenticated(p_dev_rec))) || + ((((security_required & BTM_SEC_OUT_FLAGS) == (BTM_SEC_OUT_AUTHENTICATE | BTM_SEC_OUT_ENCRYPT)) && btm_dev_encrypted(p_dev_rec))) || + ((((security_required & BTM_SEC_OUT_FLAGS) == BTM_SEC_OUT_FLAGS) && btm_dev_authorized(p_dev_rec) && btm_dev_encrypted(p_dev_rec))) ) + { + rc = BTM_SUCCESS; + } + } + else + { + if (((security_required & BTM_SEC_IN_FLAGS) == 0) || + (((security_required & BTM_SEC_IN_FLAGS) == BTM_SEC_IN_AUTHENTICATE) && btm_dev_authenticated(p_dev_rec)) || + (((security_required & BTM_SEC_IN_FLAGS) == (BTM_SEC_IN_AUTHENTICATE | BTM_SEC_IN_ENCRYPT)) && btm_dev_encrypted(p_dev_rec)) || + (((security_required & BTM_SEC_IN_FLAGS) == BTM_SEC_IN_AUTHORIZE) && (btm_dev_authorized(p_dev_rec)||btm_serv_trusted(p_dev_rec, p_serv_rec))) || + (((security_required & BTM_SEC_IN_FLAGS) == (BTM_SEC_IN_AUTHENTICATE | BTM_SEC_IN_AUTHORIZE)) && ((btm_dev_authorized(p_dev_rec)||btm_serv_trusted(p_dev_rec, p_serv_rec)) && btm_dev_authenticated(p_dev_rec))) || + (((security_required & BTM_SEC_IN_FLAGS) == (BTM_SEC_IN_ENCRYPT | BTM_SEC_IN_AUTHORIZE)) && ((btm_dev_authorized(p_dev_rec)||btm_serv_trusted(p_dev_rec, p_serv_rec)) && btm_dev_encrypted(p_dev_rec))) || + (((security_required & BTM_SEC_IN_FLAGS) == BTM_SEC_IN_FLAGS) && btm_dev_encrypted(p_dev_rec) && (btm_dev_authorized(p_dev_rec)||btm_serv_trusted(p_dev_rec, p_serv_rec)))) + { + // Check for 16 digits (or MITM) + if (((security_required & BTM_SEC_IN_MIN_16_DIGIT_PIN) == 0) || + (((security_required & BTM_SEC_IN_MIN_16_DIGIT_PIN) == BTM_SEC_IN_MIN_16_DIGIT_PIN) && btm_dev_16_digit_authenticated(p_dev_rec))) { + rc = BTM_SUCCESS; + } + } + } + + if ((rc == BTM_SUCCESS) && (security_required & BTM_SEC_MODE4_LEVEL4) && + (p_dev_rec->link_key_type != BTM_LKEY_TYPE_AUTH_COMB_P_256)) + { + rc = BTM_CMD_STARTED; + } + + if (rc == BTM_SUCCESS) + { + if (p_callback) + (*p_callback) (bd_addr, transport, (void *)p_ref_data, BTM_SUCCESS); + return(BTM_SUCCESS); + } + } + + btm_cb.sec_req_pending = TRUE; + return(BTM_CMD_STARTED); + } + + /* Save pointer to service record */ + p_dev_rec->p_cur_service = p_serv_rec; + + /* Modify security_required in btm_sec_l2cap_access_req for Lisbon */ + if (btm_cb.security_mode == BTM_SEC_MODE_SP || + btm_cb.security_mode == BTM_SEC_MODE_SP_DEBUG || + btm_cb.security_mode == BTM_SEC_MODE_SC) + { + if (BTM_SEC_IS_SM4(p_dev_rec->sm4)) + { + if (is_originator) + { + /* SM4 to SM4 -> always authenticate & encrypt */ + security_required |= (BTM_SEC_OUT_AUTHENTICATE | BTM_SEC_OUT_ENCRYPT); + } + else /* acceptor */ + { + /* SM4 to SM4: the acceptor needs to make sure the authentication is already done */ + chk_acp_auth_done = TRUE; + /* SM4 to SM4 -> always authenticate & encrypt */ + security_required |= (BTM_SEC_IN_AUTHENTICATE | BTM_SEC_IN_ENCRYPT); + } + } + else if (!(BTM_SM4_KNOWN & p_dev_rec->sm4)) + { + /* the remote features are not known yet */ + BTM_TRACE_DEBUG("%s: (%s) remote features unknown!!sec_flags:0x%02x", __FUNCTION__, + (is_originator) ? "initiator" : "acceptor", p_dev_rec->sec_flags); + + p_dev_rec->sm4 |= BTM_SM4_REQ_PEND; + return (BTM_CMD_STARTED); + } + } + + BTM_TRACE_DEBUG ("%s() sm4:0x%x, sec_flags:0x%x, security_required:0x%x chk:%d", __func__, + p_dev_rec->sm4, p_dev_rec->sec_flags, security_required, chk_acp_auth_done); + + old_security_required = p_dev_rec->security_required; + old_is_originator = p_dev_rec->is_originator; + p_dev_rec->security_required = security_required; + p_dev_rec->p_ref_data = p_ref_data; + p_dev_rec->is_originator = is_originator; + +#if (L2CAP_UCD_INCLUDED == TRUE) + if ( conn_type & CONNECTION_TYPE_CONNLESS_MASK ) + p_dev_rec->is_ucd = TRUE; + else + p_dev_rec->is_ucd = FALSE; +#endif + + /* If there are multiple service records used through the same PSM */ + /* leave security decision for the multiplexor on the top */ +#if (L2CAP_UCD_INCLUDED == TRUE) + if (((btm_sec_find_next_serv (p_serv_rec)) != NULL) + &&(!( conn_type & CONNECTION_TYPE_CONNLESS_MASK ))) /* if not UCD */ +#else + if ((btm_sec_find_next_serv (p_serv_rec)) != NULL) +#endif + { + BTM_TRACE_DEBUG ("no next_serv sm4:0x%x, chk:%d", p_dev_rec->sm4, chk_acp_auth_done); + if (!BTM_SEC_IS_SM4(p_dev_rec->sm4)) + { + BTM_TRACE_EVENT ("Security Manager: l2cap_access_req PSM:%d postponed for multiplexer", psm); + /* pre-Lisbon: restore the old settings */ + p_dev_rec->security_required = old_security_required; + p_dev_rec->is_originator = old_is_originator; + + (*p_callback) (bd_addr, transport, p_ref_data, BTM_SUCCESS); + + return(BTM_SUCCESS); + } + } + + /* if the originator is using dynamic PSM in legacy mode, do not start any security process now + * The layer above L2CAP needs to carry out the security requirement after L2CAP connect + * response is received */ + if (is_originator && + ((btm_cb.security_mode == BTM_SEC_MODE_UNDEFINED || + btm_cb.security_mode == BTM_SEC_MODE_NONE || + btm_cb.security_mode == BTM_SEC_MODE_SERVICE || + btm_cb.security_mode == BTM_SEC_MODE_LINK) || + !BTM_SEC_IS_SM4(p_dev_rec->sm4)) && (psm >= 0x1001)) + { + BTM_TRACE_EVENT ("dynamic PSM:0x%x in legacy mode - postponed for upper layer", psm); + /* restore the old settings */ + p_dev_rec->security_required = old_security_required; + p_dev_rec->is_originator = old_is_originator; + + (*p_callback) (bd_addr, transport, p_ref_data, BTM_SUCCESS); + + return(BTM_SUCCESS); + } + + if (chk_acp_auth_done) + { + BTM_TRACE_DEBUG ("(SM4 to SM4) btm_sec_l2cap_access_req rspd. authenticated: x%x, enc: x%x", + (p_dev_rec->sec_flags & BTM_SEC_AUTHENTICATED), (p_dev_rec->sec_flags & BTM_SEC_ENCRYPTED)); + /* SM4, but we do not know for sure which level of security we need. + * as long as we have a link key, it's OK */ + if ((0 == (p_dev_rec->sec_flags & BTM_SEC_AUTHENTICATED)) + ||(0 == (p_dev_rec->sec_flags & BTM_SEC_ENCRYPTED))) + { + rc = BTM_DELAY_CHECK; + /* + 2046 may report HCI_Encryption_Change and L2C Connection Request out of sequence + because of data path issues. Delay this disconnect a little bit + */ + LOG_INFO("%s peer should have initiated security process by now (SM4 to SM4)", __func__); + p_dev_rec->p_callback = p_callback; + p_dev_rec->sec_state = BTM_SEC_STATE_DELAY_FOR_ENC; + (*p_callback) (bd_addr, transport, p_ref_data, rc); + + return BTM_SUCCESS; + } + } + + p_dev_rec->p_callback = p_callback; + + if (p_dev_rec->last_author_service_id == BTM_SEC_NO_LAST_SERVICE_ID + || p_dev_rec->last_author_service_id != p_dev_rec->p_cur_service->service_id) + { + /* Although authentication and encryption are per connection + ** authorization is per access request. For example when serial connection + ** is up and authorized and client requests to read file (access to other + ** scn), we need to request user's permission again. + */ + p_dev_rec->sec_flags &= ~BTM_SEC_AUTHORIZED; + } + + if (BTM_SEC_IS_SM4(p_dev_rec->sm4)) + { + if ((p_dev_rec->security_required & BTM_SEC_MODE4_LEVEL4) && + (p_dev_rec->link_key_type != BTM_LKEY_TYPE_AUTH_COMB_P_256)) + { + /* BTM_LKEY_TYPE_AUTH_COMB_P_256 is the only acceptable key in this case */ + if ((p_dev_rec->sec_flags & BTM_SEC_LINK_KEY_KNOWN) != 0) + { + p_dev_rec->sm4 |= BTM_SM4_UPGRADE; + } + p_dev_rec->sec_flags &= ~(BTM_SEC_LINK_KEY_KNOWN | BTM_SEC_LINK_KEY_AUTHED | + BTM_SEC_AUTHENTICATED); + BTM_TRACE_DEBUG ("%s: sec_flags:0x%x", __FUNCTION__, p_dev_rec->sec_flags); + } + else + { + /* If we already have a link key to the connected peer, is it secure enough? */ + btm_sec_check_upgrade(p_dev_rec, is_originator); + } + } + + BTM_TRACE_EVENT ("%s() PSM:%d Handle:%d State:%d Flags: 0x%x Required: 0x%x Service ID:%d", + __func__, psm, handle, p_dev_rec->sec_state, p_dev_rec->sec_flags, + p_dev_rec->security_required, p_dev_rec->p_cur_service->service_id); + + if ((rc = btm_sec_execute_procedure (p_dev_rec)) != BTM_CMD_STARTED) + { + p_dev_rec->p_callback = NULL; + (*p_callback) (bd_addr, transport, p_dev_rec->p_ref_data, (UINT8)rc); + } + + return(rc); +} + +/******************************************************************************* +** +** Function btm_sec_mx_access_request +** +** Description This function is called by all Multiplexing Protocols during +** establishing connection to or from peer device to grant +** permission to establish application connection. +** +** Parameters: bd_addr - Address of the peer device +** psm - L2CAP PSM +** is_originator - TRUE if protocol above L2CAP originates +** connection +** mx_proto_id - protocol ID of the multiplexer +** mx_chan_id - multiplexer channel to reach application +** p_callback - Pointer to callback function called if +** this function returns PENDING after required +** procedures are completed +** p_ref_data - Pointer to any reference data needed by the +** the callback function. +** +** Returns BTM_CMD_STARTED +** +*******************************************************************************/ +tBTM_STATUS btm_sec_mx_access_request (BD_ADDR bd_addr, UINT16 psm, BOOLEAN is_originator, + UINT32 mx_proto_id, UINT32 mx_chan_id, + tBTM_SEC_CALLBACK *p_callback, void *p_ref_data) +{ + tBTM_SEC_DEV_REC *p_dev_rec; + tBTM_SEC_SERV_REC *p_serv_rec; + tBTM_STATUS rc; + UINT16 security_required; + BOOLEAN transport = FALSE;/* should check PSM range in LE connection oriented L2CAP connection */ + + BTM_TRACE_DEBUG ("%s() is_originator: %d", __func__, is_originator); + /* Find or get oldest record */ + p_dev_rec = btm_find_or_alloc_dev (bd_addr); + + /* Find the service record for the PSM */ + p_serv_rec = btm_sec_find_mx_serv (is_originator, psm, mx_proto_id, mx_chan_id); + + /* If there is no application registered with this PSM do not allow connection */ + if (!p_serv_rec) + { + if (p_callback) + (*p_callback) (bd_addr, transport, p_ref_data, BTM_MODE_UNSUPPORTED); + + BTM_TRACE_ERROR ("Security Manager: MX service not found PSM:%d Proto:%d SCN:%d", + psm, mx_proto_id, mx_chan_id); + return BTM_NO_RESOURCES; + } + + if ((btm_cb.security_mode == BTM_SEC_MODE_SC) && (!btm_sec_is_serv_level0(psm))) + { + security_required = btm_sec_set_serv_level4_flags (p_serv_rec->security_flags, + is_originator); + } + else + { + security_required = p_serv_rec->security_flags; + } + + /* there are some devices (moto phone) which connects to several services at the same time */ + /* we will process one after another */ + if ( (p_dev_rec->p_callback) || (btm_cb.pairing_state != BTM_PAIR_STATE_IDLE) ) + { + BTM_TRACE_EVENT ("%s() service PSM:%d Proto:%d SCN:%d delayed state: %s", __func__, + psm, mx_proto_id, mx_chan_id, btm_pair_state_descr(btm_cb.pairing_state)); + + rc = BTM_CMD_STARTED; + + if ((btm_cb.security_mode == BTM_SEC_MODE_UNDEFINED || + btm_cb.security_mode == BTM_SEC_MODE_NONE || + btm_cb.security_mode == BTM_SEC_MODE_SERVICE || + btm_cb.security_mode == BTM_SEC_MODE_LINK) || + (BTM_SM4_KNOWN == p_dev_rec->sm4) || (BTM_SEC_IS_SM4(p_dev_rec->sm4) && + (btm_sec_is_upgrade_possible(p_dev_rec, is_originator) == FALSE))) + { + /* legacy mode - local is legacy or local is lisbon/peer is legacy + * or SM4 with no possibility of link key upgrade */ + if (is_originator) + { + if (((security_required & BTM_SEC_OUT_FLAGS) == 0) || + ((((security_required & BTM_SEC_OUT_FLAGS) == BTM_SEC_OUT_AUTHENTICATE) && btm_dev_authenticated(p_dev_rec))) || + ((((security_required & BTM_SEC_OUT_FLAGS) == (BTM_SEC_OUT_AUTHENTICATE | BTM_SEC_OUT_ENCRYPT)) && btm_dev_encrypted(p_dev_rec))) + ) + { + rc = BTM_SUCCESS; + } + } + else + { + if (((security_required & BTM_SEC_IN_FLAGS) == 0) || + ((((security_required & BTM_SEC_IN_FLAGS) == BTM_SEC_IN_AUTHENTICATE) && btm_dev_authenticated(p_dev_rec))) || + (((security_required & BTM_SEC_IN_FLAGS) == BTM_SEC_IN_AUTHORIZE) && (btm_dev_authorized(p_dev_rec)||btm_serv_trusted(p_dev_rec, p_serv_rec))) || + (((security_required & BTM_SEC_IN_FLAGS) == (BTM_SEC_IN_AUTHORIZE | BTM_SEC_IN_AUTHENTICATE)) && ((btm_dev_authorized(p_dev_rec)||btm_serv_trusted(p_dev_rec, p_serv_rec)) && btm_dev_authenticated(p_dev_rec))) || + (((security_required & BTM_SEC_IN_FLAGS) == (BTM_SEC_IN_AUTHORIZE | BTM_SEC_IN_ENCRYPT)) && ((btm_dev_authorized(p_dev_rec)||btm_serv_trusted(p_dev_rec, p_serv_rec))&& btm_dev_encrypted(p_dev_rec))) || + ((((security_required & BTM_SEC_IN_FLAGS) == (BTM_SEC_IN_AUTHENTICATE | BTM_SEC_IN_ENCRYPT)) && btm_dev_encrypted(p_dev_rec))) + ) + { + // Check for 16 digits (or MITM) + if (((security_required & BTM_SEC_IN_MIN_16_DIGIT_PIN) == 0) || + (((security_required & BTM_SEC_IN_MIN_16_DIGIT_PIN) == BTM_SEC_IN_MIN_16_DIGIT_PIN) && btm_dev_16_digit_authenticated(p_dev_rec))) { + rc = BTM_SUCCESS; + } + } + } + if ((rc == BTM_SUCCESS) && (security_required & BTM_SEC_MODE4_LEVEL4) && + (p_dev_rec->link_key_type != BTM_LKEY_TYPE_AUTH_COMB_P_256)) + { + rc = BTM_CMD_STARTED; + } + } + + if (rc == BTM_SUCCESS) + { + BTM_TRACE_EVENT("%s: allow to bypass, checking authorization", __FUNCTION__); + /* the security in BTM_SEC_IN_FLAGS is fullfilled so far, check the requirements in */ + /* btm_sec_execute_procedure */ + if ((is_originator && (p_serv_rec->security_flags & BTM_SEC_OUT_AUTHORIZE)) || + (!is_originator && (p_serv_rec->security_flags & BTM_SEC_IN_AUTHORIZE))) + { + BTM_TRACE_EVENT("%s: still need authorization", __FUNCTION__); + rc = BTM_CMD_STARTED; + } + } + + /* Check whether there is a pending security procedure, if so we should always queue */ + /* the new security request */ + if (p_dev_rec->sec_state != BTM_SEC_STATE_IDLE) + { + BTM_TRACE_EVENT("%s: There is a pending security procedure", __FUNCTION__); + rc = BTM_CMD_STARTED; + } + if (rc == BTM_CMD_STARTED) + { + BTM_TRACE_EVENT("%s: call btm_sec_queue_mx_request", __FUNCTION__); + btm_sec_queue_mx_request (bd_addr, psm, is_originator, mx_proto_id, + mx_chan_id, p_callback, p_ref_data); + } + else /* rc == BTM_SUCCESS */ + { + /* access granted */ + if (p_callback) + { + (*p_callback) (bd_addr, transport, p_ref_data, (UINT8)rc); + } + } + + BTM_TRACE_EVENT("%s: return with rc = 0x%02x in delayed state %s", __FUNCTION__, rc, + btm_pair_state_descr(btm_cb.pairing_state)); + return rc; + } + + if ((!is_originator) && ((security_required & BTM_SEC_MODE4_LEVEL4) || + (btm_cb.security_mode == BTM_SEC_MODE_SC))) + { + BOOLEAN local_supports_sc = controller_get_interface()->supports_secure_connections(); + /* acceptor receives service connection establishment Request for */ + /* Secure Connections Only service */ + if (!(local_supports_sc) || !(p_dev_rec->remote_supports_secure_connections)) + { + BTM_TRACE_DEBUG("%s: SC only service,local_support_for_sc %d,", + "remote_support_for_sc %d: fail pairing",__FUNCTION__, + local_supports_sc, p_dev_rec->remote_supports_secure_connections); + + if (p_callback) + (*p_callback) (bd_addr, transport, (void *)p_ref_data, + BTM_MODE4_LEVEL4_NOT_SUPPORTED); + + return (BTM_MODE4_LEVEL4_NOT_SUPPORTED); + } + } + + p_dev_rec->p_cur_service = p_serv_rec; + p_dev_rec->security_required = security_required; + + if (btm_cb.security_mode == BTM_SEC_MODE_SP || + btm_cb.security_mode == BTM_SEC_MODE_SP_DEBUG || + btm_cb.security_mode == BTM_SEC_MODE_SC) + { + if (BTM_SEC_IS_SM4(p_dev_rec->sm4)) + { + if ((p_dev_rec->security_required & BTM_SEC_MODE4_LEVEL4) && + (p_dev_rec->link_key_type != BTM_LKEY_TYPE_AUTH_COMB_P_256)) + { + /* BTM_LKEY_TYPE_AUTH_COMB_P_256 is the only acceptable key in this case */ + if ((p_dev_rec->sec_flags & BTM_SEC_LINK_KEY_KNOWN) != 0) + { + p_dev_rec->sm4 |= BTM_SM4_UPGRADE; + } + + p_dev_rec->sec_flags &= ~(BTM_SEC_LINK_KEY_KNOWN | BTM_SEC_LINK_KEY_AUTHED | + BTM_SEC_AUTHENTICATED); + BTM_TRACE_DEBUG("%s: sec_flags:0x%x", __FUNCTION__, p_dev_rec->sec_flags); + } + else + { + /* If we already have a link key, check if that link key is good enough */ + btm_sec_check_upgrade(p_dev_rec, is_originator); + } + } + } + + p_dev_rec->is_originator = is_originator; + p_dev_rec->p_callback = p_callback; + p_dev_rec->p_ref_data = p_ref_data; + + /* Although authentication and encryption are per connection */ + /* authorization is per access request. For example when serial connection */ + /* is up and authorized and client requests to read file (access to other */ + /* scn, we need to request user's permission again. */ + p_dev_rec->sec_flags &= ~(BTM_SEC_AUTHORIZED); + + BTM_TRACE_EVENT ("%s() proto_id:%d chan_id:%d State:%d Flags:0x%x Required:0x%x Service ID:%d", + __func__, mx_proto_id, mx_chan_id, p_dev_rec->sec_state, p_dev_rec->sec_flags, + p_dev_rec->security_required, p_dev_rec->p_cur_service->service_id); + + if ((rc = btm_sec_execute_procedure (p_dev_rec)) != BTM_CMD_STARTED) + { + if (p_callback) + { + p_dev_rec->p_callback = NULL; + (*p_callback) (bd_addr,transport, p_ref_data, (UINT8)rc); + } + } + + return rc; +} + +/******************************************************************************* +** +** Function btm_sec_conn_req +** +** Description This function is when the peer device is requesting +** connection +** +** Returns void +** +*******************************************************************************/ +void btm_sec_conn_req (UINT8 *bda, UINT8 *dc) +{ + tBTM_SEC_DEV_REC *p_dev_rec = btm_find_dev (bda); + + /* Some device may request a connection before we are done with the HCI_Reset sequence */ + if (!controller_get_interface()->get_is_ready()) + { + BTM_TRACE_EVENT ("Security Manager: connect request when device not ready"); + btsnd_hcic_reject_conn (bda, HCI_ERR_HOST_REJECT_DEVICE); + return; + } + + /* Security guys wants us not to allow connection from not paired devices */ + + /* Check if connection is allowed for only paired devices */ + if (btm_cb.connect_only_paired) + { + if (!p_dev_rec || !(p_dev_rec->sec_flags & BTM_SEC_LINK_KEY_AUTHED)) + { + BTM_TRACE_EVENT ("Security Manager: connect request from non-paired device"); + btsnd_hcic_reject_conn (bda, HCI_ERR_HOST_REJECT_DEVICE); + return; + } + } + +#if BTM_ALLOW_CONN_IF_NONDISCOVER == FALSE + /* If non-discoverable, only allow known devices to connect */ + if (btm_cb.btm_inq_vars.discoverable_mode == BTM_NON_DISCOVERABLE) + { + if (!p_dev_rec) + { + BTM_TRACE_EVENT ("Security Manager: connect request from not paired device"); + btsnd_hcic_reject_conn (bda, HCI_ERR_HOST_REJECT_DEVICE); + return; + } + } +#endif + + if ((btm_cb.pairing_state != BTM_PAIR_STATE_IDLE) + &&(btm_cb.pairing_flags & BTM_PAIR_FLAGS_WE_STARTED_DD) + &&(!memcmp (btm_cb.pairing_bda, bda, BD_ADDR_LEN))) + { + BTM_TRACE_EVENT ("Security Manager: reject connect request from bonding device"); + + /* incoming connection from bonding device is rejected */ + btm_cb.pairing_flags |= BTM_PAIR_FLAGS_REJECTED_CONNECT; + btsnd_hcic_reject_conn (bda, HCI_ERR_HOST_REJECT_DEVICE); + return; + } + + /* Host is not interested or approved connection. Save BDA and DC and */ + /* pass request to L2CAP */ + memcpy (btm_cb.connecting_bda, bda, BD_ADDR_LEN); + memcpy (btm_cb.connecting_dc, dc, DEV_CLASS_LEN); + + if (l2c_link_hci_conn_req (bda)) + { + if (!p_dev_rec) + { + /* accept the connection -> allocate a device record */ + p_dev_rec = btm_sec_alloc_dev (bda); + } + if (p_dev_rec) + { + p_dev_rec->sm4 |= BTM_SM4_CONN_PEND; + } + } +} + +/******************************************************************************* +** +** Function btm_sec_bond_cancel_complete +** +** Description This function is called to report bond cancel complete +** event. +** +** Returns void +** +*******************************************************************************/ +static void btm_sec_bond_cancel_complete (void) +{ + tBTM_SEC_DEV_REC *p_dev_rec; + + if ((btm_cb.pairing_flags & BTM_PAIR_FLAGS_DISC_WHEN_DONE) || + (BTM_PAIR_STATE_WAIT_LOCAL_PIN == btm_cb.pairing_state && + BTM_PAIR_FLAGS_WE_STARTED_DD & btm_cb.pairing_flags) || + (btm_cb.pairing_state == BTM_PAIR_STATE_GET_REM_NAME && + BTM_PAIR_FLAGS_WE_CANCEL_DD & btm_cb.pairing_flags)) + { + /* for dedicated bonding in legacy mode, authentication happens at "link level" + * btm_sec_connected is called with failed status. + * In theory, the code that handles is_pairing_device/TRUE should clean out security related code. + * However, this function may clean out the security related flags and btm_sec_connected would not know + * this function also needs to do proper clean up. + */ + if ((p_dev_rec = btm_find_dev (btm_cb.pairing_bda)) != NULL) + p_dev_rec->security_required = BTM_SEC_NONE; + btm_sec_change_pairing_state (BTM_PAIR_STATE_IDLE); + + /* Notify application that the cancel succeeded */ + if (btm_cb.api.p_bond_cancel_cmpl_callback) + btm_cb.api.p_bond_cancel_cmpl_callback(BTM_SUCCESS); + } +} + +/******************************************************************************* +** +** Function btm_create_conn_cancel_complete +** +** Description This function is called when the command complete message +** is received from the HCI for the create connection cancel +** command. +** +** Returns void +** +*******************************************************************************/ +void btm_create_conn_cancel_complete (UINT8 *p) +{ + UINT8 status; + + STREAM_TO_UINT8 (status, p); + BTM_TRACE_EVENT ("btm_create_conn_cancel_complete(): in State: %s status:%d", + btm_pair_state_descr(btm_cb.pairing_state), status); + + /* if the create conn cancel cmd was issued by the bond cancel, + ** the application needs to be notified that bond cancel succeeded + */ + switch (status) + { + case HCI_SUCCESS: + btm_sec_bond_cancel_complete(); + break; + case HCI_ERR_CONNECTION_EXISTS: + case HCI_ERR_NO_CONNECTION: + default: + /* Notify application of the error */ + if (btm_cb.api.p_bond_cancel_cmpl_callback) + btm_cb.api.p_bond_cancel_cmpl_callback(BTM_ERR_PROCESSING); + break; + } +} + +/******************************************************************************* +** +** Function btm_sec_check_pending_reqs +** +** Description This function is called at the end of the security procedure +** to let L2CAP and RFCOMM know to re-submit any pending requests +** +** Returns void +** +*******************************************************************************/ +void btm_sec_check_pending_reqs (void) +{ + tBTM_SEC_QUEUE_ENTRY *p_e; + BUFFER_Q bq; + + if (btm_cb.pairing_state == BTM_PAIR_STATE_IDLE) + { + /* First, resubmit L2CAP requests */ + if (btm_cb.sec_req_pending) + { + btm_cb.sec_req_pending = FALSE; + l2cu_resubmit_pending_sec_req (NULL); + } + + /* Now, re-submit anything in the mux queue */ + bq = btm_cb.sec_pending_q; + + GKI_init_q (&btm_cb.sec_pending_q); + + while ((p_e = (tBTM_SEC_QUEUE_ENTRY *)GKI_dequeue (&bq)) != NULL) + { + /* Check that the ACL is still up before starting security procedures */ + if (btm_bda_to_acl(p_e->bd_addr, p_e->transport) != NULL) + { + if (p_e->psm != 0) + { + BTM_TRACE_EVENT("%s PSM:0x%04x Is_Orig:%u mx_proto_id:%u mx_chan_id:%u", + __FUNCTION__, p_e->psm, p_e->is_orig, + p_e->mx_proto_id, p_e->mx_chan_id); + + btm_sec_mx_access_request (p_e->bd_addr, p_e->psm, p_e->is_orig, + p_e->mx_proto_id, p_e->mx_chan_id, + p_e->p_callback, p_e->p_ref_data); + } + else + { + BTM_SetEncryption(p_e->bd_addr, p_e->transport, p_e->p_callback, + p_e->p_ref_data); + } + } + + GKI_freebuf (p_e); + } + } +} + +/******************************************************************************* +** +** Function btm_sec_init +** +** Description This function is on the SEC startup +** +** Returns void +** +*******************************************************************************/ +void btm_sec_init (UINT8 sec_mode) +{ + btm_cb.security_mode = sec_mode; + memset (btm_cb.pairing_bda, 0xff, BD_ADDR_LEN); + btm_cb.max_collision_delay = BTM_SEC_MAX_COLLISION_DELAY; +} + +/******************************************************************************* +** +** Function btm_sec_device_down +** +** Description This function should be called when device is disabled or +** turned off +** +** Returns void +** +*******************************************************************************/ +void btm_sec_device_down (void) +{ + BTM_TRACE_EVENT ("%s() State: %s", __func__, btm_pair_state_descr(btm_cb.pairing_state)); + btm_sec_change_pairing_state (BTM_PAIR_STATE_IDLE); +} + +/******************************************************************************* +** +** Function btm_sec_dev_reset +** +** Description This function should be called after device reset +** +** Returns void +** +*******************************************************************************/ +void btm_sec_dev_reset (void) +{ + if (controller_get_interface()->supports_simple_pairing()) + { + /* set the default IO capabilities */ + btm_cb.devcb.loc_io_caps = BTM_LOCAL_IO_CAPS; + /* add mx service to use no security */ + BTM_SetSecurityLevel(FALSE, "RFC_MUX", BTM_SEC_SERVICE_RFC_MUX, + BTM_SEC_NONE, BT_PSM_RFCOMM, BTM_SEC_PROTO_RFCOMM, 0); + } + else + { + btm_cb.security_mode = BTM_SEC_MODE_SERVICE; + } + + BTM_TRACE_DEBUG ("btm_sec_dev_reset sec mode: %d", btm_cb.security_mode); +} + +/******************************************************************************* +** +** Function btm_sec_abort_access_req +** +** Description This function is called by the L2CAP or RFCOMM to abort +** the pending operation. +** +** Parameters: bd_addr - Address of the peer device +** +** Returns void +** +*******************************************************************************/ +void btm_sec_abort_access_req (BD_ADDR bd_addr) +{ + tBTM_SEC_DEV_REC *p_dev_rec = btm_find_dev (bd_addr); + + if (!p_dev_rec) + return; + + if ((p_dev_rec->sec_state != BTM_SEC_STATE_AUTHORIZING) + && (p_dev_rec->sec_state != BTM_SEC_STATE_AUTHENTICATING)) + return; + + p_dev_rec->sec_state = BTM_SEC_STATE_IDLE; + p_dev_rec->p_callback = NULL; +} + +/******************************************************************************* +** +** Function btm_sec_dd_create_conn +** +** Description This function is called to create the ACL connection for +** the dedicated boding process +** +** Returns void +** +*******************************************************************************/ +static tBTM_STATUS btm_sec_dd_create_conn (tBTM_SEC_DEV_REC *p_dev_rec) +{ + tL2C_LCB *p_lcb = l2cu_find_lcb_by_bd_addr(p_dev_rec->bd_addr, BT_TRANSPORT_BR_EDR); + if (p_lcb && (p_lcb->link_state == LST_CONNECTED || p_lcb->link_state == LST_CONNECTING)) + { + BTM_TRACE_WARNING("%s Connection already exists", __func__); + return BTM_CMD_STARTED; + } + + /* Make sure an L2cap link control block is available */ + if (!p_lcb && (p_lcb = l2cu_allocate_lcb (p_dev_rec->bd_addr, TRUE, BT_TRANSPORT_BR_EDR)) == NULL) + { + BTM_TRACE_WARNING ("Security Manager: failed allocate LCB [%02x%02x%02x%02x%02x%02x]", + p_dev_rec->bd_addr[0], p_dev_rec->bd_addr[1], p_dev_rec->bd_addr[2], + p_dev_rec->bd_addr[3], p_dev_rec->bd_addr[4], p_dev_rec->bd_addr[5]); + + return(BTM_NO_RESOURCES); + } + + /* set up the control block to indicated dedicated bonding */ + btm_cb.pairing_flags |= BTM_PAIR_FLAGS_DISC_WHEN_DONE; + + if (l2cu_create_conn(p_lcb, BT_TRANSPORT_BR_EDR) == FALSE) + { + BTM_TRACE_WARNING ("Security Manager: failed create [%02x%02x%02x%02x%02x%02x]", + p_dev_rec->bd_addr[0], p_dev_rec->bd_addr[1], p_dev_rec->bd_addr[2], + p_dev_rec->bd_addr[3], p_dev_rec->bd_addr[4], p_dev_rec->bd_addr[5]); + + l2cu_release_lcb(p_lcb); + return(BTM_NO_RESOURCES); + } + + btm_acl_update_busy_level (BTM_BLI_PAGE_EVT); + + BTM_TRACE_DEBUG ("Security Manager: btm_sec_dd_create_conn [%02x%02x%02x%02x%02x%02x]", + p_dev_rec->bd_addr[0], p_dev_rec->bd_addr[1], p_dev_rec->bd_addr[2], + p_dev_rec->bd_addr[3], p_dev_rec->bd_addr[4], p_dev_rec->bd_addr[5]); + + btm_sec_change_pairing_state (BTM_PAIR_STATE_WAIT_PIN_REQ); + + return(BTM_CMD_STARTED); +} + +/******************************************************************************* +** +** Function btm_sec_rmt_name_request_complete +** +** Description This function is called when remote name was obtained from +** the peer device +** +** Returns void +** +*******************************************************************************/ +void btm_sec_rmt_name_request_complete (UINT8 *p_bd_addr, UINT8 *p_bd_name, UINT8 status) +{ + tBTM_SEC_DEV_REC *p_dev_rec; + int i; + DEV_CLASS dev_class; + UINT8 old_sec_state; + + BTM_TRACE_EVENT ("btm_sec_rmt_name_request_complete"); + if (((p_bd_addr == NULL) && !BTM_ACL_IS_CONNECTED(btm_cb.connecting_bda)) + || ((p_bd_addr != NULL) && !BTM_ACL_IS_CONNECTED(p_bd_addr))) + { + btm_acl_resubmit_page(); + } + + /* If remote name request failed, p_bd_addr is null and we need to search */ + /* based on state assuming that we are doing 1 at a time */ + if (p_bd_addr) + p_dev_rec = btm_find_dev (p_bd_addr); + else + { + p_dev_rec = &btm_cb.sec_dev_rec[0]; + + for (i = 0; i < BTM_SEC_MAX_DEVICE_RECORDS; i++, p_dev_rec++) + { + if ((p_dev_rec->sec_flags & BTM_SEC_IN_USE) + && (p_dev_rec->sec_state == BTM_SEC_STATE_GETTING_NAME)) + { + p_bd_addr = p_dev_rec->bd_addr; + break; + } + } + + if (i == BTM_SEC_MAX_DEVICE_RECORDS) + p_dev_rec = NULL; + } + + + /* Commenting out trace due to obf/compilation problems. + */ +#if (BT_USE_TRACES == TRUE) + if (!p_bd_name) + p_bd_name = (UINT8 *)""; + + if (p_dev_rec) + { + BTM_TRACE_EVENT ("Security Manager: rmt_name_complete PairState: %s RemName: %s status: %d State:%d p_dev_rec: 0x%08x ", + btm_pair_state_descr (btm_cb.pairing_state), p_bd_name, + status, p_dev_rec->sec_state, p_dev_rec); + } + else + { + BTM_TRACE_EVENT ("Security Manager: rmt_name_complete PairState: %s RemName: %s status: %d", + btm_pair_state_descr (btm_cb.pairing_state), p_bd_name, + status); + } +#endif + + if (p_dev_rec) + { + old_sec_state = p_dev_rec->sec_state; + if (status == HCI_SUCCESS) + { + BCM_STRNCPY_S ((char *)p_dev_rec->sec_bd_name, sizeof (p_dev_rec->sec_bd_name), (char *)p_bd_name, BTM_MAX_REM_BD_NAME_LEN); + p_dev_rec->sec_flags |= BTM_SEC_NAME_KNOWN; + BTM_TRACE_EVENT ("setting BTM_SEC_NAME_KNOWN sec_flags:0x%x", p_dev_rec->sec_flags); + } + else + { + /* Notify all clients waiting for name to be resolved even if it failed so clients can continue */ + p_dev_rec->sec_bd_name[0] = 0; + } + + if (p_dev_rec->sec_state == BTM_SEC_STATE_GETTING_NAME) + p_dev_rec->sec_state = BTM_SEC_STATE_IDLE; + + /* Notify all clients waiting for name to be resolved */ + for (i = 0;i < BTM_SEC_MAX_RMT_NAME_CALLBACKS; i++) + { + if (btm_cb.p_rmt_name_callback[i] && p_bd_addr) + (*btm_cb.p_rmt_name_callback[i])(p_bd_addr, p_dev_rec->dev_class, + p_dev_rec->sec_bd_name); + } + } + else + { + dev_class[0] = 0; + dev_class[1] = 0; + dev_class[2] = 0; + + /* Notify all clients waiting for name to be resolved even if not found so clients can continue */ + for (i = 0;i < BTM_SEC_MAX_RMT_NAME_CALLBACKS; i++) + { + if (btm_cb.p_rmt_name_callback[i] && p_bd_addr) + (*btm_cb.p_rmt_name_callback[i])(p_bd_addr, dev_class, (UINT8 *)""); + } + + return; + } + + /* If we were delaying asking UI for a PIN because name was not resolved, ask now */ + if ( (btm_cb.pairing_state == BTM_PAIR_STATE_WAIT_LOCAL_PIN) && p_bd_addr + && (memcmp (btm_cb.pairing_bda, p_bd_addr, BD_ADDR_LEN) == 0) ) + { + BTM_TRACE_EVENT ("btm_sec_rmt_name_request_complete() delayed pin now being requested flags:0x%x, (p_pin_callback=0x%p)", btm_cb.pairing_flags, btm_cb.api.p_pin_callback); + + if (((btm_cb.pairing_flags & BTM_PAIR_FLAGS_WE_STARTED_DD) == 0) && + ((btm_cb.pairing_flags & BTM_PAIR_FLAGS_PIN_REQD) == 0) && + btm_cb.api.p_pin_callback) + { + BTM_TRACE_EVENT ("btm_sec_rmt_name_request_complete() calling pin_callback"); + btm_cb.pairing_flags |= BTM_PAIR_FLAGS_PIN_REQD; + (*btm_cb.api.p_pin_callback) (p_dev_rec->bd_addr, p_dev_rec->dev_class, p_bd_name, + (p_dev_rec->p_cur_service==NULL) ? FALSE + : (p_dev_rec->p_cur_service->security_flags & BTM_SEC_IN_MIN_16_DIGIT_PIN)); + } + + /* Set the same state again to force the timer to be restarted */ + btm_sec_change_pairing_state (BTM_PAIR_STATE_WAIT_LOCAL_PIN); + return; + } + + /* Check if we were delaying bonding because name was not resolved */ + if ( btm_cb.pairing_state == BTM_PAIR_STATE_GET_REM_NAME) + { + if (p_bd_addr && memcmp (btm_cb.pairing_bda, p_bd_addr, BD_ADDR_LEN) == 0) + { + BTM_TRACE_EVENT ("btm_sec_rmt_name_request_complete() continue bonding sm4: 0x%04x, status:0x%x", p_dev_rec->sm4, status); + if(btm_cb.pairing_flags & BTM_PAIR_FLAGS_WE_CANCEL_DD) + { + btm_sec_bond_cancel_complete(); + return; + } + + if (status != HCI_SUCCESS) + { + btm_sec_change_pairing_state (BTM_PAIR_STATE_IDLE); + + if (btm_cb.api.p_auth_complete_callback) + (*btm_cb.api.p_auth_complete_callback) (p_dev_rec->bd_addr, p_dev_rec->dev_class, + p_dev_rec->sec_bd_name, status); + return; + } + + /* if peer is very old legacy devices, HCI_RMT_HOST_SUP_FEAT_NOTIFY_EVT is not reported */ + if (BTM_SEC_IS_SM4_UNKNOWN(p_dev_rec->sm4)) + { + /* set the KNOWN flag only if BTM_PAIR_FLAGS_REJECTED_CONNECT is not set.*/ + /* If it is set, there may be a race condition */ + BTM_TRACE_DEBUG ("btm_sec_rmt_name_request_complete IS_SM4_UNKNOWN Flags:0x%04x", + btm_cb.pairing_flags); + if ((btm_cb.pairing_flags & BTM_PAIR_FLAGS_REJECTED_CONNECT) == 0) + { + p_dev_rec->sm4 |= BTM_SM4_KNOWN; + } + } + + BTM_TRACE_DEBUG("%s, SM4 Value: %x, Legacy:%d,IS SM4:%d, Unknown:%d",__FUNCTION__, + p_dev_rec->sm4, BTM_SEC_IS_SM4_LEGACY(p_dev_rec->sm4), + BTM_SEC_IS_SM4(p_dev_rec->sm4),BTM_SEC_IS_SM4_UNKNOWN(p_dev_rec->sm4)); + + /* BT 2.1 or carkit, bring up the connection to force the peer to request PIN. + ** Else prefetch (btm_sec_check_prefetch_pin will do the prefetching if needed) + */ + if ((p_dev_rec->sm4 != BTM_SM4_KNOWN) || !btm_sec_check_prefetch_pin(p_dev_rec)) + { + /* if we rejected incoming connection request, we have to wait HCI_Connection_Complete event */ + /* before originating */ + if (btm_cb.pairing_flags & BTM_PAIR_FLAGS_REJECTED_CONNECT) + { + BTM_TRACE_WARNING ("btm_sec_rmt_name_request_complete: waiting HCI_Connection_Complete after rejecting connection"); + } + /* Both we and the peer are 2.1 - continue to create connection */ + else if (btm_sec_dd_create_conn(p_dev_rec) != BTM_CMD_STARTED) + { + BTM_TRACE_WARNING ("btm_sec_rmt_name_request_complete: failed to start connection"); + + btm_sec_change_pairing_state (BTM_PAIR_STATE_IDLE); + + if (btm_cb.api.p_auth_complete_callback) + (*btm_cb.api.p_auth_complete_callback) (p_dev_rec->bd_addr, p_dev_rec->dev_class, + p_dev_rec->sec_bd_name, HCI_ERR_MEMORY_FULL); + } + } + return; + } + else + { + BTM_TRACE_WARNING ("btm_sec_rmt_name_request_complete: wrong BDA, retry with pairing BDA"); + + BTM_ReadRemoteDeviceName (btm_cb.pairing_bda, NULL, BT_TRANSPORT_BR_EDR); + return; + } + } + + /* check if we were delaying link_key_callback because name was not resolved */ + if (p_dev_rec->link_key_not_sent) + { + /* If HCI connection complete has not arrived, wait for it */ + if (p_dev_rec->hci_handle == BTM_SEC_INVALID_HANDLE) + return; + + p_dev_rec->link_key_not_sent = FALSE; + btm_send_link_key_notif(p_dev_rec); + + /* If its not us who perform authentication, we should tell stackserver */ + /* that some authentication has been completed */ + /* This is required when different entities receive link notification and auth complete */ + if (!(p_dev_rec->security_required & BTM_SEC_OUT_AUTHENTICATE)) + { + if (btm_cb.api.p_auth_complete_callback) + (*btm_cb.api.p_auth_complete_callback) (p_dev_rec->bd_addr, + p_dev_rec->dev_class, + p_dev_rec->sec_bd_name, HCI_SUCCESS); + + } + } + + /* If this is a bonding procedure can disconnect the link now */ + if ((btm_cb.pairing_flags & BTM_PAIR_FLAGS_WE_STARTED_DD) + && (p_dev_rec->sec_flags & BTM_SEC_AUTHENTICATED)) + { + BTM_TRACE_WARNING ("btm_sec_rmt_name_request_complete (none/ce)"); + p_dev_rec->security_required &= ~(BTM_SEC_OUT_AUTHENTICATE); + l2cu_start_post_bond_timer(p_dev_rec->hci_handle); + return; + } + + if (old_sec_state != BTM_SEC_STATE_GETTING_NAME) + return; + + /* If get name failed, notify the waiting layer */ + if (status != HCI_SUCCESS) + { + btm_sec_dev_rec_cback_event (p_dev_rec, BTM_ERR_PROCESSING, FALSE); + return; + } + + if (p_dev_rec->sm4 & BTM_SM4_REQ_PEND) + { + BTM_TRACE_EVENT ("waiting for remote features!!"); + return; + } + + /* Remote Name succeeded, execute the next security procedure, if any */ + status = (UINT8)btm_sec_execute_procedure (p_dev_rec); + + /* If result is pending reply from the user or from the device is pending */ + if (status == BTM_CMD_STARTED) + return; + + /* There is no next procedure or start of procedure failed, notify the waiting layer */ + btm_sec_dev_rec_cback_event (p_dev_rec, status, FALSE); +} + +/******************************************************************************* +** +** Function btm_sec_rmt_host_support_feat_evt +** +** Description This function is called when the +** HCI_RMT_HOST_SUP_FEAT_NOTIFY_EVT is received +** +** Returns void +** +*******************************************************************************/ +void btm_sec_rmt_host_support_feat_evt (UINT8 *p) +{ + tBTM_SEC_DEV_REC *p_dev_rec; + BD_ADDR bd_addr; /* peer address */ + BD_FEATURES features; + + STREAM_TO_BDADDR (bd_addr, p); + p_dev_rec = btm_find_or_alloc_dev (bd_addr); + + BTM_TRACE_EVENT ("btm_sec_rmt_host_support_feat_evt sm4: 0x%x p[0]: 0x%x", p_dev_rec->sm4, p[0]); + + if (BTM_SEC_IS_SM4_UNKNOWN(p_dev_rec->sm4)) + { + p_dev_rec->sm4 = BTM_SM4_KNOWN; + STREAM_TO_ARRAY(features, p, HCI_FEATURE_BYTES_PER_PAGE); + if (HCI_SSP_HOST_SUPPORTED(features)) + { + p_dev_rec->sm4 = BTM_SM4_TRUE; + } + BTM_TRACE_EVENT ("btm_sec_rmt_host_support_feat_evt sm4: 0x%x features[0]: 0x%x", p_dev_rec->sm4, features[0]); + } +} + +/******************************************************************************* +** +** Function btm_io_capabilities_req +** +** Description This function is called when LM request for the IO +** capability of the local device and +** if the OOB data is present for the device in the event +** +** Returns void +** +*******************************************************************************/ +void btm_io_capabilities_req (UINT8 *p) +{ + tBTM_SP_IO_REQ evt_data; + UINT8 err_code = 0; + tBTM_SEC_DEV_REC *p_dev_rec; + BOOLEAN is_orig = TRUE; + UINT8 callback_rc = BTM_SUCCESS; + + STREAM_TO_BDADDR (evt_data.bd_addr, p); + + /* setup the default response according to compile options */ + /* assume that the local IO capability does not change + * loc_io_caps is initialized with the default value */ + evt_data.io_cap = btm_cb.devcb.loc_io_caps; + evt_data.oob_data = BTM_OOB_NONE; + evt_data.auth_req = BTM_DEFAULT_AUTH_REQ; + + BTM_TRACE_EVENT("%s: State: %s", __FUNCTION__, btm_pair_state_descr(btm_cb.pairing_state)); + + p_dev_rec = btm_find_or_alloc_dev (evt_data.bd_addr); + + BTM_TRACE_DEBUG("%s:Security mode: %d, Num Read Remote Feat pages: %d", __FUNCTION__, + btm_cb.security_mode, p_dev_rec->num_read_pages); + + if ((btm_cb.security_mode == BTM_SEC_MODE_SC) && (p_dev_rec->num_read_pages == 0)) + { + BTM_TRACE_EVENT("%s: Device security mode is SC only.", + "To continue need to know remote features.", __FUNCTION__); + + p_dev_rec->remote_features_needed = TRUE; + return; + } + + p_dev_rec->sm4 |= BTM_SM4_TRUE; + + BTM_TRACE_EVENT("%s: State: %s Flags: 0x%04x p_cur_service: 0x%08x", + __FUNCTION__, btm_pair_state_descr(btm_cb.pairing_state), + btm_cb.pairing_flags, p_dev_rec->p_cur_service); + + if (p_dev_rec->p_cur_service) + { + BTM_TRACE_EVENT("%s: cur_service psm: 0x%04x, security_flags: 0x%04x", + __FUNCTION__, p_dev_rec->p_cur_service->psm, + p_dev_rec->p_cur_service->security_flags); + } + + switch (btm_cb.pairing_state) + { + /* initiator connecting */ + case BTM_PAIR_STATE_IDLE: + //TODO: Handle Idle pairing state + //security_required = p_dev_rec->security_required; + break; + + /* received IO capability response already->acceptor */ + case BTM_PAIR_STATE_INCOMING_SSP: + is_orig = FALSE; + + if (btm_cb.pairing_flags & BTM_PAIR_FLAGS_PEER_STARTED_DD) + { + /* acceptor in dedicated bonding */ + evt_data.auth_req = BTM_DEFAULT_DD_AUTH_REQ; + } + break; + + /* initiator, at this point it is expected to be dedicated bonding + initiated by local device */ + case BTM_PAIR_STATE_WAIT_PIN_REQ: + if (!memcmp (evt_data.bd_addr, btm_cb.pairing_bda, BD_ADDR_LEN)) + { + evt_data.auth_req = BTM_DEFAULT_DD_AUTH_REQ; + } + else + { + err_code = HCI_ERR_HOST_BUSY_PAIRING; + } + break; + + /* any other state is unexpected */ + default: + err_code = HCI_ERR_HOST_BUSY_PAIRING; + BTM_TRACE_ERROR("%s: Unexpected Pairing state received %d", __FUNCTION__, + btm_cb.pairing_state); + break; + } + + if (btm_cb.pairing_disabled) + { + /* pairing is not allowed */ + BTM_TRACE_DEBUG("%s: Pairing is not allowed -> fail pairing.", __FUNCTION__); + err_code = HCI_ERR_PAIRING_NOT_ALLOWED; + } + else if (btm_cb.security_mode == BTM_SEC_MODE_SC) + { + BOOLEAN local_supports_sc = controller_get_interface()->supports_secure_connections(); + /* device in Secure Connections Only mode */ + if (!(local_supports_sc) || !(p_dev_rec->remote_supports_secure_connections)) + { + BTM_TRACE_DEBUG("%s: SC only service, local_support_for_sc %d,", + " remote_support_for_sc 0x%02x -> fail pairing", __FUNCTION__, + local_supports_sc, p_dev_rec->remote_supports_secure_connections); + + err_code = HCI_ERR_PAIRING_NOT_ALLOWED; + } + } + + if (err_code != 0) + { +/* coverity[uninit_use_in_call] +Event uninit_use_in_call: Using uninitialized element of array "evt_data.bd_addr" in call to function "memcmp" +False-positive: evt_data.bd_addr is set at the beginning with: STREAM_TO_BDADDR (evt_data.bd_addr, p); +*/ + btsnd_hcic_io_cap_req_neg_reply(evt_data.bd_addr, err_code); + return; + } + + evt_data.is_orig = is_orig; + + if (is_orig) + { + /* local device initiated the pairing non-bonding -> use p_cur_service */ + if (!(btm_cb.pairing_flags & BTM_PAIR_FLAGS_WE_STARTED_DD) && + p_dev_rec->p_cur_service && + (p_dev_rec->p_cur_service->security_flags & BTM_SEC_OUT_AUTHENTICATE)) + { + if (btm_cb.security_mode == BTM_SEC_MODE_SC) + { + /* SC only mode device requires MITM protection */ + evt_data.auth_req = BTM_AUTH_SP_YES; + } + else + { + evt_data.auth_req = (p_dev_rec->p_cur_service->security_flags & + BTM_SEC_OUT_MITM)? BTM_AUTH_SP_YES : BTM_AUTH_SP_NO; + } + } + } + + /* Notify L2CAP to increase timeout */ + l2c_pin_code_request (evt_data.bd_addr); + + memcpy (btm_cb.pairing_bda, evt_data.bd_addr, BD_ADDR_LEN); + +/* coverity[uninit_use_in_call] +Event uninit_use_in_call: Using uninitialized element of array "evt_data.bd_addr" in call to function "memcmp" +False-positive: False-positive: evt_data.bd_addr is set at the beginning with: STREAM_TO_BDADDR (evt_data.bd_addr, p); +*/ + if (!memcmp (evt_data.bd_addr, btm_cb.connecting_bda, BD_ADDR_LEN)) + memcpy (p_dev_rec->dev_class, btm_cb.connecting_dc, DEV_CLASS_LEN); + + btm_sec_change_pairing_state (BTM_PAIR_STATE_WAIT_LOCAL_IOCAPS); + + callback_rc = BTM_SUCCESS; + if (p_dev_rec->sm4 & BTM_SM4_UPGRADE) + { + p_dev_rec->sm4 &= ~BTM_SM4_UPGRADE; + + /* link key upgrade: always use SPGB_YES - assuming we want to save the link key */ + evt_data.auth_req = BTM_AUTH_SPGB_YES; + } + else if (btm_cb.api.p_sp_callback) + { + /* the callback function implementation may change the IO capability... */ + callback_rc = (*btm_cb.api.p_sp_callback) (BTM_SP_IO_REQ_EVT, (tBTM_SP_EVT_DATA *)&evt_data); + } + +#if BTM_OOB_INCLUDED == TRUE + if ((callback_rc == BTM_SUCCESS) || (BTM_OOB_UNKNOWN != evt_data.oob_data)) +#else + if (callback_rc == BTM_SUCCESS) +#endif + { + if ((btm_cb.pairing_flags & BTM_PAIR_FLAGS_WE_STARTED_DD)) + { + evt_data.auth_req = (BTM_AUTH_DD_BOND | (evt_data.auth_req & BTM_AUTH_YN_BIT)); + } + + if (btm_cb.security_mode == BTM_SEC_MODE_SC) + { + /* At this moment we know that both sides are SC capable, device in */ + /* SC only mode requires MITM for any service so let's set MITM bit */ + evt_data.auth_req |= BTM_AUTH_YN_BIT; + BTM_TRACE_DEBUG("%s: for device in \"SC only\" mode set auth_req to 0x%02x", + __FUNCTION__, evt_data.auth_req); + } + + /* if the user does not indicate "reply later" by setting the oob_data to unknown */ + /* send the response right now. Save the current IO capability in the control block */ + btm_cb.devcb.loc_auth_req = evt_data.auth_req; + btm_cb.devcb.loc_io_caps = evt_data.io_cap; + + BTM_TRACE_EVENT("%s: State: %s IO_CAP:%d oob_data:%d auth_req:%d", + __FUNCTION__, btm_pair_state_descr(btm_cb.pairing_state), evt_data.io_cap, + evt_data.oob_data, evt_data.auth_req); + + btsnd_hcic_io_cap_req_reply(evt_data.bd_addr, evt_data.io_cap, + evt_data.oob_data, evt_data.auth_req); + } +} + +/******************************************************************************* +** +** Function btm_io_capabilities_rsp +** +** Description This function is called when the IO capability of the +** specified device is received +** +** Returns void +** +*******************************************************************************/ +void btm_io_capabilities_rsp (UINT8 *p) +{ + tBTM_SEC_DEV_REC *p_dev_rec; + tBTM_SP_IO_RSP evt_data; + + STREAM_TO_BDADDR (evt_data.bd_addr, p); + STREAM_TO_UINT8 (evt_data.io_cap, p); + STREAM_TO_UINT8 (evt_data.oob_data, p); + STREAM_TO_UINT8 (evt_data.auth_req, p); + + /* Allocate a new device record or reuse the oldest one */ + p_dev_rec = btm_find_or_alloc_dev (evt_data.bd_addr); + + /* If no security is in progress, this indicates incoming security */ + if (btm_cb.pairing_state == BTM_PAIR_STATE_IDLE) + { + memcpy (btm_cb.pairing_bda, evt_data.bd_addr, BD_ADDR_LEN); + + btm_sec_change_pairing_state (BTM_PAIR_STATE_INCOMING_SSP); + + /* Make sure we reset the trusted mask to help against attacks */ + BTM_SEC_CLR_TRUSTED_DEVICE(p_dev_rec->trusted_mask); + + /* work around for FW bug */ + btm_inq_stop_on_ssp(); + } + + /* Notify L2CAP to increase timeout */ + l2c_pin_code_request (evt_data.bd_addr); + + /* We must have a device record here. + * Use the connecting device's CoD for the connection */ +/* coverity[uninit_use_in_call] +Event uninit_use_in_call: Using uninitialized element of array "evt_data.bd_addr" in call to function "memcmp" +FALSE-POSITIVE error from Coverity test-tool. evt_data.bd_addr is set at the beginning with: STREAM_TO_BDADDR (evt_data.bd_addr, p); +*/ + if (!memcmp (evt_data.bd_addr, btm_cb.connecting_bda, BD_ADDR_LEN)) + memcpy (p_dev_rec->dev_class, btm_cb.connecting_dc, DEV_CLASS_LEN); + + /* peer sets dedicated bonding bit and we did not initiate dedicated bonding */ + if (btm_cb.pairing_state == BTM_PAIR_STATE_INCOMING_SSP /* peer initiated bonding */ + && (evt_data.auth_req & BTM_AUTH_DD_BOND) ) /* and dedicated bonding bit is set */ + { + btm_cb.pairing_flags |= BTM_PAIR_FLAGS_PEER_STARTED_DD; + } + + /* save the IO capability in the device record */ + p_dev_rec->rmt_io_caps = evt_data.io_cap; + p_dev_rec->rmt_auth_req = evt_data.auth_req; + + if (btm_cb.api.p_sp_callback) + (*btm_cb.api.p_sp_callback) (BTM_SP_IO_RSP_EVT, (tBTM_SP_EVT_DATA *)&evt_data); +} + +/******************************************************************************* +** +** Function btm_proc_sp_req_evt +** +** Description This function is called to process/report +** HCI_USER_CONFIRMATION_REQUEST_EVT +** or HCI_USER_PASSKEY_REQUEST_EVT +** or HCI_USER_PASSKEY_NOTIFY_EVT +** +** Returns void +** +*******************************************************************************/ +void btm_proc_sp_req_evt (tBTM_SP_EVT event, UINT8 *p) +{ + tBTM_STATUS status = BTM_ERR_PROCESSING; + tBTM_SP_EVT_DATA evt_data; + UINT8 *p_bda = evt_data.cfm_req.bd_addr; + tBTM_SEC_DEV_REC *p_dev_rec; + + /* All events start with bd_addr */ + STREAM_TO_BDADDR (p_bda, p); + + BTM_TRACE_EVENT ("btm_proc_sp_req_evt() BDA: %08x%04x event: 0x%x, State: %s", + (p_bda[0]<<24) + (p_bda[1]<<16) + (p_bda[2]<<8) + p_bda[3], (p_bda[4] << 8) + p_bda[5], + event, btm_pair_state_descr(btm_cb.pairing_state)); + + if ( ((p_dev_rec = btm_find_dev (p_bda)) != NULL) + && (btm_cb.pairing_state != BTM_PAIR_STATE_IDLE) + && (memcmp (btm_cb.pairing_bda, p_bda, BD_ADDR_LEN) == 0) ) + { + memcpy (evt_data.cfm_req.bd_addr, p_dev_rec->bd_addr, BD_ADDR_LEN); + memcpy (evt_data.cfm_req.dev_class, p_dev_rec->dev_class, DEV_CLASS_LEN); + + BCM_STRNCPY_S ((char *)evt_data.cfm_req.bd_name, sizeof(evt_data.cfm_req.bd_name), (char *)p_dev_rec->sec_bd_name, BTM_MAX_REM_BD_NAME_LEN); + + switch (event) + { + case BTM_SP_CFM_REQ_EVT: + /* Numeric confirmation. Need user to conf the passkey */ + btm_sec_change_pairing_state (BTM_PAIR_STATE_WAIT_NUMERIC_CONFIRM); + + /* The device record must be allocated in the "IO cap exchange" step */ + STREAM_TO_UINT32 (evt_data.cfm_req.num_val, p); + + evt_data.cfm_req.just_works = TRUE; + + /* process user confirm req in association with the auth_req param */ +#if (BTM_LOCAL_IO_CAPS == BTM_IO_CAP_IO) + if ( (p_dev_rec->rmt_io_caps == BTM_IO_CAP_IO) + && (btm_cb.devcb.loc_io_caps == BTM_IO_CAP_IO) + && ((p_dev_rec->rmt_auth_req & BTM_AUTH_SP_YES) || (btm_cb.devcb.loc_auth_req & BTM_AUTH_SP_YES)) ) + { + /* Both devices are DisplayYesNo and one or both devices want to authenticate + -> use authenticated link key */ + evt_data.cfm_req.just_works = FALSE; + } +#endif + BTM_TRACE_DEBUG ("btm_proc_sp_req_evt() just_works:%d, io loc:%d, rmt:%d, auth loc:%d, rmt:%d", + evt_data.cfm_req.just_works, btm_cb.devcb.loc_io_caps, p_dev_rec->rmt_io_caps, + btm_cb.devcb.loc_auth_req, p_dev_rec->rmt_auth_req); + + evt_data.cfm_req.loc_auth_req = btm_cb.devcb.loc_auth_req; + evt_data.cfm_req.rmt_auth_req = p_dev_rec->rmt_auth_req; + evt_data.cfm_req.loc_io_caps = btm_cb.devcb.loc_io_caps; + evt_data.cfm_req.rmt_io_caps = p_dev_rec->rmt_io_caps; + break; + + case BTM_SP_KEY_NOTIF_EVT: + /* Passkey notification (other side is a keyboard) */ + STREAM_TO_UINT32 (evt_data.key_notif.passkey, p); + + BTM_TRACE_DEBUG ("BTM_SP_KEY_NOTIF_EVT: passkey: %u", evt_data.key_notif.passkey); + + btm_sec_change_pairing_state (BTM_PAIR_STATE_WAIT_AUTH_COMPLETE); + break; + +#if (BTM_LOCAL_IO_CAPS != BTM_IO_CAP_NONE) + case BTM_SP_KEY_REQ_EVT: + /* HCI_USER_PASSKEY_REQUEST_EVT */ + btm_sec_change_pairing_state (BTM_PAIR_STATE_KEY_ENTRY); + break; +#endif + } + + if (btm_cb.api.p_sp_callback) + { + status = (*btm_cb.api.p_sp_callback) (event, (tBTM_SP_EVT_DATA *)&evt_data); + if (status != BTM_NOT_AUTHORIZED) + { + return; + } + /* else BTM_NOT_AUTHORIZED means when the app wants to reject the req right now */ + } + else if ( (event == BTM_SP_CFM_REQ_EVT) && (evt_data.cfm_req.just_works == TRUE) ) + { + /* automatically reply with just works if no sp_cback */ + status = BTM_SUCCESS; + } + + if (event == BTM_SP_CFM_REQ_EVT) + { + BTM_TRACE_DEBUG ("calling BTM_ConfirmReqReply with status: %d", status); + BTM_ConfirmReqReply (status, p_bda); + } +#if (BTM_LOCAL_IO_CAPS != BTM_IO_CAP_NONE) + else if (event == BTM_SP_KEY_REQ_EVT) + { + BTM_PasskeyReqReply(status, p_bda, 0); + } +#endif + return; + } + + /* Something bad. we can only fail this connection */ + btm_cb.acl_disc_reason = HCI_ERR_HOST_REJECT_SECURITY; + + if (BTM_SP_CFM_REQ_EVT == event) + { + btsnd_hcic_user_conf_reply (p_bda, FALSE); + } + else if (BTM_SP_KEY_NOTIF_EVT == event) + { + /* do nothing -> it very unlikely to happen. + This event is most likely to be received by a HID host when it first connects to a HID device. + Usually the Host initiated the connection in this case. + On Mobile platforms, if there's a security process happening, + the host probably can not initiate another connection. + BTW (PC) is another story. */ + if (NULL != (p_dev_rec = btm_find_dev (p_bda)) ) + { + btm_sec_disconnect (p_dev_rec->hci_handle, HCI_ERR_AUTH_FAILURE); + } + } +#if (BTM_LOCAL_IO_CAPS != BTM_IO_CAP_NONE) + else + { + btsnd_hcic_user_passkey_neg_reply(p_bda); + } +#endif +} + +/******************************************************************************* +** +** Function btm_keypress_notif_evt +** +** Description This function is called when a key press notification is +** received +** +** Returns void +** +*******************************************************************************/ +void btm_keypress_notif_evt (UINT8 *p) +{ + tBTM_SP_KEYPRESS evt_data; + UINT8 *p_bda; + + /* parse & report BTM_SP_KEYPRESS_EVT */ + if (btm_cb.api.p_sp_callback) + { + p_bda = evt_data.bd_addr; + + STREAM_TO_BDADDR (p_bda, p); + evt_data.notif_type = *p; + + (*btm_cb.api.p_sp_callback) (BTM_SP_KEYPRESS_EVT, (tBTM_SP_EVT_DATA *)&evt_data); + } +} + +/******************************************************************************* +** +** Function btm_simple_pair_complete +** +** Description This function is called when simple pairing process is +** complete +** +** Returns void +** +*******************************************************************************/ +void btm_simple_pair_complete (UINT8 *p) +{ + tBTM_SP_COMPLT evt_data; + tBTM_SEC_DEV_REC *p_dev_rec; + UINT8 status; + BOOLEAN disc = FALSE; + + status = *p++; + STREAM_TO_BDADDR (evt_data.bd_addr, p); + + if ((p_dev_rec = btm_find_dev (evt_data.bd_addr)) == NULL) + { + BTM_TRACE_ERROR ("btm_simple_pair_complete() with unknown BDA: %08x%04x", + (evt_data.bd_addr[0]<<24) + (evt_data.bd_addr[1]<<16) + (evt_data.bd_addr[2]<<8) + evt_data.bd_addr[3], + (evt_data.bd_addr[4] << 8) + evt_data.bd_addr[5]); + return; + } + + BTM_TRACE_EVENT ("btm_simple_pair_complete() Pair State: %s Status:%d sec_state: %u", + btm_pair_state_descr(btm_cb.pairing_state), status, p_dev_rec->sec_state); + + evt_data.status = BTM_ERR_PROCESSING; + if (status == HCI_SUCCESS) + { + evt_data.status = BTM_SUCCESS; + p_dev_rec->sec_flags |= BTM_SEC_AUTHENTICATED; + } + else + { + if (status == HCI_ERR_PAIRING_NOT_ALLOWED) + { + /* The test spec wants the peer device to get this failure code. */ + btm_sec_change_pairing_state (BTM_PAIR_STATE_WAIT_DISCONNECT); + + /* Change the timer to 1 second */ + btu_start_timer (&btm_cb.pairing_tle, BTU_TTYPE_USER_FUNC, BT_1SEC_TIMEOUT); + } + else if (memcmp (btm_cb.pairing_bda, evt_data.bd_addr, BD_ADDR_LEN) == 0) + { + /* stop the timer */ + btu_stop_timer (&btm_cb.pairing_tle); + + if (p_dev_rec->sec_state != BTM_SEC_STATE_AUTHENTICATING) + { + /* the initiating side: will receive auth complete event. disconnect ACL at that time */ + disc = TRUE; + } + } + else + disc = TRUE; + } + + /* Let the pairing state stay active, p_auth_complete_callback will report the failure */ + memcpy (evt_data.bd_addr, p_dev_rec->bd_addr, BD_ADDR_LEN); + memcpy (evt_data.dev_class, p_dev_rec->dev_class, DEV_CLASS_LEN); + + if (btm_cb.api.p_sp_callback) + (*btm_cb.api.p_sp_callback) (BTM_SP_COMPLT_EVT, (tBTM_SP_EVT_DATA *)&evt_data); + + if (disc) + { + /* simple pairing failed */ + /* Avoid sending disconnect on HCI_ERR_PEER_USER */ + if ((status != HCI_ERR_PEER_USER) && (status != HCI_ERR_CONN_CAUSE_LOCAL_HOST)) + { + btm_sec_send_hci_disconnect (p_dev_rec, HCI_ERR_AUTH_FAILURE, p_dev_rec->hci_handle); + } + } +} + +#if BTM_OOB_INCLUDED == TRUE +/******************************************************************************* +** +** Function btm_rem_oob_req +** +** Description This function is called to process/report +** HCI_REMOTE_OOB_DATA_REQUEST_EVT +** +** Returns void +** +*******************************************************************************/ +void btm_rem_oob_req (UINT8 *p) +{ + UINT8 *p_bda; + tBTM_SP_RMT_OOB evt_data; + tBTM_SEC_DEV_REC *p_dev_rec; + BT_OCTET16 c; + BT_OCTET16 r; + + p_bda = evt_data.bd_addr; + + STREAM_TO_BDADDR (p_bda, p); + + BTM_TRACE_EVENT ("btm_rem_oob_req() BDA: %02x:%02x:%02x:%02x:%02x:%02x", + p_bda[0], p_bda[1], p_bda[2], p_bda[3], p_bda[4], p_bda[5]); + + if ( (NULL != (p_dev_rec = btm_find_dev (p_bda))) && + btm_cb.api.p_sp_callback) + { + memcpy (evt_data.bd_addr, p_dev_rec->bd_addr, BD_ADDR_LEN); + memcpy (evt_data.dev_class, p_dev_rec->dev_class, DEV_CLASS_LEN); + BCM_STRNCPY_S((char *)evt_data.bd_name, sizeof(evt_data.bd_name), (char *)p_dev_rec->sec_bd_name, BTM_MAX_REM_BD_NAME_LEN+1); + evt_data.bd_name[BTM_MAX_REM_BD_NAME_LEN] = 0; + + btm_sec_change_pairing_state(BTM_PAIR_STATE_WAIT_LOCAL_OOB_RSP); + if ((*btm_cb.api.p_sp_callback) (BTM_SP_RMT_OOB_EVT, (tBTM_SP_EVT_DATA *)&evt_data) == BTM_NOT_AUTHORIZED) + { + BTM_RemoteOobDataReply(TRUE, p_bda, c, r); + } + return; + } + + /* something bad. we can only fail this connection */ + btm_cb.acl_disc_reason = HCI_ERR_HOST_REJECT_SECURITY; + btsnd_hcic_rem_oob_neg_reply (p_bda); +} + +/******************************************************************************* +** +** Function btm_read_local_oob_complete +** +** Description This function is called when read local oob data is +** completed by the LM +** +** Returns void +** +*******************************************************************************/ +void btm_read_local_oob_complete (UINT8 *p) +{ + tBTM_SP_LOC_OOB evt_data; + UINT8 status = *p++; + + BTM_TRACE_EVENT ("btm_read_local_oob_complete:%d", status); + if (status == HCI_SUCCESS) + { + evt_data.status = BTM_SUCCESS; + STREAM_TO_ARRAY16(evt_data.c, p); + STREAM_TO_ARRAY16(evt_data.r, p); + } + else + evt_data.status = BTM_ERR_PROCESSING; + + if (btm_cb.api.p_sp_callback) + (*btm_cb.api.p_sp_callback) (BTM_SP_LOC_OOB_EVT, (tBTM_SP_EVT_DATA *)&evt_data); +} +#endif /* BTM_OOB_INCLUDED */ + +/******************************************************************************* +** +** Function btm_sec_auth_collision +** +** Description This function is called when authentication or encryption +** needs to be retried at a later time. +** +** Returns void +** +*******************************************************************************/ +static void btm_sec_auth_collision (UINT16 handle) +{ + tBTM_SEC_DEV_REC *p_dev_rec; + + if (!btm_cb.collision_start_time) + btm_cb.collision_start_time = GKI_get_os_tick_count(); + + if ((GKI_get_os_tick_count() - btm_cb.collision_start_time) < btm_cb.max_collision_delay) + { + if (handle == BTM_SEC_INVALID_HANDLE) + { + if ((p_dev_rec = btm_sec_find_dev_by_sec_state (BTM_SEC_STATE_AUTHENTICATING)) == NULL) + p_dev_rec = btm_sec_find_dev_by_sec_state (BTM_SEC_STATE_ENCRYPTING); + } + else + p_dev_rec = btm_find_dev_by_handle (handle); + + if (p_dev_rec != NULL) + { + BTM_TRACE_DEBUG ("btm_sec_auth_collision: state %d (retrying in a moment...)", p_dev_rec->sec_state); + /* We will restart authentication after timeout */ + if (p_dev_rec->sec_state == BTM_SEC_STATE_AUTHENTICATING || p_dev_rec->sec_state == BTM_SEC_STATE_ENCRYPTING) + p_dev_rec->sec_state = 0; + + btm_cb.p_collided_dev_rec = p_dev_rec; + btm_cb.sec_collision_tle.param = (UINT32) btm_sec_collision_timeout; + btu_start_timer (&btm_cb.sec_collision_tle, BTU_TTYPE_USER_FUNC, BT_1SEC_TIMEOUT); + } + } +} + +/******************************************************************************* +** +** Function btm_sec_auth_complete +** +** Description This function is when authentication of the connection is +** completed by the LM +** +** Returns void +** +*******************************************************************************/ +void btm_sec_auth_complete (UINT16 handle, UINT8 status) +{ + UINT8 old_sm4; + tBTM_PAIRING_STATE old_state = btm_cb.pairing_state; + tBTM_SEC_DEV_REC *p_dev_rec = btm_find_dev_by_handle (handle); + BOOLEAN are_bonding = FALSE; + + /* Commenting out trace due to obf/compilation problems. + */ +#if (BT_USE_TRACES == TRUE) + if (p_dev_rec) + { + BTM_TRACE_EVENT ("Security Manager: auth_complete PairState: %s handle:%u status:%d dev->sec_state: %u Bda:%08x, RName:%s", + btm_pair_state_descr (btm_cb.pairing_state), + handle, status, + p_dev_rec->sec_state, + (p_dev_rec->bd_addr[2]<<24)+(p_dev_rec->bd_addr[3]<<16)+(p_dev_rec->bd_addr[4]<<8)+p_dev_rec->bd_addr[5], + p_dev_rec->sec_bd_name); + } + else + { + BTM_TRACE_EVENT ("Security Manager: auth_complete PairState: %s handle:%u status:%d", + btm_pair_state_descr (btm_cb.pairing_state), + handle, status); + } +#endif + + /* For transaction collision we need to wait and repeat. There is no need */ + /* for random timeout because only slave should receive the result */ + if ((status == HCI_ERR_LMP_ERR_TRANS_COLLISION) || (status == HCI_ERR_DIFF_TRANSACTION_COLLISION)) + { + btm_sec_auth_collision(handle); + return; + } + btm_cb.collision_start_time = 0; + + btm_restore_mode(); + + /* Check if connection was made just to do bonding. If we authenticate + the connection that is up, this is the last event received. + */ + if (p_dev_rec + && (btm_cb.pairing_flags & BTM_PAIR_FLAGS_WE_STARTED_DD) + && !(btm_cb.pairing_flags & BTM_PAIR_FLAGS_DISC_WHEN_DONE)) + { + p_dev_rec->security_required &= ~BTM_SEC_OUT_AUTHENTICATE; + + l2cu_start_post_bond_timer (p_dev_rec->hci_handle); + } + + if (!p_dev_rec) + return; + + /* keep the old sm4 flag and clear the retry bit in control block */ + old_sm4 = p_dev_rec->sm4; + p_dev_rec->sm4 &= ~BTM_SM4_RETRY; + + if ( (btm_cb.pairing_state != BTM_PAIR_STATE_IDLE) + && (btm_cb.pairing_flags & BTM_PAIR_FLAGS_WE_STARTED_DD) + && (memcmp (p_dev_rec->bd_addr, btm_cb.pairing_bda, BD_ADDR_LEN) == 0) ) + are_bonding = TRUE; + + if ( (btm_cb.pairing_state != BTM_PAIR_STATE_IDLE) + && (memcmp (p_dev_rec->bd_addr, btm_cb.pairing_bda, BD_ADDR_LEN) == 0) ) + btm_sec_change_pairing_state (BTM_PAIR_STATE_IDLE); + + if (p_dev_rec->sec_state != BTM_SEC_STATE_AUTHENTICATING) + { + if ( (btm_cb.api.p_auth_complete_callback && status != HCI_SUCCESS) + && (old_state != BTM_PAIR_STATE_IDLE) ) + { + (*btm_cb.api.p_auth_complete_callback) (p_dev_rec->bd_addr, + p_dev_rec->dev_class, + p_dev_rec->sec_bd_name, status); + } + return; + } + + /* There can be a race condition, when we are starting authentication and + ** the peer device is doing encryption. + ** If first we receive encryption change up, then initiated authentication + ** can not be performed. According to the spec we can not do authentication + ** on the encrypted link, so device is correct. + */ + if ((status == HCI_ERR_COMMAND_DISALLOWED) + && ((p_dev_rec->sec_flags & (BTM_SEC_AUTHENTICATED | BTM_SEC_ENCRYPTED)) == + (BTM_SEC_AUTHENTICATED | BTM_SEC_ENCRYPTED))) + { + status = HCI_SUCCESS; + } + /* Currently we do not notify user if it is a keyboard which connects */ + /* User probably Disabled the keyboard while it was asleap. Let her try */ + if (btm_cb.api.p_auth_complete_callback) + { + /* report the suthentication status */ + if (old_state != BTM_PAIR_STATE_IDLE) + (*btm_cb.api.p_auth_complete_callback) (p_dev_rec->bd_addr, + p_dev_rec->dev_class, + p_dev_rec->sec_bd_name, status); + } + + p_dev_rec->sec_state = BTM_SEC_STATE_IDLE; + + /* If this is a bonding procedure can disconnect the link now */ + if (are_bonding) + { + p_dev_rec->security_required &= ~BTM_SEC_OUT_AUTHENTICATE; + + if (status != HCI_SUCCESS) + { + if(((status != HCI_ERR_PEER_USER) && (status != HCI_ERR_CONN_CAUSE_LOCAL_HOST))) + btm_sec_send_hci_disconnect (p_dev_rec, HCI_ERR_PEER_USER, p_dev_rec->hci_handle); + } + else + { + BTM_TRACE_DEBUG ("TRYING TO DECIDE IF CAN USE SMP_BR_CHNL"); + if (p_dev_rec->new_encryption_key_is_p256 && (btm_sec_use_smp_br_chnl(p_dev_rec)) + /* no LE keys are available, do deriving */ + && (!(p_dev_rec->sec_flags &BTM_SEC_LE_LINK_KEY_KNOWN) || + /* or BR key is higher security than existing LE keys */ + (!(p_dev_rec->sec_flags & BTM_SEC_LE_LINK_KEY_AUTHED) && + (p_dev_rec->sec_flags & BTM_SEC_LINK_KEY_AUTHED)))) + { + BTM_TRACE_DEBUG ("link encrypted afer dedic bonding can use SMP_BR_CHNL"); + + if (btm_sec_is_master(p_dev_rec)) + { + // Encryption is required to start SM over BR/EDR + // indicate that this is encryption after authentication + BTM_SetEncryption(p_dev_rec->bd_addr, BT_TRANSPORT_BR_EDR, NULL, NULL); + } + } + l2cu_start_post_bond_timer (p_dev_rec->hci_handle); + } + + return; + } + + /* If authentication failed, notify the waiting layer */ + if (status != HCI_SUCCESS) + { + if ((old_sm4 & BTM_SM4_RETRY) == 0) + { + /* allow retry only once */ + if (status == HCI_ERR_LMP_ERR_TRANS_COLLISION) + { + /* not retried yet. set the retry bit */ + p_dev_rec->sm4 |= BTM_SM4_RETRY; + BTM_TRACE_DEBUG ("Collision retry sm4:x%x sec_flags:0x%x", p_dev_rec->sm4, p_dev_rec->sec_flags); + } + /* this retry for missing key is for Lisbon or later only. + * Legacy device do not need this. the controller will drive the retry automatically */ + else if (HCI_ERR_KEY_MISSING == status && BTM_SEC_IS_SM4(p_dev_rec->sm4)) + { + /* not retried yet. set the retry bit */ + p_dev_rec->sm4 |= BTM_SM4_RETRY; + p_dev_rec->sec_flags &= ~BTM_SEC_LINK_KEY_KNOWN; + BTM_TRACE_DEBUG ("Retry for missing key sm4:x%x sec_flags:0x%x", p_dev_rec->sm4, p_dev_rec->sec_flags); + + /* With BRCM controller, we do not need to delete the stored link key in controller. + If the stack may sit on top of other controller, we may need this + BTM_DeleteStoredLinkKey (bd_addr, NULL); */ + } + + if (p_dev_rec->sm4 & BTM_SM4_RETRY) + { + btm_sec_execute_procedure (p_dev_rec); + return; + } + } + + btm_sec_dev_rec_cback_event (p_dev_rec, BTM_ERR_PROCESSING, FALSE); + + if (btm_cb.pairing_flags & BTM_PAIR_FLAGS_DISC_WHEN_DONE) + { + btm_sec_send_hci_disconnect (p_dev_rec, HCI_ERR_AUTH_FAILURE, p_dev_rec->hci_handle); + } + return; + } + + p_dev_rec->sec_flags |= BTM_SEC_AUTHENTICATED; + + if (p_dev_rec->pin_code_length >= 16 || + p_dev_rec->link_key_type == BTM_LKEY_TYPE_AUTH_COMB || + p_dev_rec->link_key_type == BTM_LKEY_TYPE_AUTH_COMB_P_256) { + // If we have MITM protection we have a higher level of security than + // provided by 16 digits PIN + p_dev_rec->sec_flags |= BTM_SEC_16_DIGIT_PIN_AUTHED; + } + + /* Authentication succeeded, execute the next security procedure, if any */ + status = btm_sec_execute_procedure (p_dev_rec); + + /* If there is no next procedure, or procedure failed to start, notify the caller */ + if (status != BTM_CMD_STARTED) + btm_sec_dev_rec_cback_event (p_dev_rec, status, FALSE); +} + +/******************************************************************************* +** +** Function btm_sec_encrypt_change +** +** Description This function is when encryption of the connection is +** completed by the LM +** +** Returns void +** +*******************************************************************************/ +void btm_sec_encrypt_change (UINT16 handle, UINT8 status, UINT8 encr_enable) +{ + tBTM_SEC_DEV_REC *p_dev_rec = btm_find_dev_by_handle (handle); +#if BLE_INCLUDED == TRUE && SMP_INCLUDED == TRUE + tACL_CONN *p_acl = NULL; + UINT8 acl_idx = btm_handle_to_acl_index(handle); +#endif + BTM_TRACE_EVENT ("Security Manager: encrypt_change status:%d State:%d, encr_enable = %d", + status, (p_dev_rec) ? p_dev_rec->sec_state : 0, encr_enable); + BTM_TRACE_DEBUG ("before update p_dev_rec->sec_flags=0x%x", (p_dev_rec) ? p_dev_rec->sec_flags : 0 ); + + /* For transaction collision we need to wait and repeat. There is no need */ + /* for random timeout because only slave should receive the result */ + if ((status == HCI_ERR_LMP_ERR_TRANS_COLLISION) || + (status == HCI_ERR_DIFF_TRANSACTION_COLLISION)) + { + btm_sec_auth_collision(handle); + return; + } + btm_cb.collision_start_time = 0; + + if (!p_dev_rec) + return; + + if ((status == HCI_SUCCESS) && encr_enable) + { + if (p_dev_rec->hci_handle == handle) { + p_dev_rec->sec_flags |= (BTM_SEC_AUTHENTICATED | BTM_SEC_ENCRYPTED); + if (p_dev_rec->pin_code_length >= 16 || + p_dev_rec->link_key_type == BTM_LKEY_TYPE_AUTH_COMB || + p_dev_rec->link_key_type == BTM_LKEY_TYPE_AUTH_COMB_P_256) { + p_dev_rec->sec_flags |= BTM_SEC_16_DIGIT_PIN_AUTHED; + } + } + else + { + p_dev_rec->sec_flags |= (BTM_SEC_LE_AUTHENTICATED | BTM_SEC_LE_ENCRYPTED); + } + } + + /* It is possible that we decrypted the link to perform role switch */ + /* mark link not to be encrypted, so that when we execute security next time it will kick in again */ + if ((status == HCI_SUCCESS) && !encr_enable) + { + if (p_dev_rec->hci_handle == handle) + p_dev_rec->sec_flags &= ~BTM_SEC_ENCRYPTED; + else + p_dev_rec->sec_flags &= ~BTM_SEC_LE_ENCRYPTED; + } + + BTM_TRACE_DEBUG ("after update p_dev_rec->sec_flags=0x%x", p_dev_rec->sec_flags ); + +#if BLE_INCLUDED == TRUE && SMP_INCLUDED == TRUE + if (acl_idx != MAX_L2CAP_LINKS) + p_acl = &btm_cb.acl_db[acl_idx]; + + if (p_acl != NULL) + btm_sec_check_pending_enc_req(p_dev_rec, p_acl->transport, encr_enable); + + if (p_acl && p_acl->transport == BT_TRANSPORT_LE) + { + if (status == HCI_ERR_KEY_MISSING || status == HCI_ERR_AUTH_FAILURE || + status == HCI_ERR_ENCRY_MODE_NOT_ACCEPTABLE) + { + p_dev_rec->sec_flags &= ~ (BTM_SEC_LE_LINK_KEY_KNOWN); + p_dev_rec->ble.key_type = BTM_LE_KEY_NONE; + } + btm_ble_link_encrypted(p_dev_rec->ble.pseudo_addr, encr_enable); + return; + } + else + { + /* BR/EDR connection, update the encryption key size to be 16 as always */ + p_dev_rec->enc_key_size = 16; + } + + BTM_TRACE_DEBUG ("in %s new_encr_key_256 is %d", + __func__, p_dev_rec->new_encryption_key_is_p256); + + if ((status == HCI_SUCCESS) && encr_enable && (p_dev_rec->hci_handle == handle)) + { + if (p_dev_rec->new_encryption_key_is_p256) + { + if (btm_sec_use_smp_br_chnl(p_dev_rec) && + btm_sec_is_master(p_dev_rec) && + /* if LE key is not known, do deriving */ + (!(p_dev_rec->sec_flags &BTM_SEC_LE_LINK_KEY_KNOWN) || + /* or BR key is higher security than existing LE keys */ + (!(p_dev_rec->sec_flags & BTM_SEC_LE_LINK_KEY_AUTHED) + && (p_dev_rec->sec_flags & BTM_SEC_LINK_KEY_AUTHED)))) + { + /* BR/EDR is encrypted with LK that can be used to derive LE LTK */ + p_dev_rec->new_encryption_key_is_p256 = FALSE; + + if (p_dev_rec->no_smp_on_br) + { + BTM_TRACE_DEBUG ("%s NO SM over BR/EDR", __func__); + } + else + { + BTM_TRACE_DEBUG ("%s start SM over BR/EDR", __func__); + SMP_BR_PairWith(p_dev_rec->bd_addr); + } + } + } + else + { + // BR/EDR is successfully encrypted. Correct LK type if needed + // (BR/EDR LK derived from LE LTK was used for encryption) + if ((encr_enable == 1) && /* encryption is ON for SSP */ + /* LK type is for BR/EDR SC */ + (p_dev_rec->link_key_type == BTM_LKEY_TYPE_UNAUTH_COMB_P_256 || + p_dev_rec->link_key_type == BTM_LKEY_TYPE_AUTH_COMB_P_256)) + { + if (p_dev_rec->link_key_type == BTM_LKEY_TYPE_UNAUTH_COMB_P_256) + p_dev_rec->link_key_type = BTM_LKEY_TYPE_UNAUTH_COMB; + else /* BTM_LKEY_TYPE_AUTH_COMB_P_256 */ + p_dev_rec->link_key_type = BTM_LKEY_TYPE_AUTH_COMB; + + BTM_TRACE_DEBUG("updated link key type to %d", p_dev_rec->link_key_type); + btm_send_link_key_notif(p_dev_rec); + } + } + } +#else + btm_sec_check_pending_enc_req (p_dev_rec, BT_TRANSPORT_BR_EDR, encr_enable); +#endif /* BLE_INCLUDED == TRUE && SMP_INCLUDED == TRUE */ + + /* If this encryption was started by peer do not need to do anything */ + if (p_dev_rec->sec_state != BTM_SEC_STATE_ENCRYPTING) + { + if (BTM_SEC_STATE_DELAY_FOR_ENC == p_dev_rec->sec_state) + { + p_dev_rec->sec_state = BTM_SEC_STATE_IDLE; + p_dev_rec->p_callback = NULL; + l2cu_resubmit_pending_sec_req (p_dev_rec->bd_addr); + } + return; + } + + p_dev_rec->sec_state = BTM_SEC_STATE_IDLE; + /* If encryption setup failed, notify the waiting layer */ + if (status != HCI_SUCCESS) + { + btm_sec_dev_rec_cback_event (p_dev_rec, BTM_ERR_PROCESSING, FALSE); + return; + } + + /* Encryption setup succeeded, execute the next security procedure, if any */ + status = (UINT8)btm_sec_execute_procedure (p_dev_rec); + /* If there is no next procedure, or procedure failed to start, notify the caller */ + if (status != BTM_CMD_STARTED) + btm_sec_dev_rec_cback_event (p_dev_rec, status, FALSE); +} + +/******************************************************************************* +** +** Function btm_sec_connect_after_reject_timeout +** +** Description Connection for bonding could not start because of the collision +** Initiate outgoing connection +** +** Returns Pointer to the TLE struct +** +*******************************************************************************/ +static void btm_sec_connect_after_reject_timeout (TIMER_LIST_ENT *p_tle) +{ + tBTM_SEC_DEV_REC *p_dev_rec = btm_cb.p_collided_dev_rec; + UNUSED(p_tle); + + BTM_TRACE_EVENT ("btm_sec_connect_after_reject_timeout()"); + btm_cb.sec_collision_tle.param = 0; + btm_cb.p_collided_dev_rec = 0; + + if (btm_sec_dd_create_conn(p_dev_rec) != BTM_CMD_STARTED) + { + BTM_TRACE_WARNING ("Security Manager: btm_sec_connect_after_reject_timeout: failed to start connection"); + + btm_sec_change_pairing_state (BTM_PAIR_STATE_IDLE); + + if (btm_cb.api.p_auth_complete_callback) + (*btm_cb.api.p_auth_complete_callback) (p_dev_rec->bd_addr, p_dev_rec->dev_class, + p_dev_rec->sec_bd_name, HCI_ERR_MEMORY_FULL); + } +} + +/******************************************************************************* +** +** Function btm_sec_connected +** +** Description This function is when a connection to the peer device is +** establsihed +** +** Returns void +** +*******************************************************************************/ +void btm_sec_connected (UINT8 *bda, UINT16 handle, UINT8 status, UINT8 enc_mode) +{ + tBTM_SEC_DEV_REC *p_dev_rec = btm_find_dev (bda); + UINT8 res; + BOOLEAN is_pairing_device = FALSE; + tACL_CONN *p_acl_cb; + UINT8 bit_shift = 0; + + btm_acl_resubmit_page(); + + /* Commenting out trace due to obf/compilation problems. + */ +#if (BT_USE_TRACES == TRUE) + if (p_dev_rec) + { + BTM_TRACE_EVENT ("Security Manager: btm_sec_connected in state: %s handle:%d status:%d enc_mode:%d bda:%x RName:%s", + btm_pair_state_descr(btm_cb.pairing_state), handle, status, enc_mode, + (bda[2]<<24)+(bda[3]<<16)+(bda[4]<<8)+bda[5], + p_dev_rec->sec_bd_name); + } + else + { + BTM_TRACE_EVENT ("Security Manager: btm_sec_connected in state: %s handle:%d status:%d enc_mode:%d bda:%x ", + btm_pair_state_descr(btm_cb.pairing_state), handle, status, enc_mode, + (bda[2]<<24)+(bda[3]<<16)+(bda[4]<<8)+bda[5]); + } +#endif + + if (!p_dev_rec) + { + /* There is no device record for new connection. Allocate one */ + if (status == HCI_SUCCESS) + { + p_dev_rec = btm_sec_alloc_dev (bda); + } + else + { + /* If the device matches with stored paring address + * reset the paring state to idle */ + if ((btm_cb.pairing_state != BTM_PAIR_STATE_IDLE) && + (memcmp (btm_cb.pairing_bda, bda, BD_ADDR_LEN) == 0)) + { + btm_sec_change_pairing_state(BTM_PAIR_STATE_IDLE); + } + + /* can not find the device record and the status is error, + * just ignore it */ + return; + } + } + else /* Update the timestamp for this device */ + { + +#if BLE_INCLUDED == TRUE + bit_shift = (handle == p_dev_rec->ble_hci_handle) ? 8 :0; +#endif + p_dev_rec->timestamp = btm_cb.dev_rec_count++; + if (p_dev_rec->sm4 & BTM_SM4_CONN_PEND) + { + /* tell L2CAP it's a bonding connection. */ + if ( (btm_cb.pairing_state != BTM_PAIR_STATE_IDLE) + && (memcmp (btm_cb.pairing_bda, p_dev_rec->bd_addr, BD_ADDR_LEN) == 0) + && (btm_cb.pairing_flags & BTM_PAIR_FLAGS_WE_STARTED_DD) ) + { + /* if incoming connection failed while pairing, then try to connect and continue */ + /* Motorola S9 disconnects without asking pin code */ + if ((status != HCI_SUCCESS)&&(btm_cb.pairing_state == BTM_PAIR_STATE_WAIT_PIN_REQ)) + { + BTM_TRACE_WARNING ("Security Manager: btm_sec_connected: incoming connection failed without asking PIN"); + + p_dev_rec->sm4 &= ~BTM_SM4_CONN_PEND; + if (p_dev_rec->sec_flags & BTM_SEC_NAME_KNOWN) + { + /* Start timer with 0 to initiate connection with new LCB */ + /* because L2CAP will delete current LCB with this event */ + btm_cb.p_collided_dev_rec = p_dev_rec; + btm_cb.sec_collision_tle.param = (UINT32) btm_sec_connect_after_reject_timeout; + btu_start_timer (&btm_cb.sec_collision_tle, BTU_TTYPE_USER_FUNC, 0); + } + else + { + btm_sec_change_pairing_state (BTM_PAIR_STATE_GET_REM_NAME); + BTM_ReadRemoteDeviceName(p_dev_rec->bd_addr, NULL, BT_TRANSPORT_BR_EDR); + } +#if BTM_DISC_DURING_RS == TRUE + p_dev_rec->rs_disc_pending = BTM_SEC_RS_NOT_PENDING; /* reset flag */ +#endif + return; + } + else + { + l2cu_update_lcb_4_bonding(p_dev_rec->bd_addr, TRUE); + } + } + /* always clear the pending flag */ + p_dev_rec->sm4 &= ~BTM_SM4_CONN_PEND; + } + } + +#if BLE_INCLUDED == TRUE + p_dev_rec->device_type |= BT_DEVICE_TYPE_BREDR; +#endif + +#if BTM_DISC_DURING_RS == TRUE + p_dev_rec->rs_disc_pending = BTM_SEC_RS_NOT_PENDING; /* reset flag */ +#endif + + p_dev_rec->rs_disc_pending = BTM_SEC_RS_NOT_PENDING; /* reset flag */ + + if ( (btm_cb.pairing_state != BTM_PAIR_STATE_IDLE) + && (memcmp (btm_cb.pairing_bda, bda, BD_ADDR_LEN) == 0) ) + { + /* if we rejected incoming connection from bonding device */ + if ((status == HCI_ERR_HOST_REJECT_DEVICE) + &&(btm_cb.pairing_flags & BTM_PAIR_FLAGS_REJECTED_CONNECT)) + { + BTM_TRACE_WARNING ("Security Manager: btm_sec_connected: HCI_Conn_Comp Flags:0x%04x, sm4: 0x%x", + btm_cb.pairing_flags, p_dev_rec->sm4); + + btm_cb.pairing_flags &= ~BTM_PAIR_FLAGS_REJECTED_CONNECT; + if (BTM_SEC_IS_SM4_UNKNOWN(p_dev_rec->sm4)) + { + /* Try again: RNR when no ACL causes HCI_RMT_HOST_SUP_FEAT_NOTIFY_EVT */ + btm_sec_change_pairing_state (BTM_PAIR_STATE_GET_REM_NAME); + BTM_ReadRemoteDeviceName(bda, NULL, BT_TRANSPORT_BR_EDR); + return; + } + + /* if we already have pin code */ + if (btm_cb.pairing_state != BTM_PAIR_STATE_WAIT_LOCAL_PIN) + { + /* Start timer with 0 to initiate connection with new LCB */ + /* because L2CAP will delete current LCB with this event */ + btm_cb.p_collided_dev_rec = p_dev_rec; + btm_cb.sec_collision_tle.param = (UINT32) btm_sec_connect_after_reject_timeout; + btu_start_timer (&btm_cb.sec_collision_tle, BTU_TTYPE_USER_FUNC, 0); + } + + return; + } + /* wait for incoming connection without resetting pairing state */ + else if (status == HCI_ERR_CONNECTION_EXISTS) + { + BTM_TRACE_WARNING ("Security Manager: btm_sec_connected: Wait for incoming connection"); + return; + } + + is_pairing_device = TRUE; + } + + /* If connection was made to do bonding restore link security if changed */ + btm_restore_mode(); + + /* if connection fails during pin request, notify application */ + if (status != HCI_SUCCESS) + { + /* If connection failed because of during pairing, need to tell user */ + if (is_pairing_device) + { + p_dev_rec->security_required &= ~BTM_SEC_OUT_AUTHENTICATE; + p_dev_rec->sec_flags &= ~((BTM_SEC_LINK_KEY_KNOWN | BTM_SEC_LINK_KEY_AUTHED) << bit_shift); + BTM_TRACE_DEBUG ("security_required:%x ", p_dev_rec->security_required ); + + btm_sec_change_pairing_state (BTM_PAIR_STATE_IDLE); + + /* We need to notify host that the key is not known any more */ + if (btm_cb.api.p_auth_complete_callback) + { + (*btm_cb.api.p_auth_complete_callback) (p_dev_rec->bd_addr, + p_dev_rec->dev_class, + p_dev_rec->sec_bd_name, status); + } + } + /* + Do not send authentication failure, if following conditions hold good + 1. BTM Sec Pairing state is idle + 2. Link key for the remote device is present. + 3. Remote is SSP capable. + */ + else if ((p_dev_rec->link_key_type <= BTM_LKEY_TYPE_REMOTE_UNIT) && + (((status == HCI_ERR_AUTH_FAILURE) || + (status == HCI_ERR_KEY_MISSING) || + (status == HCI_ERR_HOST_REJECT_SECURITY) || + (status == HCI_ERR_PAIRING_NOT_ALLOWED) || + (status == HCI_ERR_UNIT_KEY_USED) || + (status == HCI_ERR_PAIRING_WITH_UNIT_KEY_NOT_SUPPORTED) || + (status == HCI_ERR_ENCRY_MODE_NOT_ACCEPTABLE) || + (status == HCI_ERR_REPEATED_ATTEMPTS)))) + { + p_dev_rec->security_required &= ~BTM_SEC_OUT_AUTHENTICATE; + p_dev_rec->sec_flags &= ~ (BTM_SEC_LE_LINK_KEY_KNOWN << bit_shift); + + +#ifdef BRCM_NOT_4_BTE + /* If we rejected pairing, pass this special result code */ + if (btm_cb.acl_disc_reason == HCI_ERR_HOST_REJECT_SECURITY) + { + status = HCI_ERR_HOST_REJECT_SECURITY; + } +#endif + + /* We need to notify host that the key is not known any more */ + if (btm_cb.api.p_auth_complete_callback) + { + (*btm_cb.api.p_auth_complete_callback) (p_dev_rec->bd_addr, + p_dev_rec->dev_class, + p_dev_rec->sec_bd_name, status); + } + } + + if (status == HCI_ERR_CONNECTION_TOUT || status == HCI_ERR_LMP_RESPONSE_TIMEOUT || + status == HCI_ERR_UNSPECIFIED || status == HCI_ERR_PAGE_TIMEOUT) + btm_sec_dev_rec_cback_event (p_dev_rec, BTM_DEVICE_TIMEOUT, FALSE); + else + btm_sec_dev_rec_cback_event (p_dev_rec, BTM_ERR_PROCESSING, FALSE); + + return; + } + + /* If initiated dedicated bonding, return the link key now, and initiate disconnect */ + /* If dedicated bonding, and we now have a link key, we are all done */ + if ( is_pairing_device + && (p_dev_rec->sec_flags & BTM_SEC_LINK_KEY_KNOWN) ) + { + if (p_dev_rec->link_key_not_sent) + { + p_dev_rec->link_key_not_sent = FALSE; + btm_send_link_key_notif(p_dev_rec); + } + + p_dev_rec->security_required &= ~BTM_SEC_OUT_AUTHENTICATE; + + /* remember flag before it is initialized */ + if (btm_cb.pairing_flags & BTM_PAIR_FLAGS_WE_STARTED_DD) + res = TRUE; + else + res = FALSE; + + if (btm_cb.api.p_auth_complete_callback) + (*btm_cb.api.p_auth_complete_callback) (p_dev_rec->bd_addr, + p_dev_rec->dev_class, + p_dev_rec->sec_bd_name, HCI_SUCCESS); + + btm_sec_change_pairing_state (BTM_PAIR_STATE_IDLE); + + if ( res ) + { + /* Let l2cap start bond timer */ + l2cu_update_lcb_4_bonding (p_dev_rec->bd_addr, TRUE); + } + + return; + } + + p_dev_rec->hci_handle = handle; + + /* role may not be correct here, it will be updated by l2cap, but we need to */ + /* notify btm_acl that link is up, so starting of rmt name request will not */ + /* set paging flag up */ + p_acl_cb = btm_bda_to_acl(bda, BT_TRANSPORT_BR_EDR); + if (p_acl_cb) + { + /* whatever is in btm_establish_continue() without reporting the BTM_BL_CONN_EVT event */ +#if (!defined(BTM_BYPASS_EXTRA_ACL_SETUP) || BTM_BYPASS_EXTRA_ACL_SETUP == FALSE) + /* For now there are a some devices that do not like sending */ + /* commands events and data at the same time. */ + /* Set the packet types to the default allowed by the device */ + btm_set_packet_types (p_acl_cb, btm_cb.btm_acl_pkt_types_supported); + + if (btm_cb.btm_def_link_policy) + BTM_SetLinkPolicy (p_acl_cb->remote_addr, &btm_cb.btm_def_link_policy); +#endif + } + btm_acl_created (bda, p_dev_rec->dev_class, p_dev_rec->sec_bd_name, handle, HCI_ROLE_SLAVE, BT_TRANSPORT_BR_EDR); + + /* Initialize security flags. We need to do that because some */ + /* authorization complete could have come after the connection is dropped */ + /* and that would set wrong flag that link has been authorized already */ + p_dev_rec->sec_flags &= ~((BTM_SEC_AUTHORIZED | BTM_SEC_AUTHENTICATED | + BTM_SEC_ENCRYPTED | BTM_SEC_ROLE_SWITCHED) << bit_shift); + + if (enc_mode != HCI_ENCRYPT_MODE_DISABLED) + p_dev_rec->sec_flags |= ((BTM_SEC_AUTHENTICATED | BTM_SEC_ENCRYPTED) << bit_shift); + + if (btm_cb.security_mode == BTM_SEC_MODE_LINK) + p_dev_rec->sec_flags |= (BTM_SEC_AUTHENTICATED << bit_shift); + + if (p_dev_rec->pin_code_length >= 16 || + p_dev_rec->link_key_type == BTM_LKEY_TYPE_AUTH_COMB || + p_dev_rec->link_key_type == BTM_LKEY_TYPE_AUTH_COMB_P_256) { + p_dev_rec->sec_flags |= (BTM_SEC_16_DIGIT_PIN_AUTHED << bit_shift); + } + + p_dev_rec->link_key_changed = FALSE; + + /* After connection is established we perform security if we do not know */ + /* the name, or if we are originator because some procedure can have */ + /* been scheduled while connection was down */ + BTM_TRACE_DEBUG ("is_originator:%d ", p_dev_rec->is_originator); + if (!(p_dev_rec->sec_flags & BTM_SEC_NAME_KNOWN) || p_dev_rec->is_originator) + { + if ((res = btm_sec_execute_procedure (p_dev_rec)) != BTM_CMD_STARTED) + btm_sec_dev_rec_cback_event (p_dev_rec, res, FALSE); + } + return; +} + +/******************************************************************************* +** +** Function btm_sec_disconnect +** +** Description This function is called to disconnect HCI link +** +** Returns btm status +** +*******************************************************************************/ +tBTM_STATUS btm_sec_disconnect (UINT16 handle, UINT8 reason) +{ + tBTM_SEC_DEV_REC *p_dev_rec = btm_find_dev_by_handle (handle); + + /* In some weird race condition we may not have a record */ + if (!p_dev_rec) + { + btsnd_hcic_disconnect (handle, reason); + return(BTM_SUCCESS); + } + + /* If we are in the process of bonding we need to tell client that auth failed */ + if ( (btm_cb.pairing_state != BTM_PAIR_STATE_IDLE) + && (memcmp (btm_cb.pairing_bda, p_dev_rec->bd_addr, BD_ADDR_LEN) == 0) + && (btm_cb.pairing_flags & BTM_PAIR_FLAGS_WE_STARTED_DD) ) + { + /* we are currently doing bonding. Link will be disconnected when done */ + btm_cb.pairing_flags |= BTM_PAIR_FLAGS_DISC_WHEN_DONE; + return(BTM_BUSY); + } + + return(btm_sec_send_hci_disconnect(p_dev_rec, reason, handle)); +} + +/******************************************************************************* +** +** Function btm_sec_disconnected +** +** Description This function is when a connection to the peer device is +** dropped +** +** Returns void +** +*******************************************************************************/ +void btm_sec_disconnected (UINT16 handle, UINT8 reason) +{ + tBTM_SEC_DEV_REC *p_dev_rec = btm_find_dev_by_handle (handle); + UINT8 old_pairing_flags = btm_cb.pairing_flags; + int result = HCI_ERR_AUTH_FAILURE; + tBTM_SEC_CALLBACK *p_callback = NULL; + tBT_TRANSPORT transport = BT_TRANSPORT_BR_EDR; + + /* If page was delayed for disc complete, can do it now */ + btm_cb.discing = FALSE; + + btm_acl_resubmit_page(); + + if (!p_dev_rec) + return; + + transport = (handle == p_dev_rec->hci_handle) ? BT_TRANSPORT_BR_EDR: BT_TRANSPORT_LE; + + p_dev_rec->rs_disc_pending = BTM_SEC_RS_NOT_PENDING; /* reset flag */ + +#if BTM_DISC_DURING_RS == TRUE + LOG_INFO("%s clearing pending flag handle:%d reason:%d", __func__, handle, reason); + p_dev_rec->rs_disc_pending = BTM_SEC_RS_NOT_PENDING; /* reset flag */ +#endif + + /* clear unused flags */ + p_dev_rec->sm4 &= BTM_SM4_TRUE; + + uint8_t *bd_addr = (uint8_t *)p_dev_rec->bd_addr; + BTM_TRACE_EVENT("%s sec_req:x%x state:%s reason:%d bd_addr:%02x:%02x:%02x:%02x:%02x:%02x" + " remote_name:%s", __func__, p_dev_rec->security_required, btm_pair_state_descr(btm_cb.pairing_state), + reason, bd_addr[0], bd_addr[1], bd_addr[2], bd_addr[3], bd_addr[4], bd_addr[5], p_dev_rec->sec_bd_name); + + BTM_TRACE_EVENT("%s before update sec_flags=0x%x", __func__, p_dev_rec->sec_flags); + + /* If we are in the process of bonding we need to tell client that auth failed */ + if ( (btm_cb.pairing_state != BTM_PAIR_STATE_IDLE) + && (memcmp (btm_cb.pairing_bda, p_dev_rec->bd_addr, BD_ADDR_LEN) == 0)) + { + btm_sec_change_pairing_state (BTM_PAIR_STATE_IDLE); + p_dev_rec->sec_flags &= ~BTM_SEC_LINK_KEY_KNOWN; + if (btm_cb.api.p_auth_complete_callback) + { + /* If the disconnection reason is REPEATED_ATTEMPTS, + send this error message to complete callback function + to display the error message of Repeated attempts. + All others, send HCI_ERR_AUTH_FAILURE. */ + if (reason == HCI_ERR_REPEATED_ATTEMPTS) + { + result = HCI_ERR_REPEATED_ATTEMPTS; + } + else if (old_pairing_flags & BTM_PAIR_FLAGS_WE_STARTED_DD) + { + result = HCI_ERR_HOST_REJECT_SECURITY; + } + (*btm_cb.api.p_auth_complete_callback) (p_dev_rec->bd_addr, p_dev_rec->dev_class, + p_dev_rec->sec_bd_name, result); + } + } + +#if BLE_INCLUDED == TRUE && SMP_INCLUDED == TRUE + btm_ble_update_mode_operation(HCI_ROLE_UNKNOWN, p_dev_rec->bd_addr, HCI_SUCCESS); + /* see sec_flags processing in btm_acl_removed */ + + if (transport == BT_TRANSPORT_LE) + { + p_dev_rec->ble_hci_handle = BTM_SEC_INVALID_HANDLE; + p_dev_rec->sec_flags &= ~(BTM_SEC_LE_AUTHENTICATED|BTM_SEC_LE_ENCRYPTED); + p_dev_rec->enc_key_size = 0; + } + else +#endif + { + p_dev_rec->hci_handle = BTM_SEC_INVALID_HANDLE; + p_dev_rec->sec_flags &= ~(BTM_SEC_AUTHORIZED | BTM_SEC_AUTHENTICATED | BTM_SEC_ENCRYPTED + | BTM_SEC_ROLE_SWITCHED | BTM_SEC_16_DIGIT_PIN_AUTHED); + } + +#if BLE_INCLUDED == TRUE && SMP_INCLUDED == TRUE + if (p_dev_rec->sec_state == BTM_SEC_STATE_DISCONNECTING_BOTH) + { + p_dev_rec->sec_state = (transport == BT_TRANSPORT_LE) ? + BTM_SEC_STATE_DISCONNECTING : BTM_SEC_STATE_DISCONNECTING_BLE; + return; + } +#endif + p_dev_rec->sec_state = BTM_SEC_STATE_IDLE; + p_dev_rec->security_required = BTM_SEC_NONE; + + p_callback = p_dev_rec->p_callback; + + /* if security is pending, send callback to clean up the security state */ + if(p_callback) + { + p_dev_rec->p_callback = NULL; /* when the peer device time out the authentication before + we do, this call back must be reset here */ + (*p_callback) (p_dev_rec->bd_addr, transport, p_dev_rec->p_ref_data, BTM_ERR_PROCESSING); + } + + BTM_TRACE_EVENT("%s after update sec_flags=0x%x", __func__, p_dev_rec->sec_flags); +} + +/******************************************************************************* +** +** Function btm_sec_link_key_notification +** +** Description This function is called when a new connection link key is +** generated +** +** Returns Pointer to the record or NULL +** +*******************************************************************************/ +void btm_sec_link_key_notification (UINT8 *p_bda, UINT8 *p_link_key, UINT8 key_type) +{ + tBTM_SEC_DEV_REC *p_dev_rec = btm_find_or_alloc_dev (p_bda); + BOOLEAN we_are_bonding = FALSE; + BOOLEAN ltk_derived_lk = FALSE; + + BTM_TRACE_EVENT ("btm_sec_link_key_notification() BDA:%04x%08x, TYPE: %d", + (p_bda[0]<<8)+p_bda[1], (p_bda[2]<<24)+(p_bda[3]<<16)+(p_bda[4]<<8)+p_bda[5], + key_type); + + if ((key_type >= BTM_LTK_DERIVED_LKEY_OFFSET + BTM_LKEY_TYPE_COMBINATION) && + (key_type <= BTM_LTK_DERIVED_LKEY_OFFSET + BTM_LKEY_TYPE_AUTH_COMB_P_256)) + { + ltk_derived_lk = TRUE; + key_type -= BTM_LTK_DERIVED_LKEY_OFFSET; + } + /* If connection was made to do bonding restore link security if changed */ + btm_restore_mode(); + + if (key_type != BTM_LKEY_TYPE_CHANGED_COMB) + p_dev_rec->link_key_type = key_type; + + p_dev_rec->sec_flags |= BTM_SEC_LINK_KEY_KNOWN; + + /* + * Until this point in time, we do not know if MITM was enabled, hence we + * add the extended security flag here. + */ + if (p_dev_rec->pin_code_length >= 16 || + p_dev_rec->link_key_type == BTM_LKEY_TYPE_AUTH_COMB || + p_dev_rec->link_key_type == BTM_LKEY_TYPE_AUTH_COMB_P_256) { + p_dev_rec->sec_flags |= BTM_SEC_16_DIGIT_PIN_AUTHED; + } + +#if (BLE_INCLUDED == TRUE) + /* BR/EDR connection, update the encryption key size to be 16 as always */ + p_dev_rec->enc_key_size = 16; +#endif + memcpy (p_dev_rec->link_key, p_link_key, LINK_KEY_LEN); + + if ( (btm_cb.pairing_state != BTM_PAIR_STATE_IDLE) + && (memcmp (btm_cb.pairing_bda, p_bda, BD_ADDR_LEN) == 0) ) + { + if (btm_cb.pairing_flags & BTM_PAIR_FLAGS_WE_STARTED_DD) + we_are_bonding = TRUE; + else + btm_sec_change_pairing_state (BTM_PAIR_STATE_IDLE); + } + + /* save LTK derived LK no matter what */ + if (ltk_derived_lk) + { + if (btm_cb.api.p_link_key_callback) + { + BTM_TRACE_DEBUG ("%s() Save LTK derived LK (key_type = %d)", + __FUNCTION__, p_dev_rec->link_key_type); + (*btm_cb.api.p_link_key_callback) (p_bda, p_dev_rec->dev_class, + p_dev_rec->sec_bd_name, + p_link_key, p_dev_rec->link_key_type); + } + } + else + { + if ((p_dev_rec->link_key_type == BTM_LKEY_TYPE_UNAUTH_COMB_P_256) || + (p_dev_rec->link_key_type == BTM_LKEY_TYPE_AUTH_COMB_P_256)) + { + p_dev_rec->new_encryption_key_is_p256 = TRUE; + BTM_TRACE_DEBUG ("%s set new_encr_key_256 to %d", + __func__, p_dev_rec->new_encryption_key_is_p256); + } + } + + /* If name is not known at this point delay calling callback until the name is */ + /* resolved. Unless it is a HID Device and we really need to send all link keys. */ + if ((!(p_dev_rec->sec_flags & BTM_SEC_NAME_KNOWN) + && ((p_dev_rec->dev_class[1] & BTM_COD_MAJOR_CLASS_MASK) != BTM_COD_MAJOR_PERIPHERAL)) + && !ltk_derived_lk) + { + BTM_TRACE_EVENT ("btm_sec_link_key_notification() Delayed BDA: %08x%04x Type:%d", + (p_bda[0]<<24) + (p_bda[1]<<16) + (p_bda[2]<<8) + p_bda[3], + (p_bda[4] << 8) + p_bda[5], key_type); + + p_dev_rec->link_key_not_sent = TRUE; + + /* If it is for bonding nothing else will follow, so we need to start name resolution */ + if (we_are_bonding) + { + if (!(btsnd_hcic_rmt_name_req (p_bda, HCI_PAGE_SCAN_REP_MODE_R1, HCI_MANDATARY_PAGE_SCAN_MODE, 0))) + btm_inq_rmt_name_failed(); + } + + BTM_TRACE_EVENT ("rmt_io_caps:%d, sec_flags:x%x, dev_class[1]:x%02x", p_dev_rec->rmt_io_caps, p_dev_rec->sec_flags, p_dev_rec->dev_class[1]) + return; + } + + /* If its not us who perform authentication, we should tell stackserver */ + /* that some authentication has been completed */ + /* This is required when different entities receive link notification and auth complete */ + if (!(p_dev_rec->security_required & BTM_SEC_OUT_AUTHENTICATE) + /* for derived key, always send authentication callback for BR channel */ + || ltk_derived_lk) + { + if (btm_cb.api.p_auth_complete_callback) + (*btm_cb.api.p_auth_complete_callback) (p_dev_rec->bd_addr, p_dev_rec->dev_class, + p_dev_rec->sec_bd_name, HCI_SUCCESS); + } + + /* We will save link key only if the user authorized it - BTE report link key in all cases */ +#ifdef BRCM_NONE_BTE + if (p_dev_rec->sec_flags & BTM_SEC_LINK_KEY_AUTHED) +#endif + { + if (btm_cb.api.p_link_key_callback) + { + if (ltk_derived_lk) + { + BTM_TRACE_DEBUG ("btm_sec_link_key_notification() LTK derived LK is saved already" + " (key_type = %d)", p_dev_rec->link_key_type); + } + else + { + (*btm_cb.api.p_link_key_callback) (p_bda, p_dev_rec->dev_class, + p_dev_rec->sec_bd_name, + p_link_key, p_dev_rec->link_key_type); + } + } + } +} + +/******************************************************************************* +** +** Function btm_sec_link_key_request +** +** Description This function is called when controller requests link key +** +** Returns Pointer to the record or NULL +** +*******************************************************************************/ +void btm_sec_link_key_request (UINT8 *p_bda) +{ + tBTM_SEC_DEV_REC *p_dev_rec = btm_find_or_alloc_dev (p_bda); + + BTM_TRACE_EVENT ("btm_sec_link_key_request() BDA: %02x:%02x:%02x:%02x:%02x:%02x", + p_bda[0], p_bda[1], p_bda[2], p_bda[3], p_bda[4], p_bda[5]); + + if( (btm_cb.pairing_state == BTM_PAIR_STATE_WAIT_PIN_REQ) && + (btm_cb.collision_start_time != 0) && + (memcmp (btm_cb.p_collided_dev_rec->bd_addr, p_bda, BD_ADDR_LEN) == 0) ) + { + BTM_TRACE_EVENT ("btm_sec_link_key_request() rejecting link key req " + "State: %d START_TIMEOUT : %d", + btm_cb.pairing_state, btm_cb.collision_start_time); + btsnd_hcic_link_key_neg_reply (p_bda); + return; + } + if (p_dev_rec->sec_flags & BTM_SEC_LINK_KEY_KNOWN) + { + btsnd_hcic_link_key_req_reply (p_bda, p_dev_rec->link_key); + return; + } + + /* Notify L2CAP to increase timeout */ + l2c_pin_code_request (p_bda); + + /* The link key is not in the database and it is not known to the manager */ + btsnd_hcic_link_key_neg_reply (p_bda); +} + +/******************************************************************************* +** +** Function btm_sec_pairing_timeout +** +** Description This function is called when host does not provide PIN +** within requested time +** +** Returns Pointer to the TLE struct +** +*******************************************************************************/ +static void btm_sec_pairing_timeout (TIMER_LIST_ENT *p_tle) +{ + tBTM_CB *p_cb = &btm_cb; + tBTM_SEC_DEV_REC *p_dev_rec; +#if BTM_OOB_INCLUDED == TRUE +#if (BTM_LOCAL_IO_CAPS == BTM_IO_CAP_NONE) + tBTM_AUTH_REQ auth_req = BTM_AUTH_AP_NO; +#else + tBTM_AUTH_REQ auth_req = BTM_AUTH_AP_YES; +#endif +#endif + UINT8 name[2]; + UNUSED(p_tle); + + p_cb->pairing_tle.param = 0; +/* Coverity: FALSE-POSITIVE error from Coverity tool. Please do NOT remove following comment. */ +/* coverity[UNUSED_VALUE] pointer p_dev_rec is actually used several times... This is a Coverity false-positive, i.e. a fake issue. +*/ + p_dev_rec = btm_find_dev (p_cb->pairing_bda); + + BTM_TRACE_EVENT ("btm_sec_pairing_timeout() State: %s Flags: %u", + btm_pair_state_descr(p_cb->pairing_state), p_cb->pairing_flags); + + switch (p_cb->pairing_state) + { + case BTM_PAIR_STATE_WAIT_PIN_REQ: + btm_sec_bond_cancel_complete(); + break; + + case BTM_PAIR_STATE_WAIT_LOCAL_PIN: + if ( (btm_cb.pairing_flags & BTM_PAIR_FLAGS_PRE_FETCH_PIN) == 0) + btsnd_hcic_pin_code_neg_reply (p_cb->pairing_bda); + btm_sec_change_pairing_state (BTM_PAIR_STATE_IDLE); + /* We need to notify the UI that no longer need the PIN */ + if (btm_cb.api.p_auth_complete_callback) + { + if (p_dev_rec == NULL) + { + name[0] = 0; + (*btm_cb.api.p_auth_complete_callback) (p_cb->pairing_bda, + NULL, + name, HCI_ERR_CONNECTION_TOUT); + } + else + (*btm_cb.api.p_auth_complete_callback) (p_dev_rec->bd_addr, + p_dev_rec->dev_class, + p_dev_rec->sec_bd_name, HCI_ERR_CONNECTION_TOUT); + } + break; + + case BTM_PAIR_STATE_WAIT_NUMERIC_CONFIRM: + btsnd_hcic_user_conf_reply (p_cb->pairing_bda, FALSE); + /* btm_sec_change_pairing_state (BTM_PAIR_STATE_IDLE); */ + break; + +#if (BTM_LOCAL_IO_CAPS != BTM_IO_CAP_NONE) + case BTM_PAIR_STATE_KEY_ENTRY: + btsnd_hcic_user_passkey_neg_reply(p_cb->pairing_bda); + /* btm_sec_change_pairing_state (BTM_PAIR_STATE_IDLE); */ + break; +#endif /* !BTM_IO_CAP_NONE */ + +#if BTM_OOB_INCLUDED == TRUE + case BTM_PAIR_STATE_WAIT_LOCAL_IOCAPS: + if (btm_cb.pairing_flags & BTM_PAIR_FLAGS_WE_STARTED_DD) + auth_req |= BTM_AUTH_DD_BOND; + + btsnd_hcic_io_cap_req_reply (p_cb->pairing_bda, btm_cb.devcb.loc_io_caps, + BTM_OOB_NONE, auth_req); + btm_sec_change_pairing_state (BTM_PAIR_STATE_IDLE); + break; + + case BTM_PAIR_STATE_WAIT_LOCAL_OOB_RSP: + btsnd_hcic_rem_oob_neg_reply (p_cb->pairing_bda); + btm_sec_change_pairing_state (BTM_PAIR_STATE_IDLE); + break; +#endif /* BTM_OOB_INCLUDED */ + + case BTM_PAIR_STATE_WAIT_DISCONNECT: + /* simple pairing failed. Started a 1-sec timer at simple pairing complete. + * now it's time to tear down the ACL link*/ + if (p_dev_rec == NULL) + { + BTM_TRACE_ERROR ("btm_sec_pairing_timeout() BTM_PAIR_STATE_WAIT_DISCONNECT unknown BDA: %08x%04x", + (p_cb->pairing_bda[0]<<24) + (p_cb->pairing_bda[1]<<16) + (p_cb->pairing_bda[2]<<8) + p_cb->pairing_bda[3], + (p_cb->pairing_bda[4] << 8) + p_cb->pairing_bda[5]); + break; + } + btm_sec_send_hci_disconnect (p_dev_rec, HCI_ERR_AUTH_FAILURE, p_dev_rec->hci_handle); + btm_sec_change_pairing_state (BTM_PAIR_STATE_IDLE); + break; + + case BTM_PAIR_STATE_WAIT_AUTH_COMPLETE: + case BTM_PAIR_STATE_GET_REM_NAME: + /* We need to notify the UI that timeout has happened while waiting for authentication*/ + btm_sec_change_pairing_state (BTM_PAIR_STATE_IDLE); + if (btm_cb.api.p_auth_complete_callback) + { + if (p_dev_rec == NULL) + { + name[0] = 0; + (*btm_cb.api.p_auth_complete_callback) (p_cb->pairing_bda, + NULL, + name, HCI_ERR_CONNECTION_TOUT); + } + else + (*btm_cb.api.p_auth_complete_callback) (p_dev_rec->bd_addr, + p_dev_rec->dev_class, + p_dev_rec->sec_bd_name, HCI_ERR_CONNECTION_TOUT); + } + break; + + default: + BTM_TRACE_WARNING ("btm_sec_pairing_timeout() not processed state: %s", btm_pair_state_descr(btm_cb.pairing_state)); + btm_sec_change_pairing_state (BTM_PAIR_STATE_IDLE); + break; + } +} + +/******************************************************************************* +** +** Function btm_sec_pin_code_request +** +** Description This function is called when controller requests PIN code +** +** Returns Pointer to the record or NULL +** +*******************************************************************************/ +void btm_sec_pin_code_request (UINT8 *p_bda) +{ + tBTM_SEC_DEV_REC *p_dev_rec; + tBTM_CB *p_cb = &btm_cb; + +#ifdef PORCHE_PAIRING_CONFLICT + UINT8 default_pin_code_len = 4; + PIN_CODE default_pin_code = {0x30, 0x30, 0x30, 0x30}; +#endif + BTM_TRACE_EVENT ("btm_sec_pin_code_request() State: %s, BDA:%04x%08x", + btm_pair_state_descr(btm_cb.pairing_state), + (p_bda[0]<<8)+p_bda[1], (p_bda[2]<<24)+(p_bda[3]<<16)+(p_bda[4]<<8)+p_bda[5] ); + + if (btm_cb.pairing_state != BTM_PAIR_STATE_IDLE) + { + if ( (memcmp (p_bda, btm_cb.pairing_bda, BD_ADDR_LEN) == 0) && + (btm_cb.pairing_state == BTM_PAIR_STATE_WAIT_AUTH_COMPLETE) ) + { + /* fake this out - porshe carkit issue - */ +// btm_cb.pairing_state = BTM_PAIR_STATE_IDLE; + if(! btm_cb.pin_code_len_saved) + { + btsnd_hcic_pin_code_neg_reply (p_bda); + return; + } + else + { + btsnd_hcic_pin_code_req_reply (p_bda, btm_cb.pin_code_len_saved, p_cb->pin_code); + return; + } + } + else if ((btm_cb.pairing_state != BTM_PAIR_STATE_WAIT_PIN_REQ) + || memcmp (p_bda, btm_cb.pairing_bda, BD_ADDR_LEN) != 0) + { + BTM_TRACE_WARNING ("btm_sec_pin_code_request() rejected - state: %s", + btm_pair_state_descr(btm_cb.pairing_state)); + +#ifdef PORCHE_PAIRING_CONFLICT + /* reply pin code again due to counter in_rand when local initiates pairing */ + BTM_TRACE_EVENT ("btm_sec_pin_code_request from remote dev. for local initiated pairing"); + if(! btm_cb.pin_code_len_saved) + { + btm_sec_change_pairing_state (BTM_PAIR_STATE_WAIT_AUTH_COMPLETE); + btsnd_hcic_pin_code_req_reply (p_bda, default_pin_code_len, default_pin_code); + } + else + { + btm_sec_change_pairing_state (BTM_PAIR_STATE_WAIT_AUTH_COMPLETE); + btsnd_hcic_pin_code_req_reply (p_bda, btm_cb.pin_code_len_saved, p_cb->pin_code); + } +#else + btsnd_hcic_pin_code_neg_reply (p_bda); +#endif + return; + } + } + + p_dev_rec = btm_find_or_alloc_dev (p_bda); + /* received PIN code request. must be non-sm4 */ + p_dev_rec->sm4 = BTM_SM4_KNOWN; + + if (btm_cb.pairing_state == BTM_PAIR_STATE_IDLE) + { + memcpy (btm_cb.pairing_bda, p_bda, BD_ADDR_LEN); + + btm_cb.pairing_flags = BTM_PAIR_FLAGS_PEER_STARTED_DD; + /* Make sure we reset the trusted mask to help against attacks */ + BTM_SEC_CLR_TRUSTED_DEVICE(p_dev_rec->trusted_mask); + } + + if (!p_cb->pairing_disabled && (p_cb->cfg.pin_type == HCI_PIN_TYPE_FIXED)) + { + BTM_TRACE_EVENT ("btm_sec_pin_code_request fixed pin replying"); + btm_sec_change_pairing_state (BTM_PAIR_STATE_WAIT_AUTH_COMPLETE); + btsnd_hcic_pin_code_req_reply (p_bda, p_cb->cfg.pin_code_len, p_cb->cfg.pin_code); + return; + } + + /* Use the connecting device's CoD for the connection */ + if ( (!memcmp (p_bda, p_cb->connecting_bda, BD_ADDR_LEN)) + && (p_cb->connecting_dc[0] || p_cb->connecting_dc[1] || p_cb->connecting_dc[2]) ) + memcpy (p_dev_rec->dev_class, p_cb->connecting_dc, DEV_CLASS_LEN); + + /* We could have started connection after asking user for the PIN code */ + if (btm_cb.pin_code_len != 0) + { + BTM_TRACE_EVENT ("btm_sec_pin_code_request bonding sending reply"); + btsnd_hcic_pin_code_req_reply (p_bda, btm_cb.pin_code_len, p_cb->pin_code); + +#ifdef PORCHE_PAIRING_CONFLICT + btm_cb.pin_code_len_saved = btm_cb.pin_code_len; +#endif + + /* Mark that we forwarded received from the user PIN code */ + btm_cb.pin_code_len = 0; + + /* We can change mode back right away, that other connection being established */ + /* is not forced to be secure - found a FW issue, so we can not do this + btm_restore_mode(); */ + + btm_sec_change_pairing_state (BTM_PAIR_STATE_WAIT_AUTH_COMPLETE); + } + + /* If pairing disabled OR (no PIN callback and not bonding) */ + /* OR we could not allocate entry in the database reject pairing request */ + else if (p_cb->pairing_disabled + || (p_cb->api.p_pin_callback == NULL) + + /* OR Microsoft keyboard can for some reason try to establish connection */ + /* the only thing we can do here is to shut it up. Normally we will be originator */ + /* for keyboard bonding */ + || (!p_dev_rec->is_originator + && ((p_dev_rec->dev_class[1] & BTM_COD_MAJOR_CLASS_MASK) == BTM_COD_MAJOR_PERIPHERAL) + && (p_dev_rec->dev_class[2] & BTM_COD_MINOR_KEYBOARD)) ) + { + BTM_TRACE_WARNING("btm_sec_pin_code_request(): Pairing disabled:%d; PIN callback:%x, Dev Rec:%x!", + p_cb->pairing_disabled, p_cb->api.p_pin_callback, p_dev_rec); + + btsnd_hcic_pin_code_neg_reply (p_bda); + } + /* Notify upper layer of PIN request and start expiration timer */ + else + { + btm_cb.pin_code_len_saved = 0; + btm_sec_change_pairing_state (BTM_PAIR_STATE_WAIT_LOCAL_PIN); + /* Pin code request can not come at the same time as connection request */ + memcpy (p_cb->connecting_bda, p_bda, BD_ADDR_LEN); + memcpy (p_cb->connecting_dc, p_dev_rec->dev_class, DEV_CLASS_LEN); + + /* Check if the name is known */ + /* Even if name is not known we might not be able to get one */ + /* this is the case when we are already getting something from the */ + /* device, so HCI level is flow controlled */ + /* Also cannot send remote name request while paging, i.e. connection is not completed */ + if (p_dev_rec->sec_flags & BTM_SEC_NAME_KNOWN) + { + BTM_TRACE_EVENT ("btm_sec_pin_code_request going for callback"); + + btm_cb.pairing_flags |= BTM_PAIR_FLAGS_PIN_REQD; + if (p_cb->api.p_pin_callback) { + (*p_cb->api.p_pin_callback) (p_bda, p_dev_rec->dev_class, p_dev_rec->sec_bd_name, + (p_dev_rec->p_cur_service == NULL) ? FALSE + : (p_dev_rec->p_cur_service->security_flags + & BTM_SEC_IN_MIN_16_DIGIT_PIN)); + } + } + else + { + BTM_TRACE_EVENT ("btm_sec_pin_code_request going for remote name"); + + /* We received PIN code request for the device with unknown name */ + /* it is not user friendly just to ask for the PIN without name */ + /* try to get name at first */ + if (!btsnd_hcic_rmt_name_req (p_dev_rec->bd_addr, + HCI_PAGE_SCAN_REP_MODE_R1, + HCI_MANDATARY_PAGE_SCAN_MODE, 0)) + { + p_dev_rec->sec_flags |= BTM_SEC_NAME_KNOWN; + p_dev_rec->sec_bd_name[0] = 'f'; + p_dev_rec->sec_bd_name[1] = '0'; + BTM_TRACE_ERROR ("can not send rmt_name_req?? fake a name and call callback"); + + btm_cb.pairing_flags |= BTM_PAIR_FLAGS_PIN_REQD; + if (p_cb->api.p_pin_callback) + (*p_cb->api.p_pin_callback) (p_bda, p_dev_rec->dev_class, + p_dev_rec->sec_bd_name, (p_dev_rec->p_cur_service == NULL) ? FALSE + : (p_dev_rec->p_cur_service->security_flags + & BTM_SEC_IN_MIN_16_DIGIT_PIN)); + } + } + } + + return; +} + +/******************************************************************************* +** +** Function btm_sec_update_clock_offset +** +** Description This function is called to update clock offset +** +** Returns void +** +*******************************************************************************/ +void btm_sec_update_clock_offset (UINT16 handle, UINT16 clock_offset) +{ + tBTM_SEC_DEV_REC *p_dev_rec; + tBTM_INQ_INFO *p_inq_info; + + if ((p_dev_rec = btm_find_dev_by_handle (handle)) == NULL) + return; + + p_dev_rec->clock_offset = clock_offset | BTM_CLOCK_OFFSET_VALID; + + if ((p_inq_info = BTM_InqDbRead(p_dev_rec->bd_addr)) == NULL) + return; + + p_inq_info->results.clock_offset = clock_offset | BTM_CLOCK_OFFSET_VALID; +} + + +/****************************************************************** +** S T A T I C F U N C T I O N S +*******************************************************************/ + +/******************************************************************************* +** +** Function btm_sec_execute_procedure +** +** Description This function is called to start required security +** procedure. There is a case when multiplexing protocol +** calls this function on the originating side, connection to +** the peer will not be established. This function in this +** case performs only authorization. +** +** Returns BTM_SUCCESS - permission is granted +** BTM_CMD_STARTED - in process +** BTM_NO_RESOURCES - permission declined +** +*******************************************************************************/ +static tBTM_STATUS btm_sec_execute_procedure (tBTM_SEC_DEV_REC *p_dev_rec) +{ + BTM_TRACE_EVENT ("btm_sec_execute_procedure: Required:0x%x Flags:0x%x State:%d", + p_dev_rec->security_required, p_dev_rec->sec_flags, p_dev_rec->sec_state); + + /* There is a chance that we are getting name. Wait until done. */ + if (p_dev_rec->sec_state != 0) + return(BTM_CMD_STARTED); + + /* If any security is required, get the name first */ + if (!(p_dev_rec->sec_flags & BTM_SEC_NAME_KNOWN) + && (p_dev_rec->hci_handle != BTM_SEC_INVALID_HANDLE)) + { + BTM_TRACE_EVENT ("Security Manager: Start get name"); + if (!btm_sec_start_get_name (p_dev_rec)) + { + return(BTM_NO_RESOURCES); + } + return(BTM_CMD_STARTED); + } + + /* If connection is not authenticated and authentication is required */ + /* start authentication and return PENDING to the caller */ + if ((((!(p_dev_rec->sec_flags & BTM_SEC_AUTHENTICATED)) + && (( p_dev_rec->is_originator && (p_dev_rec->security_required & BTM_SEC_OUT_AUTHENTICATE)) + || (!p_dev_rec->is_originator && (p_dev_rec->security_required & BTM_SEC_IN_AUTHENTICATE)))) + || (!(p_dev_rec->sec_flags & BTM_SEC_16_DIGIT_PIN_AUTHED) + && (!p_dev_rec->is_originator + && (p_dev_rec->security_required & BTM_SEC_IN_MIN_16_DIGIT_PIN)))) + && (p_dev_rec->hci_handle != BTM_SEC_INVALID_HANDLE)) + { + /* + * We rely on BTM_SEC_16_DIGIT_PIN_AUTHED being set if MITM is in use, + * as 16 DIGIT is only needed if MITM is not used. Unfortunately, the + * BTM_SEC_AUTHENTICATED is used for both MITM and non-MITM + * authenticated connections, hence we cannot distinguish here. + */ + +#if (L2CAP_UCD_INCLUDED == TRUE) + /* if incoming UCD packet, discard it */ + if ( !p_dev_rec->is_originator && (p_dev_rec->is_ucd == TRUE )) + return(BTM_FAILED_ON_SECURITY); +#endif + + BTM_TRACE_EVENT ("Security Manager: Start authentication"); + + /* + * If we do have a link-key, but we end up here because we need an + * upgrade, then clear the link-key known and authenticated flag before + * restarting authentication. + * WARNING: If the controller has link-key, it is optional and + * recommended for the controller to send a Link_Key_Request. + * In case we need an upgrade, the only alternative would be to delete + * the existing link-key. That could lead to very bad user experience + * or even IOP issues, if a reconnect causes a new connection that + * requires an upgrade. + */ + if ((p_dev_rec->sec_flags & BTM_SEC_LINK_KEY_KNOWN) + && (!(p_dev_rec->sec_flags & BTM_SEC_16_DIGIT_PIN_AUTHED) + && (!p_dev_rec->is_originator && (p_dev_rec->security_required + & BTM_SEC_IN_MIN_16_DIGIT_PIN)))) { + p_dev_rec->sec_flags &= ~(BTM_SEC_LINK_KEY_KNOWN | BTM_SEC_LINK_KEY_AUTHED + | BTM_SEC_AUTHENTICATED); + } + + if (!btm_sec_start_authentication (p_dev_rec)) + { + return(BTM_NO_RESOURCES); + } + return(BTM_CMD_STARTED); + } + + /* If connection is not encrypted and encryption is required */ + /* start encryption and return PENDING to the caller */ + if (!(p_dev_rec->sec_flags & BTM_SEC_ENCRYPTED) + && (( p_dev_rec->is_originator && (p_dev_rec->security_required & BTM_SEC_OUT_ENCRYPT)) + || (!p_dev_rec->is_originator && (p_dev_rec->security_required & BTM_SEC_IN_ENCRYPT))) + && (p_dev_rec->hci_handle != BTM_SEC_INVALID_HANDLE)) + { +#if (L2CAP_UCD_INCLUDED == TRUE) + /* if incoming UCD packet, discard it */ + if ( !p_dev_rec->is_originator && (p_dev_rec->is_ucd == TRUE )) + return(BTM_FAILED_ON_SECURITY); +#endif + + BTM_TRACE_EVENT ("Security Manager: Start encryption"); + + if (!btm_sec_start_encryption (p_dev_rec)) + { + return(BTM_NO_RESOURCES); + } + return(BTM_CMD_STARTED); + } + + if ((p_dev_rec->security_required & BTM_SEC_MODE4_LEVEL4) && + (p_dev_rec->link_key_type != BTM_LKEY_TYPE_AUTH_COMB_P_256)) + { + BTM_TRACE_EVENT("%s: Security Manager: SC only service, but link key type is 0x%02x -", + "security failure", __FUNCTION__, p_dev_rec->link_key_type); + return (BTM_FAILED_ON_SECURITY); + } + + /* If connection is not authorized and authorization is required */ + /* start authorization and return PENDING to the caller */ + if (!(p_dev_rec->sec_flags & BTM_SEC_AUTHORIZED) + && (( p_dev_rec->is_originator && (p_dev_rec->security_required & BTM_SEC_OUT_AUTHORIZE)) + || (!p_dev_rec->is_originator && (p_dev_rec->security_required & BTM_SEC_IN_AUTHORIZE)))) + { + BTM_TRACE_EVENT ("service id:%d, is trusted:%d", + p_dev_rec->p_cur_service->service_id, + (BTM_SEC_IS_SERVICE_TRUSTED(p_dev_rec->trusted_mask, + p_dev_rec->p_cur_service->service_id))); + if ((btm_sec_are_all_trusted(p_dev_rec->trusted_mask) == FALSE) && + (p_dev_rec->p_cur_service->service_id < BTM_SEC_MAX_SERVICES) && + (BTM_SEC_IS_SERVICE_TRUSTED(p_dev_rec->trusted_mask, + p_dev_rec->p_cur_service->service_id) == FALSE)) + { + BTM_TRACE_EVENT ("Security Manager: Start authorization"); + return(btm_sec_start_authorization (p_dev_rec)); + } + } + + /* All required security procedures already established */ + p_dev_rec->security_required &= ~(BTM_SEC_OUT_AUTHORIZE | BTM_SEC_IN_AUTHORIZE | + BTM_SEC_OUT_AUTHENTICATE | BTM_SEC_IN_AUTHENTICATE | + BTM_SEC_OUT_ENCRYPT | BTM_SEC_IN_ENCRYPT | + BTM_SEC_FORCE_MASTER | BTM_SEC_ATTEMPT_MASTER | + BTM_SEC_FORCE_SLAVE | BTM_SEC_ATTEMPT_SLAVE); + + BTM_TRACE_EVENT ("Security Manager: trusted:0x%04x%04x", p_dev_rec->trusted_mask[1], p_dev_rec->trusted_mask[0]); + BTM_TRACE_EVENT ("Security Manager: access granted"); + + return(BTM_SUCCESS); +} + + +/******************************************************************************* +** +** Function btm_sec_start_get_name +** +** Description This function is called to start get name procedure +** +** Returns TRUE if started +** +*******************************************************************************/ +static BOOLEAN btm_sec_start_get_name (tBTM_SEC_DEV_REC *p_dev_rec) +{ + UINT8 tempstate = p_dev_rec->sec_state; + + p_dev_rec->sec_state = BTM_SEC_STATE_GETTING_NAME; + + /* Device should be connected, no need to provide correct page params */ + /* 0 and NULL are as timeout and callback params because they are not used in security get name case */ + if ((btm_initiate_rem_name (p_dev_rec->bd_addr, NULL, BTM_RMT_NAME_SEC, + 0, NULL)) != BTM_CMD_STARTED) + { + p_dev_rec->sec_state = tempstate; + return(FALSE); + } + + return(TRUE); +} + +/******************************************************************************* +** +** Function btm_sec_start_authentication +** +** Description This function is called to start authentication +** +** Returns TRUE if started +** +*******************************************************************************/ +static BOOLEAN btm_sec_start_authentication (tBTM_SEC_DEV_REC *p_dev_rec) +{ + p_dev_rec->sec_state = BTM_SEC_STATE_AUTHENTICATING; + + return(btsnd_hcic_auth_request (p_dev_rec->hci_handle)); +} + +/******************************************************************************* +** +** Function btm_sec_start_encryption +** +** Description This function is called to start encryption +** +** Returns TRUE if started +** +*******************************************************************************/ +static BOOLEAN btm_sec_start_encryption (tBTM_SEC_DEV_REC *p_dev_rec) +{ + if (!btsnd_hcic_set_conn_encrypt (p_dev_rec->hci_handle, TRUE)) + return(FALSE); + + p_dev_rec->sec_state = BTM_SEC_STATE_ENCRYPTING; + return(TRUE); +} + + +/******************************************************************************* +** +** Function btm_sec_start_authorization +** +** Description This function is called to start authorization +** +** Returns TRUE if started +** +*******************************************************************************/ +static UINT8 btm_sec_start_authorization (tBTM_SEC_DEV_REC *p_dev_rec) +{ + UINT8 result; + UINT8 *p_service_name = NULL; + UINT8 service_id; + + if ((p_dev_rec->sec_flags & BTM_SEC_NAME_KNOWN) + || (p_dev_rec->hci_handle == BTM_SEC_INVALID_HANDLE)) + { + if (!btm_cb.api.p_authorize_callback) + return(BTM_MODE_UNSUPPORTED); + + if (p_dev_rec->p_cur_service) + { +#if BTM_SEC_SERVICE_NAME_LEN > 0 + if (p_dev_rec->is_originator) + p_service_name = p_dev_rec->p_cur_service->orig_service_name; + else + p_service_name = p_dev_rec->p_cur_service->term_service_name; +#endif + service_id = p_dev_rec->p_cur_service->service_id; + } + else + service_id = 0; + + /* Send authorization request if not already sent during this service connection */ + if (p_dev_rec->last_author_service_id == BTM_SEC_NO_LAST_SERVICE_ID + || p_dev_rec->last_author_service_id != service_id) + { + p_dev_rec->sec_state = BTM_SEC_STATE_AUTHORIZING; + result = (*btm_cb.api.p_authorize_callback) (p_dev_rec->bd_addr, + p_dev_rec->dev_class, + p_dev_rec->sec_bd_name, + p_service_name, + service_id, + p_dev_rec->is_originator); + } + + else /* Already authorized once for this L2CAP bringup */ + { + BTM_TRACE_DEBUG ("btm_sec_start_authorization: (Ignoring extra Authorization prompt for service %d)", service_id); + return (BTM_SUCCESS); + } + + if (result == BTM_SUCCESS) + { + p_dev_rec->sec_flags |= BTM_SEC_AUTHORIZED; + + /* Save the currently authorized service in case we are asked again by another multiplexer layer */ + if (!p_dev_rec->is_originator) + p_dev_rec->last_author_service_id = service_id; + + p_dev_rec->sec_state = BTM_SEC_STATE_IDLE; + } + return(result); + } + btm_sec_start_get_name (p_dev_rec); + return(BTM_CMD_STARTED); +} + +/******************************************************************************* +** +** Function btm_sec_are_all_trusted +** +** Description This function is called check if all services are trusted +** +** Returns TRUE if all are trusted, otherwise FALSE +** +*******************************************************************************/ +BOOLEAN btm_sec_are_all_trusted(UINT32 p_mask[]) +{ + UINT32 trusted_inx; + for (trusted_inx = 0; trusted_inx < BTM_SEC_SERVICE_ARRAY_SIZE; trusted_inx++) + { + if (p_mask[trusted_inx] != BTM_SEC_TRUST_ALL) + return(FALSE); + } + + return(TRUE); +} + +/******************************************************************************* +** +** Function btm_sec_find_first_serv +** +** Description Look for the first record in the service database +** with specified PSM +** +** Returns Pointer to the record or NULL +** +*******************************************************************************/ +static tBTM_SEC_SERV_REC *btm_sec_find_first_serv (CONNECTION_TYPE conn_type, UINT16 psm) +{ + tBTM_SEC_SERV_REC *p_serv_rec = &btm_cb.sec_serv_rec[0]; + int i; + BOOLEAN is_originator; + +#if (L2CAP_UCD_INCLUDED == TRUE) + + if ( conn_type & CONNECTION_TYPE_ORIG_MASK ) + is_originator = TRUE; + else + is_originator = FALSE; +#else + is_originator = conn_type; +#endif + + if (is_originator && btm_cb.p_out_serv && btm_cb.p_out_serv->psm == psm) + { + /* If this is outgoing connection and the PSM matches p_out_serv, + * use it as the current service */ + return btm_cb.p_out_serv; + } + + /* otherwise, just find the first record with the specified PSM */ + for (i = 0; i < BTM_SEC_MAX_SERVICE_RECORDS; i++, p_serv_rec++) + { + if ( (p_serv_rec->security_flags & BTM_SEC_IN_USE) && (p_serv_rec->psm == psm) ) + return(p_serv_rec); + } + return(NULL); +} + + +/******************************************************************************* +** +** Function btm_sec_find_next_serv +** +** Description Look for the next record in the service database +** with specified PSM +** +** Returns Pointer to the record or NULL +** +*******************************************************************************/ +static tBTM_SEC_SERV_REC *btm_sec_find_next_serv (tBTM_SEC_SERV_REC *p_cur) +{ + tBTM_SEC_SERV_REC *p_serv_rec = &btm_cb.sec_serv_rec[0]; + int i; + + for (i = 0; i < BTM_SEC_MAX_SERVICE_RECORDS; i++, p_serv_rec++) + { + if ((p_serv_rec->security_flags & BTM_SEC_IN_USE) + && (p_serv_rec->psm == p_cur->psm) ) + { + if (p_cur != p_serv_rec) + { + return(p_serv_rec); + } + } + } + return(NULL); +} + + +/******************************************************************************* +** +** Function btm_sec_find_mx_serv +** +** Description Look for the record in the service database with specified +** PSM and multiplexor channel information +** +** Returns Pointer to the record or NULL +** +*******************************************************************************/ +static tBTM_SEC_SERV_REC *btm_sec_find_mx_serv (UINT8 is_originator, UINT16 psm, + UINT32 mx_proto_id, UINT32 mx_chan_id) +{ + tBTM_SEC_SERV_REC *p_out_serv = btm_cb.p_out_serv; + tBTM_SEC_SERV_REC *p_serv_rec = &btm_cb.sec_serv_rec[0]; + int i; + + BTM_TRACE_DEBUG ("%s()", __func__); + if (is_originator && p_out_serv && p_out_serv->psm == psm + && p_out_serv->mx_proto_id == mx_proto_id + && p_out_serv->orig_mx_chan_id == mx_chan_id) + { + /* If this is outgoing connection and the parameters match p_out_serv, + * use it as the current service */ + return btm_cb.p_out_serv; + } + + /* otherwise, the old way */ + for (i = 0; i < BTM_SEC_MAX_SERVICE_RECORDS; i++, p_serv_rec++) + { + if ((p_serv_rec->security_flags & BTM_SEC_IN_USE) + && (p_serv_rec->psm == psm) + && (p_serv_rec->mx_proto_id == mx_proto_id) + && (( is_originator && (p_serv_rec->orig_mx_chan_id == mx_chan_id)) + || (!is_originator && (p_serv_rec->term_mx_chan_id == mx_chan_id)))) + { + return(p_serv_rec); + } + } + return(NULL); +} + + +/******************************************************************************* +** +** Function btm_sec_collision_timeout +** +** Description Encryption could not start because of the collision +** try to do it again +** +** Returns Pointer to the TLE struct +** +*******************************************************************************/ +static void btm_sec_collision_timeout (TIMER_LIST_ENT *p_tle) +{ + UNUSED(p_tle); + + BTM_TRACE_EVENT ("%s()", __func__); + btm_cb.sec_collision_tle.param = 0; + + tBTM_STATUS status = btm_sec_execute_procedure (btm_cb.p_collided_dev_rec); + + /* If result is pending reply from the user or from the device is pending */ + if (status != BTM_CMD_STARTED) + { + /* There is no next procedure or start of procedure failed, notify the waiting layer */ + btm_sec_dev_rec_cback_event (btm_cb.p_collided_dev_rec, status, FALSE); + } +} + +/******************************************************************************* +** +** Function btm_sec_link_key_request +** +** Description This function is called when controller requests link key +** +** Returns Pointer to the record or NULL +** +*******************************************************************************/ +static void btm_send_link_key_notif (tBTM_SEC_DEV_REC *p_dev_rec) +{ + if (btm_cb.api.p_link_key_callback) + (*btm_cb.api.p_link_key_callback) (p_dev_rec->bd_addr, p_dev_rec->dev_class, + p_dev_rec->sec_bd_name, p_dev_rec->link_key, + p_dev_rec->link_key_type); +} + +/******************************************************************************* +** +** Function BTM_ReadTrustedMask +** +** Description Get trusted mask for the peer device +** +** Parameters: bd_addr - Address of the device +** +** Returns NULL, if the device record is not found. +** otherwise, the trusted mask +** +*******************************************************************************/ +UINT32 * BTM_ReadTrustedMask (BD_ADDR bd_addr) +{ + tBTM_SEC_DEV_REC *p_dev_rec = btm_find_dev (bd_addr); + if (p_dev_rec != NULL) + return(p_dev_rec->trusted_mask); + return NULL; +} + +/******************************************************************************* +** +** Function btm_restore_mode +** +** Description This function returns the security mode to previous setting +** if it was changed during bonding. +** +** +** Parameters: void +** +*******************************************************************************/ +static void btm_restore_mode(void) +{ + if (btm_cb.security_mode_changed) + { + btm_cb.security_mode_changed = FALSE; + BTM_TRACE_DEBUG("%s() Auth enable -> %d", __func__, (btm_cb.security_mode == BTM_SEC_MODE_LINK)); + btsnd_hcic_write_auth_enable ((UINT8)(btm_cb.security_mode == BTM_SEC_MODE_LINK)); + } + + if (btm_cb.pin_type_changed) + { + btm_cb.pin_type_changed = FALSE; + btsnd_hcic_write_pin_type (btm_cb.cfg.pin_type); + } +} + + +/******************************************************************************* +** +** Function btm_sec_find_dev_by_sec_state +** +** Description Look for the record in the device database for the device +** which is being authenticated or encrypted +** +** Returns Pointer to the record or NULL +** +*******************************************************************************/ +tBTM_SEC_DEV_REC *btm_sec_find_dev_by_sec_state (UINT8 state) +{ + tBTM_SEC_DEV_REC *p_dev_rec = &btm_cb.sec_dev_rec[0]; + + for (int i = 0; i < BTM_SEC_MAX_DEVICE_RECORDS; i++, p_dev_rec++) + { + if ((p_dev_rec->sec_flags & BTM_SEC_IN_USE) + && (p_dev_rec->sec_state == state)) + return(p_dev_rec); + } + return(NULL); +} + +/******************************************************************************* +** +** Function btm_sec_change_pairing_state +** +** Description This function is called to change pairing state +** +*******************************************************************************/ +static void btm_sec_change_pairing_state (tBTM_PAIRING_STATE new_state) +{ + tBTM_PAIRING_STATE old_state = btm_cb.pairing_state; + + BTM_TRACE_EVENT ("%s() Old: %s", __func__, btm_pair_state_descr(btm_cb.pairing_state)); + BTM_TRACE_EVENT ("%s() New: %s pairing_flags:0x%x", __func__, + btm_pair_state_descr(new_state), btm_cb.pairing_flags); + + btm_cb.pairing_state = new_state; + + if (new_state == BTM_PAIR_STATE_IDLE) + { + btu_stop_timer (&btm_cb.pairing_tle); + + btm_cb.pairing_flags = 0; + btm_cb.pin_code_len = 0; + + /* Make sure the the lcb shows we are not bonding */ + l2cu_update_lcb_4_bonding (btm_cb.pairing_bda, FALSE); + + btm_restore_mode(); + btm_sec_check_pending_reqs(); + btm_inq_clear_ssp(); + + memset (btm_cb.pairing_bda, 0xFF, BD_ADDR_LEN); + } + else + { + /* If transitionng out of idle, mark the lcb as bonding */ + if (old_state == BTM_PAIR_STATE_IDLE) + l2cu_update_lcb_4_bonding (btm_cb.pairing_bda, TRUE); + + btm_cb.pairing_tle.param = (TIMER_PARAM_TYPE)btm_sec_pairing_timeout; + + btu_start_timer (&btm_cb.pairing_tle, BTU_TTYPE_USER_FUNC, BTM_SEC_TIMEOUT_VALUE); + } +} + + +/******************************************************************************* +** +** Function btm_pair_state_descr +** +** Description Return state description for tracing +** +*******************************************************************************/ +#if (BT_USE_TRACES == TRUE) +static char *btm_pair_state_descr (tBTM_PAIRING_STATE state) +{ +#if (BT_TRACE_VERBOSE == TRUE) + switch (state) + { + case BTM_PAIR_STATE_IDLE: return("IDLE"); + case BTM_PAIR_STATE_GET_REM_NAME: return("GET_REM_NAME"); + case BTM_PAIR_STATE_WAIT_PIN_REQ: return("WAIT_PIN_REQ"); + case BTM_PAIR_STATE_WAIT_LOCAL_PIN: return("WAIT_LOCAL_PIN"); + case BTM_PAIR_STATE_WAIT_NUMERIC_CONFIRM: return("WAIT_NUM_CONFIRM"); + case BTM_PAIR_STATE_KEY_ENTRY: return("KEY_ENTRY"); + case BTM_PAIR_STATE_WAIT_LOCAL_OOB_RSP: return("WAIT_LOCAL_OOB_RSP"); + case BTM_PAIR_STATE_WAIT_LOCAL_IOCAPS: return("WAIT_LOCAL_IOCAPS"); + case BTM_PAIR_STATE_INCOMING_SSP: return("INCOMING_SSP"); + case BTM_PAIR_STATE_WAIT_AUTH_COMPLETE: return("WAIT_AUTH_COMPLETE"); + case BTM_PAIR_STATE_WAIT_DISCONNECT: return("WAIT_DISCONNECT"); + } + + return("???"); +#else + sprintf(btm_cb.state_temp_buffer,"%hhu",state); + + return(btm_cb.state_temp_buffer); +#endif +} +#endif + +/******************************************************************************* +** +** Function btm_sec_dev_rec_cback_event +** +** Description This function calls the callback function with the given +** result and clear the callback function. +** +** Parameters: void +** +*******************************************************************************/ +void btm_sec_dev_rec_cback_event (tBTM_SEC_DEV_REC *p_dev_rec, UINT8 res, BOOLEAN is_le_transport) +{ + tBTM_SEC_CALLBACK *p_callback = p_dev_rec->p_callback; + + if (p_dev_rec->p_callback) + { + p_dev_rec->p_callback = NULL; + +#if BLE_INCLUDED == TRUE + if (is_le_transport) + (*p_callback) (p_dev_rec->ble.pseudo_addr, BT_TRANSPORT_LE, p_dev_rec->p_ref_data, res); + else +#endif + (*p_callback) (p_dev_rec->bd_addr, BT_TRANSPORT_BR_EDR, p_dev_rec->p_ref_data, res); + } + + btm_sec_check_pending_reqs(); +} + +/******************************************************************************* +** +** Function btm_sec_queue_mx_request +** +** Description Return state description for tracing +** +*******************************************************************************/ +static BOOLEAN btm_sec_queue_mx_request (BD_ADDR bd_addr, UINT16 psm, BOOLEAN is_orig, + UINT32 mx_proto_id, UINT32 mx_chan_id, + tBTM_SEC_CALLBACK *p_callback, void *p_ref_data) +{ + tBTM_SEC_QUEUE_ENTRY *p_e = (tBTM_SEC_QUEUE_ENTRY *)GKI_getbuf (sizeof(tBTM_SEC_QUEUE_ENTRY)); + + if (p_e) + { + p_e->psm = psm; + p_e->is_orig = is_orig; + p_e->p_callback = p_callback; + p_e->p_ref_data = p_ref_data; + p_e->mx_proto_id = mx_proto_id; + p_e->mx_chan_id = mx_chan_id; + p_e->transport = BT_TRANSPORT_BR_EDR; + + memcpy (p_e->bd_addr, bd_addr, BD_ADDR_LEN); + + BTM_TRACE_EVENT ("%s() PSM: 0x%04x Is_Orig: %u mx_proto_id: %u mx_chan_id: %u", + __func__, psm, is_orig, mx_proto_id, mx_chan_id); + + GKI_enqueue (&btm_cb.sec_pending_q, p_e); + + return(TRUE); + } + + return(FALSE); +} + +static BOOLEAN btm_sec_check_prefetch_pin (tBTM_SEC_DEV_REC *p_dev_rec) +{ + UINT8 major = (UINT8)(p_dev_rec->dev_class[1] & BTM_COD_MAJOR_CLASS_MASK); + UINT8 minor = (UINT8)(p_dev_rec->dev_class[2] & BTM_COD_MINOR_CLASS_MASK); + BOOLEAN rv = FALSE; + + if ((major == BTM_COD_MAJOR_AUDIO) + && ((minor == BTM_COD_MINOR_CONFM_HANDSFREE) || (minor == BTM_COD_MINOR_CAR_AUDIO)) ) + { + BTM_TRACE_EVENT ("%s() Skipping pre-fetch PIN for carkit COD Major: 0x%02x Minor: 0x%02x", + __func__, major, minor); + + if (btm_cb.security_mode_changed == FALSE) + { + btm_cb.security_mode_changed = TRUE; +#ifdef APPL_AUTH_WRITE_EXCEPTION + if(!(APPL_AUTH_WRITE_EXCEPTION)(p_dev_rec->bd_addr)) +#endif + btsnd_hcic_write_auth_enable (TRUE); + } + } + else + { + btm_sec_change_pairing_state (BTM_PAIR_STATE_WAIT_LOCAL_PIN); + + /* If we got a PIN, use that, else try to get one */ + if (btm_cb.pin_code_len) + { + BTM_PINCodeReply (p_dev_rec->bd_addr, BTM_SUCCESS, btm_cb.pin_code_len, btm_cb.pin_code, p_dev_rec->trusted_mask); + } + else + { + /* pin was not supplied - pre-fetch pin code now */ + if (btm_cb.api.p_pin_callback && ((btm_cb.pairing_flags & BTM_PAIR_FLAGS_PIN_REQD) == 0)) + { + BTM_TRACE_DEBUG("%s() PIN code callback called", __func__); + if (btm_bda_to_acl(p_dev_rec->bd_addr, BT_TRANSPORT_BR_EDR) == NULL) + btm_cb.pairing_flags |= BTM_PAIR_FLAGS_PIN_REQD; + (btm_cb.api.p_pin_callback) (p_dev_rec->bd_addr, p_dev_rec->dev_class, + p_dev_rec->sec_bd_name, (p_dev_rec->p_cur_service == NULL) ? FALSE + : (p_dev_rec->p_cur_service->security_flags + & BTM_SEC_IN_MIN_16_DIGIT_PIN)); + } + } + + rv = TRUE; + } + + return rv; +} + +/******************************************************************************* +** +** Function btm_sec_auth_payload_tout +** +** Description Processes the HCI Autheniticated Payload Timeout Event +** indicating that a packet containing a valid MIC on the +** connection handle was not received within the programmed +** timeout value. (Spec Default is 30 secs, but can be +** changed via the BTM_SecSetAuthPayloadTimeout() function. +** +*******************************************************************************/ +void btm_sec_auth_payload_tout (UINT8 *p, UINT16 hci_evt_len) +{ + UINT16 handle; + + STREAM_TO_UINT16 (handle, p); + handle = HCID_GET_HANDLE (handle); + + /* Will be exposed to upper layers in the future if/when determined necessary */ + BTM_TRACE_ERROR ("%s on handle 0x%02x", __func__, handle); +} + +/******************************************************************************* +** +** Function btm_sec_queue_encrypt_request +** +** Description encqueue encryption request when device has active security +** process pending. +** +*******************************************************************************/ +static BOOLEAN btm_sec_queue_encrypt_request (BD_ADDR bd_addr, tBT_TRANSPORT transport, + tBTM_SEC_CALLBACK *p_callback, void *p_ref_data) +{ + tBTM_SEC_QUEUE_ENTRY *p_e; + p_e = (tBTM_SEC_QUEUE_ENTRY *)GKI_getbuf(sizeof(tBTM_SEC_QUEUE_ENTRY) + 1); + + if (p_e) + { + p_e->psm = 0; /* if PSM 0, encryption request */ + p_e->p_callback = p_callback; + p_e->p_ref_data = (void *)(p_e + 1); + *(UINT8 *)p_e->p_ref_data = *(UINT8 *)(p_ref_data); + p_e->transport = transport; + memcpy(p_e->bd_addr, bd_addr, BD_ADDR_LEN); + GKI_enqueue(&btm_cb.sec_pending_q, p_e); + return TRUE; + } + + return FALSE; +} + +/******************************************************************************* +** +** Function btm_sec_set_peer_sec_caps +** +** Description This function is called to set sm4 and rmt_sec_caps fields +** based on the available peer device features. +** +** Returns void +** +*******************************************************************************/ +void btm_sec_set_peer_sec_caps(tACL_CONN *p_acl_cb, tBTM_SEC_DEV_REC *p_dev_rec) +{ + BD_ADDR rem_bd_addr; + UINT8 *p_rem_bd_addr; + + if ((btm_cb.security_mode == BTM_SEC_MODE_SP || + btm_cb.security_mode == BTM_SEC_MODE_SP_DEBUG || + btm_cb.security_mode == BTM_SEC_MODE_SC) && + HCI_SSP_HOST_SUPPORTED(p_acl_cb->peer_lmp_features[HCI_EXT_FEATURES_PAGE_1])) + { + p_dev_rec->sm4 = BTM_SM4_TRUE; + p_dev_rec->remote_supports_secure_connections = + (HCI_SC_HOST_SUPPORTED(p_acl_cb->peer_lmp_features[HCI_EXT_FEATURES_PAGE_1])); + } + else + { + p_dev_rec->sm4 = BTM_SM4_KNOWN; + p_dev_rec->remote_supports_secure_connections = FALSE; + } + + BTM_TRACE_API("%s: sm4: 0x%02x, rmt_support_for_secure_connections %d", __FUNCTION__, + p_dev_rec->sm4, p_dev_rec->remote_supports_secure_connections); + + + if (p_dev_rec->remote_features_needed) + { + BTM_TRACE_EVENT("%s: Now device in SC Only mode, waiting for peer remote features!", + __FUNCTION__); + p_rem_bd_addr = (UINT8*) rem_bd_addr; + BDADDR_TO_STREAM(p_rem_bd_addr, p_dev_rec->bd_addr); + p_rem_bd_addr = (UINT8*) rem_bd_addr; + btm_io_capabilities_req(p_rem_bd_addr); + p_dev_rec->remote_features_needed = FALSE; + } +} + +/******************************************************************************* +** +** Function btm_sec_clean_pending_req_queue +** +** Description This function cleans up the pending security request when the +** link to the target device dropped. +** +** Returns void +** +*******************************************************************************/ +static void btm_sec_clean_pending_req_queue (BD_ADDR remote_bda, tBT_TRANSPORT transport) +{ + tBTM_SEC_QUEUE_ENTRY *p_e; + BUFFER_Q *bq = &btm_cb.sec_pending_q; + + p_e = (tBTM_SEC_QUEUE_ENTRY *)GKI_getfirst(bq); + + if (p_e != NULL) + { + if (memcmp(p_e->bd_addr, remote_bda, BD_ADDR_LEN) == 0 +#if BLE_INCLUDED == TRUE + && p_e->transport == transport +#endif + ) + { + (*p_e->p_callback) (remote_bda, transport, p_e->p_ref_data, BTM_ERR_PROCESSING); + GKI_remove_from_queue(bq, (void *)p_e); + } + p_e = (tBTM_SEC_QUEUE_ENTRY *) GKI_getnext ((void *)p_e); + } +} + +/******************************************************************************* +** +** Function btm_sec_is_serv_level0 +** +** Description This function is called to check if the service corresponding +** to PSM is security mode 4 level 0 service. +** +** Returns TRUE if the service is security mode 4 level 0 service +** +*******************************************************************************/ +static BOOLEAN btm_sec_is_serv_level0(UINT16 psm) +{ + if (psm == BT_PSM_SDP) + { + BTM_TRACE_DEBUG("%s: PSM: 0x%04x -> mode 4 level 0 service", __FUNCTION__, psm); + return TRUE; + } + return FALSE; +} + +/******************************************************************************* +** +** Function btm_sec_check_pending_enc_req +** +** Description This function is called to send pending encryption callback if +** waiting +** +** Returns void +** +*******************************************************************************/ +static void btm_sec_check_pending_enc_req (tBTM_SEC_DEV_REC *p_dev_rec, tBT_TRANSPORT transport, + UINT8 encr_enable) +{ + tBTM_SEC_QUEUE_ENTRY *p_e; + BUFFER_Q *bq = &btm_cb.sec_pending_q; + UINT8 res = encr_enable ? BTM_SUCCESS : BTM_ERR_PROCESSING; + + p_e = (tBTM_SEC_QUEUE_ENTRY *)GKI_getfirst(bq); + + while (p_e != NULL) + { + if (memcmp(p_e->bd_addr, p_dev_rec->bd_addr, BD_ADDR_LEN) == 0 && p_e->psm == 0 +#if BLE_INCLUDED == TRUE + && p_e->transport == transport +#endif + ) + { +#if BLE_INCLUDED == TRUE + UINT8 sec_act = *(UINT8 *)(p_e->p_ref_data); +#endif + + if (encr_enable == 0 || transport == BT_TRANSPORT_BR_EDR +#if BLE_INCLUDED == TRUE + || (sec_act == BTM_BLE_SEC_ENCRYPT || sec_act == BTM_BLE_SEC_ENCRYPT_NO_MITM) + || (sec_act == BTM_BLE_SEC_ENCRYPT_MITM && p_dev_rec->sec_flags + & BTM_SEC_LE_AUTHENTICATED) +#endif + ) + { + (*p_e->p_callback) (p_dev_rec->bd_addr, transport, p_e->p_ref_data, res); + GKI_remove_from_queue(bq, (void *)p_e); + } + } + p_e = (tBTM_SEC_QUEUE_ENTRY *) GKI_getnext ((void *)p_e); + } +} + +/******************************************************************************* +** +** Function btm_sec_set_serv_level4_flags +** +** Description This function is called to set security mode 4 level 4 flags. +** +** Returns service security requirements updated to include secure +** connections only mode. +** +*******************************************************************************/ +static UINT16 btm_sec_set_serv_level4_flags(UINT16 cur_security, BOOLEAN is_originator) +{ + UINT16 sec_level4_flags = is_originator ? BTM_SEC_OUT_LEVEL4_FLAGS : BTM_SEC_IN_LEVEL4_FLAGS; + + return cur_security | sec_level4_flags; +} + +/******************************************************************************* +** +** Function btm_sec_clear_ble_keys +** +** Description This function is called to clear out the BLE keys. +** Typically when devices are removed in BTM_SecDeleteDevice, +** or when a new BT Link key is generated. +** +** Returns void +** +*******************************************************************************/ +void btm_sec_clear_ble_keys (tBTM_SEC_DEV_REC *p_dev_rec) +{ + + BTM_TRACE_DEBUG ("%s() Clearing BLE Keys", __func__); +#if (SMP_INCLUDED== TRUE) + p_dev_rec->ble.key_type = BTM_LE_KEY_NONE; + memset (&p_dev_rec->ble.keys, 0, sizeof(tBTM_SEC_BLE_KEYS)); + +#if (BLE_PRIVACY_SPT == TRUE) + btm_ble_resolving_list_remove_dev(p_dev_rec); +#endif +#endif +} + +/******************************************************************************* +** +** Function btm_sec_is_a_bonded_dev +** +** Description Is the specified device is a bonded device +** +** Returns TRUE - dev is bonded +** +*******************************************************************************/ +BOOLEAN btm_sec_is_a_bonded_dev (BD_ADDR bda) +{ + + tBTM_SEC_DEV_REC *p_dev_rec= btm_find_dev (bda); + BOOLEAN is_bonded= FALSE; + + if (p_dev_rec && +#if (SMP_INCLUDED == TRUE) + ((p_dev_rec->ble.key_type && (p_dev_rec->sec_flags & BTM_SEC_LE_LINK_KEY_KNOWN))|| +#else + ( +#endif + (p_dev_rec->sec_flags & BTM_SEC_LINK_KEY_KNOWN))) + { + is_bonded = TRUE; + } + BTM_TRACE_DEBUG ("%s() is_bonded=%d", __func__, is_bonded); + return(is_bonded); +} + +/******************************************************************************* +** +** Function btm_sec_is_le_capable_dev +** +** Description Is the specified device is dual mode or LE only device +** +** Returns TRUE - dev is a dual mode +** +*******************************************************************************/ +BOOLEAN btm_sec_is_le_capable_dev (BD_ADDR bda) +{ + tBTM_SEC_DEV_REC *p_dev_rec= btm_find_dev (bda); + BOOLEAN le_capable = FALSE; + +#if (BLE_INCLUDED== TRUE) + if (p_dev_rec && (p_dev_rec->device_type & BT_DEVICE_TYPE_BLE) == BT_DEVICE_TYPE_BLE) + le_capable = TRUE; +#endif + return le_capable; +} + +/******************************************************************************* +** +** Function btm_sec_find_bonded_dev +** +** Description Find a bonded device starting from the specified index +** +** Returns TRUE - found a bonded device +** +*******************************************************************************/ +BOOLEAN btm_sec_find_bonded_dev (UINT8 start_idx, UINT8 *p_found_idx, tBTM_SEC_DEV_REC **p_rec) +{ + BOOLEAN found= FALSE; + +#if (SMP_INCLUDED== TRUE) + tBTM_SEC_DEV_REC *p_dev_rec; + int i; + if (start_idx >= BTM_SEC_MAX_DEVICE_RECORDS) + { + BTM_TRACE_DEBUG ("LE bonded device not found"); + return found; + } + + p_dev_rec = &btm_cb.sec_dev_rec[start_idx]; + for (i = start_idx; i < BTM_SEC_MAX_DEVICE_RECORDS; i++, p_dev_rec++) + { + if (p_dev_rec->ble.key_type || (p_dev_rec->sec_flags & BTM_SEC_LINK_KEY_KNOWN)) + { + *p_found_idx = i; + *p_rec = p_dev_rec; + break; + } + } + BTM_TRACE_DEBUG ("%s() found=%d", __func__, found); +#endif + return(found); +} + +/******************************************************************************* +** +** Function btm_sec_use_smp_br_chnl +** +** Description The function checks if SMP BR connection can be used with +** the peer. +** Is called when authentication for dedicated bonding is +** successfully completed. +** +** Returns TRUE - if SMP BR connection can be used (the link key is +** generated from P-256 and the peer supports Security +** Manager over BR). +** +*******************************************************************************/ +static BOOLEAN btm_sec_use_smp_br_chnl(tBTM_SEC_DEV_REC *p_dev_rec) +{ + UINT32 ext_feat; + UINT8 chnl_mask[L2CAP_FIXED_CHNL_ARRAY_SIZE]; + + BTM_TRACE_DEBUG ("%s() link_key_type = 0x%x", __func__, + p_dev_rec->link_key_type); + + if ((p_dev_rec->link_key_type != BTM_LKEY_TYPE_UNAUTH_COMB_P_256) && + (p_dev_rec->link_key_type != BTM_LKEY_TYPE_AUTH_COMB_P_256)) + return FALSE; + + if (!L2CA_GetPeerFeatures (p_dev_rec->bd_addr, &ext_feat, chnl_mask)) + return FALSE; + + if (!(chnl_mask[0] & L2CAP_FIXED_CHNL_SMP_BR_BIT)) + return FALSE; + + return TRUE; +} + +/******************************************************************************* +** +** Function btm_sec_is_master +** +** Description The function checks if the device is BR/EDR master after +** pairing is completed. +** +** Returns TRUE - if the device is master. +** +*******************************************************************************/ +static BOOLEAN btm_sec_is_master(tBTM_SEC_DEV_REC *p_dev_rec) +{ + tACL_CONN *p= btm_bda_to_acl(p_dev_rec->bd_addr, BT_TRANSPORT_BR_EDR); + return (p && (p->link_role == BTM_ROLE_MASTER)); +} + diff --git a/components/bt/bluedroid/stack/btu/btu_hcif.c b/components/bt/bluedroid/stack/btu/btu_hcif.c new file mode 100755 index 0000000000..80e24e1633 --- /dev/null +++ b/components/bt/bluedroid/stack/btu/btu_hcif.c @@ -0,0 +1,1777 @@ +/****************************************************************************** + * + * Copyright (C) 1999-2012 Broadcom Corporation + * + * 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 functions that interface with the HCI transport. On + * the receive side, it routes events to the appropriate handler, e.g. + * L2CAP, ScoMgr. On the transmit side, it manages the command + * transmission. + * + ******************************************************************************/ + +//#define LOG_TAG "bt_btu_hcif" + +//#include +#include + +#include "gki.h" +#include "bt_types.h" +#include "hcimsgs.h" +#include "btu.h" +#include "l2c_int.h" +#include "btm_api.h" +#include "btm_int.h" +//#include "bt_utils.h" +#include "controller.h" +#include "osi.h" +#include "hci_layer.h" +#include "bt_trace.h" + +#include "thread.h" + +// TODO(zachoverflow): remove this horrible hack +#include "btu.h" +extern fixed_queue_t *btu_hci_msg_queue; + +extern void btm_process_cancel_complete(UINT8 status, UINT8 mode); +extern void btm_ble_test_command_complete(UINT8 *p); + +/********************************************************************************/ +/* L O C A L F U N C T I O N P R O T O T Y P E S */ +/********************************************************************************/ +static void btu_hcif_inquiry_comp_evt (UINT8 *p); +static void btu_hcif_inquiry_result_evt (UINT8 *p); +static void btu_hcif_inquiry_rssi_result_evt (UINT8 *p); +static void btu_hcif_extended_inquiry_result_evt (UINT8 *p); + +static void btu_hcif_connection_comp_evt (UINT8 *p); +static void btu_hcif_connection_request_evt (UINT8 *p); +static void btu_hcif_disconnection_comp_evt (UINT8 *p); +static void btu_hcif_authentication_comp_evt (UINT8 *p); +static void btu_hcif_rmt_name_request_comp_evt (UINT8 *p, UINT16 evt_len); +static void btu_hcif_encryption_change_evt (UINT8 *p); +static void btu_hcif_read_rmt_features_comp_evt (UINT8 *p); +static void btu_hcif_read_rmt_ext_features_comp_evt (UINT8 *p); +static void btu_hcif_read_rmt_version_comp_evt (UINT8 *p); +static void btu_hcif_qos_setup_comp_evt (UINT8 *p); +static void btu_hcif_command_complete_evt (BT_HDR *response, void *context); +static void btu_hcif_command_status_evt (uint8_t status, BT_HDR *command, void *context); +static void btu_hcif_hardware_error_evt (UINT8 *p); +static void btu_hcif_flush_occured_evt (void); +static void btu_hcif_role_change_evt (UINT8 *p); +static void btu_hcif_num_compl_data_pkts_evt (UINT8 *p); +static void btu_hcif_mode_change_evt (UINT8 *p); +static void btu_hcif_pin_code_request_evt (UINT8 *p); +static void btu_hcif_link_key_request_evt (UINT8 *p); +static void btu_hcif_link_key_notification_evt (UINT8 *p); +static void btu_hcif_loopback_command_evt (void); +static void btu_hcif_data_buf_overflow_evt (void); +static void btu_hcif_max_slots_changed_evt (void); +static void btu_hcif_read_clock_off_comp_evt (UINT8 *p); +static void btu_hcif_conn_pkt_type_change_evt (void); +static void btu_hcif_qos_violation_evt (UINT8 *p); +static void btu_hcif_page_scan_mode_change_evt (void); +static void btu_hcif_page_scan_rep_mode_chng_evt (void); +static void btu_hcif_esco_connection_comp_evt(UINT8 *p); +static void btu_hcif_esco_connection_chg_evt(UINT8 *p); + +/* Simple Pairing Events */ +static void btu_hcif_host_support_evt (UINT8 *p); +static void btu_hcif_io_cap_request_evt (UINT8 *p); +static void btu_hcif_io_cap_response_evt (UINT8 *p); +static void btu_hcif_user_conf_request_evt (UINT8 *p); +static void btu_hcif_user_passkey_request_evt (UINT8 *p); +static void btu_hcif_user_passkey_notif_evt (UINT8 *p); +static void btu_hcif_keypress_notif_evt (UINT8 *p); + +#if BTM_OOB_INCLUDED == TRUE +static void btu_hcif_rem_oob_request_evt (UINT8 *p); +#endif + +static void btu_hcif_simple_pair_complete_evt (UINT8 *p); +#if L2CAP_NON_FLUSHABLE_PB_INCLUDED == TRUE +static void btu_hcif_enhanced_flush_complete_evt (void); +#endif + +#if (BTM_SSR_INCLUDED == TRUE) +static void btu_hcif_ssr_evt (UINT8 *p, UINT16 evt_len); +#endif /* BTM_SSR_INCLUDED == TRUE */ + +#if BLE_INCLUDED == TRUE +static void btu_ble_ll_conn_complete_evt (UINT8 *p, UINT16 evt_len); +static void btu_ble_process_adv_pkt (UINT8 *p); +static void btu_ble_read_remote_feat_evt (UINT8 *p); +static void btu_ble_ll_conn_param_upd_evt (UINT8 *p, UINT16 evt_len); +static void btu_ble_proc_ltk_req (UINT8 *p); +static void btu_hcif_encryption_key_refresh_cmpl_evt (UINT8 *p); +static void btu_ble_data_length_change_evt (UINT8 *p, UINT16 evt_len); +#if (BLE_LLT_INCLUDED == TRUE) +static void btu_ble_rc_param_req_evt(UINT8 *p); +#endif +#if (defined BLE_PRIVACY_SPT && BLE_PRIVACY_SPT == TRUE) +static void btu_ble_proc_enhanced_conn_cmpl (UINT8 *p, UINT16 evt_len); +#endif + +#endif + +/******************************************************************************* +** +** Function btu_hcif_process_event +** +** Description This function is called when an event is received from +** the Host Controller. +** +** Returns void +** +*******************************************************************************/ +void btu_hcif_process_event (UNUSED_ATTR UINT8 controller_id, BT_HDR *p_msg) +{ + UINT8 *p = (UINT8 *)(p_msg + 1) + p_msg->offset; + UINT8 hci_evt_code, hci_evt_len; +#if BLE_INCLUDED == TRUE + UINT8 ble_sub_code; +#endif + STREAM_TO_UINT8 (hci_evt_code, p); + STREAM_TO_UINT8 (hci_evt_len, p); + + switch (hci_evt_code) + { + case HCI_INQUIRY_COMP_EVT: + btu_hcif_inquiry_comp_evt (p); + break; + case HCI_INQUIRY_RESULT_EVT: + btu_hcif_inquiry_result_evt (p); + break; + case HCI_INQUIRY_RSSI_RESULT_EVT: + btu_hcif_inquiry_rssi_result_evt (p); + break; + case HCI_EXTENDED_INQUIRY_RESULT_EVT: + btu_hcif_extended_inquiry_result_evt (p); + break; + case HCI_CONNECTION_COMP_EVT: + btu_hcif_connection_comp_evt (p); + break; + case HCI_CONNECTION_REQUEST_EVT: + btu_hcif_connection_request_evt (p); + break; + case HCI_DISCONNECTION_COMP_EVT: + btu_hcif_disconnection_comp_evt (p); + break; + case HCI_AUTHENTICATION_COMP_EVT: + btu_hcif_authentication_comp_evt (p); + break; + case HCI_RMT_NAME_REQUEST_COMP_EVT: + btu_hcif_rmt_name_request_comp_evt (p, hci_evt_len); + break; + case HCI_ENCRYPTION_CHANGE_EVT: + btu_hcif_encryption_change_evt (p); + break; +#if BLE_INCLUDED == TRUE + case HCI_ENCRYPTION_KEY_REFRESH_COMP_EVT: + btu_hcif_encryption_key_refresh_cmpl_evt(p); + break; +#endif + case HCI_READ_RMT_FEATURES_COMP_EVT: + btu_hcif_read_rmt_features_comp_evt (p); + break; + case HCI_READ_RMT_EXT_FEATURES_COMP_EVT: + btu_hcif_read_rmt_ext_features_comp_evt (p); + break; + case HCI_READ_RMT_VERSION_COMP_EVT: + btu_hcif_read_rmt_version_comp_evt (p); + break; + case HCI_QOS_SETUP_COMP_EVT: + btu_hcif_qos_setup_comp_evt (p); + break; + case HCI_COMMAND_COMPLETE_EVT: + //HCI_TRACE_ERROR("%s should not have received a command complete event. " + // "Someone didn't go through the hci transmit_command function.", __func__); + break; + case HCI_COMMAND_STATUS_EVT: + //HCI_TRACE_ERROR("%s should not have received a command status event. " + // "Someone didn't go through the hci transmit_command function.", __func__); + break; + case HCI_HARDWARE_ERROR_EVT: + btu_hcif_hardware_error_evt (p); + break; + case HCI_FLUSH_OCCURED_EVT: + btu_hcif_flush_occured_evt (); + break; + case HCI_ROLE_CHANGE_EVT: + btu_hcif_role_change_evt (p); + break; + case HCI_NUM_COMPL_DATA_PKTS_EVT: + btu_hcif_num_compl_data_pkts_evt (p); + break; + case HCI_MODE_CHANGE_EVT: + btu_hcif_mode_change_evt (p); + break; + case HCI_PIN_CODE_REQUEST_EVT: + btu_hcif_pin_code_request_evt (p); + break; + case HCI_LINK_KEY_REQUEST_EVT: + btu_hcif_link_key_request_evt (p); + break; + case HCI_LINK_KEY_NOTIFICATION_EVT: + btu_hcif_link_key_notification_evt (p); + break; + case HCI_LOOPBACK_COMMAND_EVT: + btu_hcif_loopback_command_evt (); + break; + case HCI_DATA_BUF_OVERFLOW_EVT: + btu_hcif_data_buf_overflow_evt (); + break; + case HCI_MAX_SLOTS_CHANGED_EVT: + btu_hcif_max_slots_changed_evt (); + break; + case HCI_READ_CLOCK_OFF_COMP_EVT: + btu_hcif_read_clock_off_comp_evt (p); + break; + case HCI_CONN_PKT_TYPE_CHANGE_EVT: + btu_hcif_conn_pkt_type_change_evt (); + break; + case HCI_QOS_VIOLATION_EVT: + btu_hcif_qos_violation_evt (p); + break; + case HCI_PAGE_SCAN_MODE_CHANGE_EVT: + btu_hcif_page_scan_mode_change_evt (); + break; + case HCI_PAGE_SCAN_REP_MODE_CHNG_EVT: + btu_hcif_page_scan_rep_mode_chng_evt (); + break; + case HCI_ESCO_CONNECTION_COMP_EVT: + btu_hcif_esco_connection_comp_evt (p); + break; + case HCI_ESCO_CONNECTION_CHANGED_EVT: + btu_hcif_esco_connection_chg_evt (p); + break; +#if (BTM_SSR_INCLUDED == TRUE) + case HCI_SNIFF_SUB_RATE_EVT: + btu_hcif_ssr_evt (p, hci_evt_len); + break; +#endif /* BTM_SSR_INCLUDED == TRUE */ + case HCI_RMT_HOST_SUP_FEAT_NOTIFY_EVT: + btu_hcif_host_support_evt (p); + break; + case HCI_IO_CAPABILITY_REQUEST_EVT: + btu_hcif_io_cap_request_evt (p); + break; + case HCI_IO_CAPABILITY_RESPONSE_EVT: + btu_hcif_io_cap_response_evt (p); + break; + case HCI_USER_CONFIRMATION_REQUEST_EVT: + btu_hcif_user_conf_request_evt (p); + break; + case HCI_USER_PASSKEY_REQUEST_EVT: + btu_hcif_user_passkey_request_evt (p); + break; +#if BTM_OOB_INCLUDED == TRUE + case HCI_REMOTE_OOB_DATA_REQUEST_EVT: + btu_hcif_rem_oob_request_evt (p); + break; +#endif + case HCI_SIMPLE_PAIRING_COMPLETE_EVT: + btu_hcif_simple_pair_complete_evt (p); + break; + case HCI_USER_PASSKEY_NOTIFY_EVT: + btu_hcif_user_passkey_notif_evt (p); + break; + case HCI_KEYPRESS_NOTIFY_EVT: + btu_hcif_keypress_notif_evt (p); + break; +#if L2CAP_NON_FLUSHABLE_PB_INCLUDED == TRUE + case HCI_ENHANCED_FLUSH_COMPLETE_EVT: + btu_hcif_enhanced_flush_complete_evt (); + break; +#endif + +#if (BLE_INCLUDED == TRUE) + case HCI_BLE_EVENT: + STREAM_TO_UINT8 (ble_sub_code, p); + + HCI_TRACE_DEBUG("BLE HCI(id=%d) event = 0x%02x)", hci_evt_code, ble_sub_code); + + switch (ble_sub_code) + { + case HCI_BLE_ADV_PKT_RPT_EVT: /* result of inquiry */ + btu_ble_process_adv_pkt(p); + break; + case HCI_BLE_CONN_COMPLETE_EVT: + btu_ble_ll_conn_complete_evt(p, hci_evt_len); + break; + case HCI_BLE_LL_CONN_PARAM_UPD_EVT: + btu_ble_ll_conn_param_upd_evt(p, hci_evt_len); + break; + case HCI_BLE_READ_REMOTE_FEAT_CMPL_EVT: + btu_ble_read_remote_feat_evt(p); + break; + case HCI_BLE_LTK_REQ_EVT: /* received only at slave device */ + btu_ble_proc_ltk_req(p); + break; +#if (defined BLE_PRIVACY_SPT && BLE_PRIVACY_SPT == TRUE) + case HCI_BLE_ENHANCED_CONN_COMPLETE_EVT: + btu_ble_proc_enhanced_conn_cmpl(p, hci_evt_len); + break; +#endif +#if (BLE_LLT_INCLUDED == TRUE) + case HCI_BLE_RC_PARAM_REQ_EVT: + btu_ble_rc_param_req_evt(p); + break; +#endif + case HCI_BLE_DATA_LENGTH_CHANGE_EVT: + btu_ble_data_length_change_evt(p, hci_evt_len); + break; + } + break; +#endif /* BLE_INCLUDED */ + case HCI_VENDOR_SPECIFIC_EVT: + btm_vendor_specific_evt (p, hci_evt_len); + break; + } +} + + +/******************************************************************************* +** +** Function btu_hcif_send_cmd +** +** Description This function is called to send commands to the Host Controller. +** +** Returns void +** +*******************************************************************************/ +void btu_hcif_send_cmd (UNUSED_ATTR UINT8 controller_id, BT_HDR *p_buf) +{ + if (!p_buf) + return; + + uint16_t opcode; + uint8_t *stream = p_buf->data + p_buf->offset; + void * vsc_callback = NULL; + + STREAM_TO_UINT16(opcode, stream); + + // Eww...horrible hackery here + /* If command was a VSC, then extract command_complete callback */ + if ((opcode & HCI_GRP_VENDOR_SPECIFIC) == HCI_GRP_VENDOR_SPECIFIC +#if BLE_INCLUDED == TRUE + || (opcode == HCI_BLE_RAND) + || (opcode == HCI_BLE_ENCRYPT) +#endif + ) { + vsc_callback = *((void **)(p_buf + 1)); + } + + hci_layer_get_interface()->transmit_command( + p_buf, + btu_hcif_command_complete_evt, + btu_hcif_command_status_evt, + vsc_callback); + +#if (defined(HCILP_INCLUDED) && HCILP_INCLUDED == TRUE) + btu_check_bt_sleep (); +#endif +} + + +/******************************************************************************* +** +** Function btu_hcif_send_host_rdy_for_data +** +** Description This function is called to check if it can send commands +** to the Host Controller. It may be passed the address of +** a packet to send. +** +** Returns void +** +*******************************************************************************/ +void btu_hcif_send_host_rdy_for_data(void) +{ + UINT16 num_pkts[MAX_L2CAP_LINKS + 4]; /* 3 SCO connections */ + UINT16 handles[MAX_L2CAP_LINKS + 4]; + UINT8 num_ents; + + /* Get the L2CAP numbers */ + num_ents = l2c_link_pkts_rcvd (num_pkts, handles); + + /* Get the SCO numbers */ + /* No SCO for now ?? */ + + if (num_ents) + { + btsnd_hcic_host_num_xmitted_pkts (num_ents, handles, num_pkts); + } +} + +/******************************************************************************* +** +** Function btu_hcif_inquiry_comp_evt +** +** Description Process event HCI_INQUIRY_COMP_EVT +** +** Returns void +** +*******************************************************************************/ +static void btu_hcif_inquiry_comp_evt (UINT8 *p) +{ + UINT8 status; + + STREAM_TO_UINT8 (status, p); + + /* Tell inquiry processing that we are done */ + btm_process_inq_complete(status, BTM_BR_INQUIRY_MASK); +} + + +/******************************************************************************* +** +** Function btu_hcif_inquiry_result_evt +** +** Description Process event HCI_INQUIRY_RESULT_EVT +** +** Returns void +** +*******************************************************************************/ +static void btu_hcif_inquiry_result_evt (UINT8 *p) +{ + /* Store results in the cache */ + btm_process_inq_results (p, BTM_INQ_RESULT_STANDARD); +} + +/******************************************************************************* +** +** Function btu_hcif_inquiry_rssi_result_evt +** +** Description Process event HCI_INQUIRY_RSSI_RESULT_EVT +** +** Returns void +** +*******************************************************************************/ +static void btu_hcif_inquiry_rssi_result_evt (UINT8 *p) +{ + /* Store results in the cache */ + btm_process_inq_results (p, BTM_INQ_RESULT_WITH_RSSI); +} + +/******************************************************************************* +** +** Function btu_hcif_extended_inquiry_result_evt +** +** Description Process event HCI_EXTENDED_INQUIRY_RESULT_EVT +** +** Returns void +** +*******************************************************************************/ +static void btu_hcif_extended_inquiry_result_evt (UINT8 *p) +{ + /* Store results in the cache */ + btm_process_inq_results (p, BTM_INQ_RESULT_EXTENDED); +} + +/******************************************************************************* +** +** Function btu_hcif_connection_comp_evt +** +** Description Process event HCI_CONNECTION_COMP_EVT +** +** Returns void +** +*******************************************************************************/ +static void btu_hcif_connection_comp_evt (UINT8 *p) +{ + UINT8 status; + UINT16 handle; + BD_ADDR bda; + UINT8 link_type; + UINT8 enc_mode; +#if BTM_SCO_INCLUDED == TRUE + tBTM_ESCO_DATA esco_data; +#endif + + STREAM_TO_UINT8 (status, p); + STREAM_TO_UINT16 (handle, p); + STREAM_TO_BDADDR (bda, p); + STREAM_TO_UINT8 (link_type, p); + STREAM_TO_UINT8 (enc_mode, p); + + handle = HCID_GET_HANDLE (handle); + + if (link_type == HCI_LINK_TYPE_ACL) + { + btm_sec_connected (bda, handle, status, enc_mode); + + l2c_link_hci_conn_comp (status, handle, bda); + } +#if BTM_SCO_INCLUDED == TRUE + else + { + memset(&esco_data, 0, sizeof(tBTM_ESCO_DATA)); + /* esco_data.link_type = HCI_LINK_TYPE_SCO; already zero */ + memcpy (esco_data.bd_addr, bda, BD_ADDR_LEN); + btm_sco_connected (status, bda, handle, &esco_data); + } +#endif /* BTM_SCO_INCLUDED */ +} + + +/******************************************************************************* +** +** Function btu_hcif_connection_request_evt +** +** Description Process event HCI_CONNECTION_REQUEST_EVT +** +** Returns void +** +*******************************************************************************/ +static void btu_hcif_connection_request_evt (UINT8 *p) +{ + BD_ADDR bda; + DEV_CLASS dc; + UINT8 link_type; + + STREAM_TO_BDADDR (bda, p); + STREAM_TO_DEVCLASS (dc, p); + STREAM_TO_UINT8 (link_type, p); + + /* Pass request to security manager to check connect filters before */ + /* passing request to l2cap */ + if (link_type == HCI_LINK_TYPE_ACL) + { + btm_sec_conn_req (bda, dc); + } +#if BTM_SCO_INCLUDED == TRUE + else + { + btm_sco_conn_req (bda, dc, link_type); + } +#endif /* BTM_SCO_INCLUDED */ +} + + +/******************************************************************************* +** +** Function btu_hcif_disconnection_comp_evt +** +** Description Process event HCI_DISCONNECTION_COMP_EVT +** +** Returns void +** +*******************************************************************************/ +static void btu_hcif_disconnection_comp_evt (UINT8 *p) +{ + UINT16 handle; + UINT8 reason; + + ++p; + STREAM_TO_UINT16 (handle, p); + STREAM_TO_UINT8 (reason, p); + + handle = HCID_GET_HANDLE (handle); + +#if BTM_SCO_INCLUDED == TRUE + /* If L2CAP doesn't know about it, send it to SCO */ + if (!l2c_link_hci_disc_comp (handle, reason)) + btm_sco_removed (handle, reason); +#else + l2c_link_hci_disc_comp (handle, reason); +#endif /* BTM_SCO_INCLUDED */ + + /* Notify security manager */ + btm_sec_disconnected (handle, reason); +} + +/******************************************************************************* +** +** Function btu_hcif_authentication_comp_evt +** +** Description Process event HCI_AUTHENTICATION_COMP_EVT +** +** Returns void +** +*******************************************************************************/ +static void btu_hcif_authentication_comp_evt (UINT8 *p) +{ + UINT8 status; + UINT16 handle; + + STREAM_TO_UINT8 (status, p); + STREAM_TO_UINT16 (handle, p); + + btm_sec_auth_complete (handle, status); +} + + +/******************************************************************************* +** +** Function btu_hcif_rmt_name_request_comp_evt +** +** Description Process event HCI_RMT_NAME_REQUEST_COMP_EVT +** +** Returns void +** +*******************************************************************************/ +static void btu_hcif_rmt_name_request_comp_evt (UINT8 *p, UINT16 evt_len) +{ + UINT8 status; + BD_ADDR bd_addr; + + STREAM_TO_UINT8 (status, p); + STREAM_TO_BDADDR (bd_addr, p); + + evt_len -= (1 + BD_ADDR_LEN); + + btm_process_remote_name (bd_addr, p, evt_len, status); + + btm_sec_rmt_name_request_complete (bd_addr, p, status); +} + + +/******************************************************************************* +** +** Function btu_hcif_encryption_change_evt +** +** Description Process event HCI_ENCRYPTION_CHANGE_EVT +** +** Returns void +** +*******************************************************************************/ +static void btu_hcif_encryption_change_evt (UINT8 *p) +{ + UINT8 status; + UINT16 handle; + UINT8 encr_enable; + + STREAM_TO_UINT8 (status, p); + STREAM_TO_UINT16 (handle, p); + STREAM_TO_UINT8 (encr_enable, p); + + btm_acl_encrypt_change (handle, status, encr_enable); + btm_sec_encrypt_change (handle, status, encr_enable); +} + +/******************************************************************************* +** +** Function btu_hcif_read_rmt_features_comp_evt +** +** Description Process event HCI_READ_RMT_FEATURES_COMP_EVT +** +** Returns void +** +*******************************************************************************/ +static void btu_hcif_read_rmt_features_comp_evt (UINT8 *p) +{ + btm_read_remote_features_complete(p); +} + +/******************************************************************************* +** +** Function btu_hcif_read_rmt_ext_features_comp_evt +** +** Description Process event HCI_READ_RMT_EXT_FEATURES_COMP_EVT +** +** Returns void +** +*******************************************************************************/ +static void btu_hcif_read_rmt_ext_features_comp_evt (UINT8 *p) +{ + UINT8 *p_cur = p; + UINT8 status; + UINT16 handle; + + STREAM_TO_UINT8 (status, p_cur); + + if (status == HCI_SUCCESS) + btm_read_remote_ext_features_complete(p); + else + { + STREAM_TO_UINT16 (handle, p_cur); + btm_read_remote_ext_features_failed(status, handle); + } +} + +/******************************************************************************* +** +** Function btu_hcif_read_rmt_version_comp_evt +** +** Description Process event HCI_READ_RMT_VERSION_COMP_EVT +** +** Returns void +** +*******************************************************************************/ +static void btu_hcif_read_rmt_version_comp_evt (UINT8 *p) +{ + btm_read_remote_version_complete (p); +} + + +/******************************************************************************* +** +** Function btu_hcif_qos_setup_comp_evt +** +** Description Process event HCI_QOS_SETUP_COMP_EVT +** +** Returns void +** +*******************************************************************************/ +static void btu_hcif_qos_setup_comp_evt (UINT8 *p) +{ + UINT8 status; + UINT16 handle; + FLOW_SPEC flow; + + STREAM_TO_UINT8 (status, p); + STREAM_TO_UINT16 (handle, p); + STREAM_TO_UINT8 (flow.qos_flags, p); + STREAM_TO_UINT8 (flow.service_type, p); + STREAM_TO_UINT32 (flow.token_rate, p); + STREAM_TO_UINT32 (flow.peak_bandwidth, p); + STREAM_TO_UINT32 (flow.latency, p); + STREAM_TO_UINT32 (flow.delay_variation, p); + + btm_qos_setup_complete(status, handle, &flow); +} + + +/******************************************************************************* +** +** Function btu_hcif_esco_connection_comp_evt +** +** Description Process event HCI_ESCO_CONNECTION_COMP_EVT +** +** Returns void +** +*******************************************************************************/ +static void btu_hcif_esco_connection_comp_evt (UINT8 *p) +{ +#if BTM_SCO_INCLUDED == TRUE + tBTM_ESCO_DATA data; + UINT16 handle; + BD_ADDR bda; + UINT8 status; + + STREAM_TO_UINT8 (status, p); + STREAM_TO_UINT16 (handle, p); + STREAM_TO_BDADDR (bda, p); + + STREAM_TO_UINT8 (data.link_type, p); + STREAM_TO_UINT8 (data.tx_interval, p); + STREAM_TO_UINT8 (data.retrans_window, p); + STREAM_TO_UINT16 (data.rx_pkt_len, p); + STREAM_TO_UINT16 (data.tx_pkt_len, p); + STREAM_TO_UINT8 (data.air_mode, p); + + memcpy (data.bd_addr, bda, BD_ADDR_LEN); + btm_sco_connected (status, bda, handle, &data); +#endif +} + + +/******************************************************************************* +** +** Function btu_hcif_esco_connection_chg_evt +** +** Description Process event HCI_ESCO_CONNECTION_CHANGED_EVT +** +** Returns void +** +*******************************************************************************/ +static void btu_hcif_esco_connection_chg_evt (UINT8 *p) +{ +#if BTM_SCO_INCLUDED == TRUE + UINT16 handle; + UINT16 tx_pkt_len; + UINT16 rx_pkt_len; + UINT8 status; + UINT8 tx_interval; + UINT8 retrans_window; + + STREAM_TO_UINT8 (status, p); + STREAM_TO_UINT16 (handle, p); + + STREAM_TO_UINT8 (tx_interval, p); + STREAM_TO_UINT8 (retrans_window, p); + STREAM_TO_UINT16 (rx_pkt_len, p); + STREAM_TO_UINT16 (tx_pkt_len, p); + + btm_esco_proc_conn_chg (status, handle, tx_interval, retrans_window, + rx_pkt_len, tx_pkt_len); +#endif +} + +/******************************************************************************* +** +** Function btu_hcif_hdl_command_complete +** +** Description Handle command complete event +** +** Returns void +** +*******************************************************************************/ +static void btu_hcif_hdl_command_complete (UINT16 opcode, UINT8 *p, UINT16 evt_len, + void *p_cplt_cback) +{ + switch (opcode) + { + case HCI_INQUIRY_CANCEL: + /* Tell inquiry processing that we are done */ + btm_process_cancel_complete(HCI_SUCCESS, BTM_BR_INQUIRY_MASK); + break; + case HCI_SET_EVENT_FILTER: + btm_event_filter_complete (p); + break; + + case HCI_DELETE_STORED_LINK_KEY: + btm_delete_stored_link_key_complete (p); + break; + + case HCI_READ_LOCAL_NAME: + btm_read_local_name_complete (p, evt_len); + break; + + case HCI_GET_LINK_QUALITY: + btm_read_link_quality_complete (p); + break; + + case HCI_READ_RSSI: + btm_read_rssi_complete (p); + break; + + case HCI_READ_TRANSMIT_POWER_LEVEL: + btm_read_tx_power_complete(p, FALSE); + break; + + case HCI_CREATE_CONNECTION_CANCEL: + btm_create_conn_cancel_complete(p); + break; + + case HCI_READ_LOCAL_OOB_DATA: +#if BTM_OOB_INCLUDED == TRUE + btm_read_local_oob_complete(p); +#endif + break; + + + case HCI_READ_INQ_TX_POWER_LEVEL: + btm_read_linq_tx_power_complete (p); + break; + +#if (BLE_INCLUDED == TRUE) +/* BLE Commands sComplete*/ + case HCI_BLE_ADD_WHITE_LIST: + btm_ble_add_2_white_list_complete(*p); + break; + + case HCI_BLE_CLEAR_WHITE_LIST: + btm_ble_clear_white_list_complete(p, evt_len); + break; + + case HCI_BLE_REMOVE_WHITE_LIST: + btm_ble_remove_from_white_list_complete(p, evt_len); + break; + + case HCI_BLE_RAND: + case HCI_BLE_ENCRYPT: + btm_ble_rand_enc_complete (p, opcode, (tBTM_RAND_ENC_CB *)p_cplt_cback); + break; + + case HCI_BLE_READ_ADV_CHNL_TX_POWER: + btm_read_tx_power_complete(p, TRUE); + break; + + case HCI_BLE_WRITE_ADV_ENABLE: + btm_ble_write_adv_enable_complete(p); + break; + + case HCI_BLE_CREATE_LL_CONN: + btm_ble_create_ll_conn_complete(*p); + break; + + case HCI_BLE_TRANSMITTER_TEST: + case HCI_BLE_RECEIVER_TEST: + case HCI_BLE_TEST_END: + btm_ble_test_command_complete(p); + break; + +#if (defined BLE_PRIVACY_SPT && BLE_PRIVACY_SPT == TRUE) + case HCI_BLE_ADD_DEV_RESOLVING_LIST: + btm_ble_add_resolving_list_entry_complete(p, evt_len); + break; + + case HCI_BLE_RM_DEV_RESOLVING_LIST: + btm_ble_remove_resolving_list_entry_complete(p, evt_len); + break; + + case HCI_BLE_CLEAR_RESOLVING_LIST: + btm_ble_clear_resolving_list_complete(p, evt_len); + break; + + case HCI_BLE_READ_RESOLVABLE_ADDR_PEER: + btm_ble_read_resolving_list_entry_complete(p, evt_len); + break; + + case HCI_BLE_READ_RESOLVABLE_ADDR_LOCAL: + case HCI_BLE_SET_ADDR_RESOLUTION_ENABLE: + case HCI_BLE_SET_RAND_PRIV_ADDR_TIMOUT: + break; +#endif +#endif /* (BLE_INCLUDED == TRUE) */ + + default: + if ((opcode & HCI_GRP_VENDOR_SPECIFIC) == HCI_GRP_VENDOR_SPECIFIC) + btm_vsc_complete (p, opcode, evt_len, (tBTM_CMPL_CB *)p_cplt_cback); + break; + } +} + +/******************************************************************************* +** +** Function btu_hcif_command_complete_evt +** +** Description Process event HCI_COMMAND_COMPLETE_EVT +** +** Returns void +** +*******************************************************************************/ +static void btu_hcif_command_complete_evt_on_task(BT_HDR *event) +{ + command_complete_hack_t *hack = (command_complete_hack_t *)&event->data[0]; + + command_opcode_t opcode; + uint8_t *stream = hack->response->data + hack->response->offset + 3; // 2 to skip the event headers, 1 to skip the command credits + STREAM_TO_UINT16(opcode, stream); + + btu_hcif_hdl_command_complete( + opcode, + stream, + hack->response->len - 5, // 3 for the command complete headers, 2 for the event headers + hack->context); + + GKI_freebuf(hack->response); + osi_free(event); +} + +static void btu_hcif_command_complete_evt(BT_HDR *response, void *context) +{ + BT_HDR *event = osi_calloc(sizeof(BT_HDR) + sizeof(command_complete_hack_t)); + command_complete_hack_t *hack = (command_complete_hack_t *)&event->data[0]; + + LOG_ERROR("btu_hcif_command_complete_evt\n"); + + hack->callback = btu_hcif_command_complete_evt_on_task; + hack->response = response; + hack->context = context; + + event->event = BTU_POST_TO_TASK_NO_GOOD_HORRIBLE_HACK; + + fixed_queue_enqueue(btu_hci_msg_queue, event); + // ke_event_set(KE_EVENT_BTU_TASK_THREAD); + btu_task_post(); +} + + +/******************************************************************************* +** +** Function btu_hcif_hdl_command_status +** +** Description Handle a command status event +** +** Returns void +** +*******************************************************************************/ +static void btu_hcif_hdl_command_status (UINT16 opcode, UINT8 status, UINT8 *p_cmd, + void *p_vsc_status_cback) +{ + BD_ADDR bd_addr; + UINT16 handle; +#if BTM_SCO_INCLUDED == TRUE + tBTM_ESCO_DATA esco_data; +#endif + + switch (opcode) + { + case HCI_EXIT_SNIFF_MODE: + case HCI_EXIT_PARK_MODE: +#if BTM_SCO_WAKE_PARKED_LINK == TRUE + if (status != HCI_SUCCESS) + { + /* Allow SCO initiation to continue if waiting for change mode event */ + if (p_cmd != NULL) + { + p_cmd++; /* bypass length field */ + STREAM_TO_UINT16 (handle, p_cmd); + btm_sco_chk_pend_unpark (status, handle); + } + } +#endif + /* Case Falls Through */ + + case HCI_HOLD_MODE: + case HCI_SNIFF_MODE: + case HCI_PARK_MODE: + btm_pm_proc_cmd_status(status); + break; + + default: + /* If command failed to start, we may need to tell BTM */ + if (status != HCI_SUCCESS) + { + switch (opcode) + { + case HCI_INQUIRY: + /* Tell inquiry processing that we are done */ + btm_process_inq_complete(status, BTM_BR_INQUIRY_MASK); + break; + + case HCI_RMT_NAME_REQUEST: + /* Tell inquiry processing that we are done */ + btm_process_remote_name (NULL, NULL, 0, status); + + btm_sec_rmt_name_request_complete (NULL, NULL, status); + break; + + case HCI_QOS_SETUP_COMP_EVT: + /* Tell qos setup that we are done */ + btm_qos_setup_complete(status,0,NULL); + break; + + case HCI_SWITCH_ROLE: + /* Tell BTM that the command failed */ + /* read bd addr out of stored command */ + if (p_cmd != NULL) + { + p_cmd++; + STREAM_TO_BDADDR (bd_addr, p_cmd); + btm_acl_role_changed(status, bd_addr, BTM_ROLE_UNDEFINED); + } + else + btm_acl_role_changed(status, NULL, BTM_ROLE_UNDEFINED); + l2c_link_role_changed (NULL, BTM_ROLE_UNDEFINED, HCI_ERR_COMMAND_DISALLOWED); + break; + + case HCI_CREATE_CONNECTION: + /* read bd addr out of stored command */ + if (p_cmd != NULL) + { + p_cmd++; + STREAM_TO_BDADDR (bd_addr, p_cmd); + btm_sec_connected (bd_addr, HCI_INVALID_HANDLE, status, 0); + l2c_link_hci_conn_comp (status, HCI_INVALID_HANDLE, bd_addr); + } + break; + + case HCI_READ_RMT_EXT_FEATURES: + if (p_cmd != NULL) + { + p_cmd++; /* skip command length */ + STREAM_TO_UINT16 (handle, p_cmd); + } + else + handle = HCI_INVALID_HANDLE; + + btm_read_remote_ext_features_failed(status, handle); + break; + + case HCI_AUTHENTICATION_REQUESTED: + /* Device refused to start authentication. That should be treated as authentication failure. */ + btm_sec_auth_complete (BTM_INVALID_HCI_HANDLE, status); + break; + + case HCI_SET_CONN_ENCRYPTION: + /* Device refused to start encryption. That should be treated as encryption failure. */ + btm_sec_encrypt_change (BTM_INVALID_HCI_HANDLE, status, FALSE); + break; + +#if BLE_INCLUDED == TRUE + case HCI_BLE_CREATE_LL_CONN: + btm_ble_create_ll_conn_complete(status); + break; +#endif + +#if BTM_SCO_INCLUDED == TRUE + case HCI_SETUP_ESCO_CONNECTION: + /* read handle out of stored command */ + if (p_cmd != NULL) + { + p_cmd++; + STREAM_TO_UINT16 (handle, p_cmd); + + /* Determine if initial connection failed or is a change of setup */ + if (btm_is_sco_active(handle)) + btm_esco_proc_conn_chg (status, handle, 0, 0, 0, 0); + else + btm_sco_connected (status, NULL, handle, &esco_data); + } + break; +#endif + +/* This is commented out until an upper layer cares about returning event +#if L2CAP_NON_FLUSHABLE_PB_INCLUDED == TRUE + case HCI_ENHANCED_FLUSH: + break; +#endif +*/ + default: + if ((opcode & HCI_GRP_VENDOR_SPECIFIC) == HCI_GRP_VENDOR_SPECIFIC) + btm_vsc_complete (&status, opcode, 1, (tBTM_CMPL_CB *)p_vsc_status_cback); + break; + } + + } + else + { + if ((opcode & HCI_GRP_VENDOR_SPECIFIC) == HCI_GRP_VENDOR_SPECIFIC) + btm_vsc_complete (&status, opcode, 1, (tBTM_CMPL_CB *)p_vsc_status_cback); + } + } +} + +/******************************************************************************* +** +** Function btu_hcif_command_status_evt +** +** Description Process event HCI_COMMAND_STATUS_EVT +** +** Returns void +** +*******************************************************************************/ +static void btu_hcif_command_status_evt_on_task(BT_HDR *event) +{ + command_status_hack_t *hack = (command_status_hack_t *)&event->data[0]; + + command_opcode_t opcode; + uint8_t *stream = hack->command->data + hack->command->offset; + STREAM_TO_UINT16(opcode, stream); + + btu_hcif_hdl_command_status( + opcode, + hack->status, + stream, + hack->context); + + GKI_freebuf(hack->command); + osi_free(event); +} + +static void btu_hcif_command_status_evt(uint8_t status, BT_HDR *command, void *context) +{ + BT_HDR *event = osi_calloc(sizeof(BT_HDR) + sizeof(command_status_hack_t)); + command_status_hack_t *hack = (command_status_hack_t *)&event->data[0]; + + hack->callback = btu_hcif_command_status_evt_on_task; + hack->status = status; + hack->command = command; + hack->context = context; + + event->event = BTU_POST_TO_TASK_NO_GOOD_HORRIBLE_HACK; + + fixed_queue_enqueue(btu_hci_msg_queue, event); + //ke_event_set(KE_EVENT_BTU_TASK_THREAD); + btu_task_post(); +} + +/******************************************************************************* +** +** Function btu_hcif_hardware_error_evt +** +** Description Process event HCI_HARDWARE_ERROR_EVT +** +** Returns void +** +*******************************************************************************/ +static void btu_hcif_hardware_error_evt (UINT8 *p) +{ + HCI_TRACE_ERROR("Ctlr H/w error event - code:0x%x", *p); + + /* If anyone wants device status notifications, give him one. */ + btm_report_device_status (BTM_DEV_STATUS_DOWN); + + /* Reset the controller */ + if (BTM_IsDeviceUp()) + BTM_DeviceReset (NULL); +} + + +/******************************************************************************* +** +** Function btu_hcif_flush_occured_evt +** +** Description Process event HCI_FLUSH_OCCURED_EVT +** +** Returns void +** +*******************************************************************************/ +static void btu_hcif_flush_occured_evt (void) +{ +} + + +/******************************************************************************* +** +** Function btu_hcif_role_change_evt +** +** Description Process event HCI_ROLE_CHANGE_EVT +** +** Returns void +** +*******************************************************************************/ +static void btu_hcif_role_change_evt (UINT8 *p) +{ + UINT8 status; + BD_ADDR bda; + UINT8 role; + + STREAM_TO_UINT8 (status, p); + STREAM_TO_BDADDR (bda, p); + STREAM_TO_UINT8 (role, p); + + l2c_link_role_changed (bda, role, status); + btm_acl_role_changed(status, bda, role); +} + + +/******************************************************************************* +** +** Function btu_hcif_num_compl_data_pkts_evt +** +** Description Process event HCI_NUM_COMPL_DATA_PKTS_EVT +** +** Returns void +** +*******************************************************************************/ +static void btu_hcif_num_compl_data_pkts_evt (UINT8 *p) +{ + /* Process for L2CAP and SCO */ + l2c_link_process_num_completed_pkts (p); + + /* Send on to SCO */ + /*?? No SCO for now */ +} + +/******************************************************************************* +** +** Function btu_hcif_mode_change_evt +** +** Description Process event HCI_MODE_CHANGE_EVT +** +** Returns void +** +*******************************************************************************/ +static void btu_hcif_mode_change_evt (UINT8 *p) +{ + UINT8 status; + UINT16 handle; + UINT8 current_mode; + UINT16 interval; + + STREAM_TO_UINT8 (status, p); + + STREAM_TO_UINT16 (handle, p); + STREAM_TO_UINT8 (current_mode, p); + STREAM_TO_UINT16 (interval, p); +#if BTM_SCO_WAKE_PARKED_LINK == TRUE + btm_sco_chk_pend_unpark (status, handle); +#endif + btm_pm_proc_mode_change (status, handle, current_mode, interval); + +/* +#if (HID_DEV_INCLUDED == TRUE) && (HID_DEV_PM_INCLUDED == TRUE) + hidd_pm_proc_mode_change( status, current_mode, interval ) ; +#endif +*/ +} + +/******************************************************************************* +** +** Function btu_hcif_ssr_evt +** +** Description Process event HCI_SNIFF_SUB_RATE_EVT +** +** Returns void +** +*******************************************************************************/ + #if (BTM_SSR_INCLUDED == TRUE) +static void btu_hcif_ssr_evt (UINT8 *p, UINT16 evt_len) +{ + btm_pm_proc_ssr_evt(p, evt_len); +} + #endif + +/******************************************************************************* +** +** Function btu_hcif_pin_code_request_evt +** +** Description Process event HCI_PIN_CODE_REQUEST_EVT +** +** Returns void +** +*******************************************************************************/ +static void btu_hcif_pin_code_request_evt (UINT8 *p) +{ + BD_ADDR bda; + + STREAM_TO_BDADDR (bda, p); + + /* Tell L2CAP that there was a PIN code request, */ + /* it may need to stretch timeouts */ + l2c_pin_code_request (bda); + + btm_sec_pin_code_request (bda); +} + + +/******************************************************************************* +** +** Function btu_hcif_link_key_request_evt +** +** Description Process event HCI_LINK_KEY_REQUEST_EVT +** +** Returns void +** +*******************************************************************************/ +static void btu_hcif_link_key_request_evt (UINT8 *p) +{ + BD_ADDR bda; + + STREAM_TO_BDADDR (bda, p); + btm_sec_link_key_request (bda); +} + + +/******************************************************************************* +** +** Function btu_hcif_link_key_notification_evt +** +** Description Process event HCI_LINK_KEY_NOTIFICATION_EVT +** +** Returns void +** +*******************************************************************************/ +static void btu_hcif_link_key_notification_evt (UINT8 *p) +{ + BD_ADDR bda; + LINK_KEY key; + UINT8 key_type; + + STREAM_TO_BDADDR (bda, p); + STREAM_TO_ARRAY16 (key, p); + STREAM_TO_UINT8 (key_type, p); + + btm_sec_link_key_notification (bda, key, key_type); +} + + +/******************************************************************************* +** +** Function btu_hcif_loopback_command_evt +** +** Description Process event HCI_LOOPBACK_COMMAND_EVT +** +** Returns void +** +*******************************************************************************/ +static void btu_hcif_loopback_command_evt (void) +{ +} + + +/******************************************************************************* +** +** Function btu_hcif_data_buf_overflow_evt +** +** Description Process event HCI_DATA_BUF_OVERFLOW_EVT +** +** Returns void +** +*******************************************************************************/ +static void btu_hcif_data_buf_overflow_evt (void) +{ +} + + +/******************************************************************************* +** +** Function btu_hcif_max_slots_changed_evt +** +** Description Process event HCI_MAX_SLOTS_CHANGED_EVT +** +** Returns void +** +*******************************************************************************/ +static void btu_hcif_max_slots_changed_evt (void) +{ +} + + +/******************************************************************************* +** +** Function btu_hcif_read_clock_off_comp_evt +** +** Description Process event HCI_READ_CLOCK_OFF_COMP_EVT +** +** Returns void +** +*******************************************************************************/ +static void btu_hcif_read_clock_off_comp_evt (UINT8 *p) +{ + UINT8 status; + UINT16 handle; + UINT16 clock_offset; + + STREAM_TO_UINT8 (status, p); + + /* If failed to get clock offset just drop the result */ + if (status != HCI_SUCCESS) + return; + + STREAM_TO_UINT16 (handle, p); + STREAM_TO_UINT16 (clock_offset, p); + + handle = HCID_GET_HANDLE (handle); + + btm_process_clk_off_comp_evt (handle, clock_offset); + btm_sec_update_clock_offset (handle, clock_offset); +} + + +/******************************************************************************* +** +** Function btu_hcif_conn_pkt_type_change_evt +** +** Description Process event HCI_CONN_PKT_TYPE_CHANGE_EVT +** +** Returns void +** +*******************************************************************************/ +static void btu_hcif_conn_pkt_type_change_evt (void) +{ +} + + +/******************************************************************************* +** +** Function btu_hcif_qos_violation_evt +** +** Description Process event HCI_QOS_VIOLATION_EVT +** +** Returns void +** +*******************************************************************************/ +static void btu_hcif_qos_violation_evt (UINT8 *p) +{ + UINT16 handle; + + STREAM_TO_UINT16 (handle, p); + + handle = HCID_GET_HANDLE (handle); + + + l2c_link_hci_qos_violation (handle); +} + + +/******************************************************************************* +** +** Function btu_hcif_page_scan_mode_change_evt +** +** Description Process event HCI_PAGE_SCAN_MODE_CHANGE_EVT +** +** Returns void +** +*******************************************************************************/ +static void btu_hcif_page_scan_mode_change_evt (void) +{ +} + + +/******************************************************************************* +** +** Function btu_hcif_page_scan_rep_mode_chng_evt +** +** Description Process event HCI_PAGE_SCAN_REP_MODE_CHNG_EVT +** +** Returns void +** +*******************************************************************************/ +static void btu_hcif_page_scan_rep_mode_chng_evt (void) +{ +} + +/********************************************** +** Simple Pairing Events +***********************************************/ + +/******************************************************************************* +** +** Function btu_hcif_host_support_evt +** +** Description Process event HCI_RMT_HOST_SUP_FEAT_NOTIFY_EVT +** +** Returns void +** +*******************************************************************************/ +static void btu_hcif_host_support_evt (UINT8 *p) +{ + btm_sec_rmt_host_support_feat_evt(p); +} + +/******************************************************************************* +** +** Function btu_hcif_io_cap_request_evt +** +** Description Process event HCI_IO_CAPABILITY_REQUEST_EVT +** +** Returns void +** +*******************************************************************************/ +static void btu_hcif_io_cap_request_evt (UINT8 *p) +{ + btm_io_capabilities_req(p); +} + + +/******************************************************************************* +** +** Function btu_hcif_io_cap_response_evt +** +** Description Process event HCI_IO_CAPABILITY_RESPONSE_EVT +** +** Returns void +** +*******************************************************************************/ +static void btu_hcif_io_cap_response_evt (UINT8 *p) +{ + btm_io_capabilities_rsp(p); +} + + +/******************************************************************************* +** +** Function btu_hcif_user_conf_request_evt +** +** Description Process event HCI_USER_CONFIRMATION_REQUEST_EVT +** +** Returns void +** +*******************************************************************************/ +static void btu_hcif_user_conf_request_evt (UINT8 *p) +{ + btm_proc_sp_req_evt(BTM_SP_CFM_REQ_EVT, p); +} + + +/******************************************************************************* +** +** Function btu_hcif_user_passkey_request_evt +** +** Description Process event HCI_USER_PASSKEY_REQUEST_EVT +** +** Returns void +** +*******************************************************************************/ +static void btu_hcif_user_passkey_request_evt (UINT8 *p) +{ + btm_proc_sp_req_evt(BTM_SP_KEY_REQ_EVT, p); +} + +/******************************************************************************* +** +** Function btu_hcif_user_passkey_notif_evt +** +** Description Process event HCI_USER_PASSKEY_NOTIFY_EVT +** +** Returns void +** +*******************************************************************************/ +static void btu_hcif_user_passkey_notif_evt (UINT8 *p) +{ + btm_proc_sp_req_evt(BTM_SP_KEY_NOTIF_EVT, p); +} + +/******************************************************************************* +** +** Function btu_hcif_keypress_notif_evt +** +** Description Process event HCI_KEYPRESS_NOTIFY_EVT +** +** Returns void +** +*******************************************************************************/ +static void btu_hcif_keypress_notif_evt (UINT8 *p) +{ + btm_keypress_notif_evt(p); +} + +/******************************************************************************* +** +** Function btu_hcif_rem_oob_request_evt +** +** Description Process event HCI_REMOTE_OOB_DATA_REQUEST_EVT +** +** Returns void +** +*******************************************************************************/ +#if BTM_OOB_INCLUDED == TRUE +static void btu_hcif_rem_oob_request_evt (UINT8 *p) +{ + btm_rem_oob_req(p); +} +#endif + +/******************************************************************************* +** +** Function btu_hcif_simple_pair_complete_evt +** +** Description Process event HCI_SIMPLE_PAIRING_COMPLETE_EVT +** +** Returns void +** +*******************************************************************************/ +static void btu_hcif_simple_pair_complete_evt (UINT8 *p) +{ + btm_simple_pair_complete(p); +} + +/******************************************************************************* +** +** Function btu_hcif_enhanced_flush_complete_evt +** +** Description Process event HCI_ENHANCED_FLUSH_COMPLETE_EVT +** +** Returns void +** +*******************************************************************************/ +#if L2CAP_NON_FLUSHABLE_PB_INCLUDED == TRUE +static void btu_hcif_enhanced_flush_complete_evt (void) +{ +/* This is empty until an upper layer cares about returning event */ +} +#endif +/********************************************** +** End of Simple Pairing Events +***********************************************/ + + +/********************************************** +** BLE Events +***********************************************/ +#if (defined BLE_INCLUDED) && (BLE_INCLUDED == TRUE) +static void btu_hcif_encryption_key_refresh_cmpl_evt (UINT8 *p) +{ + UINT8 status; + UINT8 enc_enable = 0; + UINT16 handle; + + STREAM_TO_UINT8 (status, p); + STREAM_TO_UINT16 (handle, p); + + if (status == HCI_SUCCESS) enc_enable = 1; + + btm_sec_encrypt_change (handle, status, enc_enable); +} + +static void btu_ble_process_adv_pkt (UINT8 *p) +{ + HCI_TRACE_EVENT("btu_ble_process_adv_pkt"); + + btm_ble_process_adv_pkt(p); +} + +static void btu_ble_ll_conn_complete_evt ( UINT8 *p, UINT16 evt_len) +{ + btm_ble_conn_complete(p, evt_len, FALSE); +} +#if (defined BLE_PRIVACY_SPT && BLE_PRIVACY_SPT == TRUE) +static void btu_ble_proc_enhanced_conn_cmpl( UINT8 *p, UINT16 evt_len) +{ + btm_ble_conn_complete(p, evt_len, TRUE); +} +#endif +static void btu_ble_ll_conn_param_upd_evt (UINT8 *p, UINT16 evt_len) +{ + /* LE connection update has completed successfully as a master. */ + /* We can enable the update request if the result is a success. */ + /* extract the HCI handle first */ + UINT8 status; + UINT16 handle; + + STREAM_TO_UINT8 (status, p); + STREAM_TO_UINT16 (handle, p); + l2cble_process_conn_update_evt(handle, status); +} + +static void btu_ble_read_remote_feat_evt (UINT8 *p) +{ + btm_ble_read_remote_features_complete(p); +} + +static void btu_ble_proc_ltk_req (UINT8 *p) +{ + UINT16 ediv, handle; + UINT8 *pp; + + STREAM_TO_UINT16(handle, p); + pp = p + 8; + STREAM_TO_UINT16(ediv, pp); +#if BLE_INCLUDED == TRUE && SMP_INCLUDED == TRUE + btm_ble_ltk_request(handle, p, ediv); +#endif + /* This is empty until an upper layer cares about returning event */ +} + +static void btu_ble_data_length_change_evt(UINT8 *p, UINT16 evt_len) +{ + UINT16 handle; + UINT16 tx_data_len; + UINT16 rx_data_len; + + if (!controller_get_interface()->supports_ble_packet_extension()) + { + HCI_TRACE_WARNING("%s, request not supported", __FUNCTION__); + return; + } + + STREAM_TO_UINT16(handle, p); + STREAM_TO_UINT16(tx_data_len, p); + p += 2; /* Skip the TxTimer */ + STREAM_TO_UINT16(rx_data_len, p); + + l2cble_process_data_length_change_event(handle, tx_data_len, rx_data_len); +} + +/********************************************** +** End of BLE Events Handler +***********************************************/ +#if (defined BLE_LLT_INCLUDED) && (BLE_LLT_INCLUDED == TRUE) +static void btu_ble_rc_param_req_evt(UINT8 *p) +{ + UINT16 handle; + UINT16 int_min, int_max, latency, timeout; + + STREAM_TO_UINT16(handle, p); + STREAM_TO_UINT16(int_min, p); + STREAM_TO_UINT16(int_max, p); + STREAM_TO_UINT16(latency, p); + STREAM_TO_UINT16(timeout, p); + + l2cble_process_rc_param_request_evt(handle, int_min, int_max, latency, timeout); +} +#endif /* BLE_LLT_INCLUDED */ + +#endif /* BLE_INCLUDED */ + diff --git a/components/bt/bluedroid/stack/btu/btu_init.c b/components/bt/bluedroid/stack/btu/btu_init.c new file mode 100755 index 0000000000..9831263d58 --- /dev/null +++ b/components/bt/bluedroid/stack/btu/btu_init.c @@ -0,0 +1,270 @@ +/****************************************************************************** + * + * Copyright (C) 2000-2012 Broadcom Corporation + * + * 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. + * + ******************************************************************************/ +#include + +#include "bt_defs.h" +#include "bt_target.h" +#include "bt_trace.h" +#include "controller.h" +#include "alarm.h" +#include "fixed_queue.h" +#include "hash_map.h" +#include "hash_functions.h" + +#include "l2c_int.h" +#include "dyn_mem.h" +#include "btu.h" +#include "btm_int.h" + +#if SDP_INCLUDED == TRUE +#include "sdpint.h" +#endif + +#if (BLE_INCLUDED == TRUE) +#include "gatt_api.h" +#include "gatt_int.h" +#if SMP_INCLUDED == TRUE +#include "smp_int.h" +#endif +#endif + +extern fixed_queue_t *btif_msg_queue; + +// Communication queue from bta thread to bt_workqueue. +fixed_queue_t *btu_bta_msg_queue; + +// Communication queue from hci thread to bt_workqueue. +extern fixed_queue_t *btu_hci_msg_queue; + +// General timer queue. +fixed_queue_t *btu_general_alarm_queue; +hash_map_t *btu_general_alarm_hash_map; +pthread_mutex_t btu_general_alarm_lock; +static const size_t BTU_GENERAL_ALARM_HASH_MAP_SIZE = 17; + +// Oneshot timer queue. +fixed_queue_t *btu_oneshot_alarm_queue; +hash_map_t *btu_oneshot_alarm_hash_map; +pthread_mutex_t btu_oneshot_alarm_lock; +static const size_t BTU_ONESHOT_ALARM_HASH_MAP_SIZE = 17; + +// l2cap timer queue. +fixed_queue_t *btu_l2cap_alarm_queue; +hash_map_t *btu_l2cap_alarm_hash_map; +pthread_mutex_t btu_l2cap_alarm_lock; +static const size_t BTU_L2CAP_ALARM_HASH_MAP_SIZE = 17; + +//thread_t *bt_workqueue_thread; +//static const char *BT_WORKQUEUE_NAME = "bt_workqueue"; + +extern void PLATFORM_DisableHciTransport(UINT8 bDisable); + +/***************************************************************************** +** V A R I A B L E S * +******************************************************************************/ +// TODO(cmanton) Move this out of this file +const BD_ADDR BT_BD_ANY = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; +/***************************************************************************** +** +** Function btu_init_core +** +** Description Initialize control block memory for each core component. +** +** +** Returns void +** +******************************************************************************/ +void btu_init_core(void) +{ + /* Initialize the mandatory core stack components */ + btm_init(); + + l2c_init(); + +#if (defined(SDP_INCLUDED) && SDP_INCLUDED == TRUE) + sdp_init(); +#endif + +#if BLE_INCLUDED == TRUE +#if (defined(GATT_INCLUDED) && GATT_INCLUDED == true) + gatt_init(); +#endif +#if (defined(SMP_INCLUDED) && SMP_INCLUDED == TRUE) + SMP_Init(); +#endif + btm_ble_init(); +#endif +} + +/***************************************************************************** +** +** Function btu_free_core +** +** Description Releases control block memory for each core component. +** +** +** Returns void +** +******************************************************************************/ +void btu_free_core(void) +{ + // Free the mandatory core stack components + l2c_free(); + +#if BLE_INCLUDED == TRUE +#if (defined(GATT_INCLUDED) && GATT_INCLUDED == true) + gatt_free(); +#endif +#endif +} + +/***************************************************************************** +** +** Function BTU_StartUp +** +** Description Initializes the BTU control block. +** +** NOTE: Must be called before creating any tasks +** (RPC, BTU, HCIT, APPL, etc.) +** +** Returns void +** +******************************************************************************/ +void BTU_StartUp(void) +{ + memset (&btu_cb, 0, sizeof (tBTU_CB)); + btu_cb.trace_level = HCI_INITIAL_TRACE_LEVEL; + + btu_bta_msg_queue = fixed_queue_new(SIZE_MAX); + if (btu_bta_msg_queue == NULL) + goto error_exit; + + btu_general_alarm_hash_map = hash_map_new(BTU_GENERAL_ALARM_HASH_MAP_SIZE, + hash_function_pointer, NULL, (data_free_fn)osi_alarm_free, NULL); + if (btu_general_alarm_hash_map == NULL) + goto error_exit; + + pthread_mutex_init(&btu_general_alarm_lock, NULL); + + btu_general_alarm_queue = fixed_queue_new(SIZE_MAX); + if (btu_general_alarm_queue == NULL) + goto error_exit; + + btu_oneshot_alarm_hash_map = hash_map_new(BTU_ONESHOT_ALARM_HASH_MAP_SIZE, + hash_function_pointer, NULL, (data_free_fn)osi_alarm_free, NULL); + if (btu_oneshot_alarm_hash_map == NULL) + goto error_exit; + + pthread_mutex_init(&btu_oneshot_alarm_lock, NULL); + + btu_oneshot_alarm_queue = fixed_queue_new(SIZE_MAX); + if (btu_oneshot_alarm_queue == NULL) + goto error_exit; + + btu_l2cap_alarm_hash_map = hash_map_new(BTU_L2CAP_ALARM_HASH_MAP_SIZE, + hash_function_pointer, NULL, (data_free_fn)osi_alarm_free, NULL); + if (btu_l2cap_alarm_hash_map == NULL) + goto error_exit; + + pthread_mutex_init(&btu_l2cap_alarm_lock, NULL); + + btu_l2cap_alarm_queue = fixed_queue_new(SIZE_MAX); + if (btu_l2cap_alarm_queue == NULL) + goto error_exit; + + btu_task_start_up(); + +/* + // Continue startup on bt workqueue thread. + thread_post(bt_workqueue_thread, btu_task_start_up, NULL); +*/ + return; + + error_exit:; + LOG_ERROR("%s Unable to allocate resources for bt_workqueue", __func__); + BTU_ShutDown(); +} + +void BTU_ShutDown(void) { + btu_task_shut_down(); +/* + fixed_queue_free(btu_bta_msg_queue, NULL); +*/ + hash_map_free(btu_general_alarm_hash_map); + pthread_mutex_destroy(&btu_general_alarm_lock); + fixed_queue_free(btu_general_alarm_queue, NULL); + + hash_map_free(btu_oneshot_alarm_hash_map); + pthread_mutex_destroy(&btu_oneshot_alarm_lock); + fixed_queue_free(btu_oneshot_alarm_queue, NULL); + + hash_map_free(btu_l2cap_alarm_hash_map); + pthread_mutex_destroy(&btu_l2cap_alarm_lock); + fixed_queue_free(btu_l2cap_alarm_queue, NULL); + + //thread_free(bt_workqueue_thread); + + btu_bta_msg_queue = NULL; + + btu_general_alarm_hash_map = NULL; + btu_general_alarm_queue = NULL; + + btu_oneshot_alarm_hash_map = NULL; + btu_oneshot_alarm_queue = NULL; + + btu_l2cap_alarm_hash_map = NULL; + btu_l2cap_alarm_queue = NULL; + +// bt_workqueue_thread = NULL; +} + +/***************************************************************************** +** +** Function BTU_BleAclPktSize +** +** Description export the BLE ACL packet size. +** +** Returns UINT16 +** +******************************************************************************/ +UINT16 BTU_BleAclPktSize(void) +{ +#if BLE_INCLUDED == TRUE + return controller_get_interface()->get_acl_packet_size_ble(); +#else + return 0; +#endif +} +/******************************************************************************* +** +** Function btu_uipc_rx_cback +** +** Description +** +** +** Returns void +** +*******************************************************************************/ +/* +void btu_uipc_rx_cback(BT_HDR *p_msg) { + assert(p_msg != NULL); + BT_TRACE(TRACE_LAYER_BTM, TRACE_TYPE_DEBUG, "btu_uipc_rx_cback event 0x%x," + " len %d, offset %d", p_msg->event, p_msg->len, p_msg->offset); + fixed_queue_enqueue(btu_hci_msg_queue, p_msg); +} +*/ diff --git a/components/bt/bluedroid/stack/btu/btu_task.c b/components/bt/bluedroid/stack/btu/btu_task.c new file mode 100755 index 0000000000..5ae1399045 --- /dev/null +++ b/components/bt/bluedroid/stack/btu/btu_task.c @@ -0,0 +1,734 @@ +/****************************************************************************** + * + * Copyright (C) 1999-2012 Broadcom Corporation + * + * 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. + * + ******************************************************************************/ +#include + + +#include "alarm.h" +#include "thread.h" +#include "bt_target.h" +#include "bt_trace.h" +#include "bt_types.h" +#include "allocator.h" +#include "btm_api.h" +#include "btm_int.h" +#include "btu.h" +#include "fixed_queue.h" +#include "gki.h" +#include "hash_map.h" +#include "hcimsgs.h" +#include "l2c_int.h" +#include "osi.h" +#if (defined(SDP_INCLUDED) && SDP_INCLUDED == TRUE) +#include "sdpint.h" +#endif + +#if (defined(RFCOMM_INCLUDED) && RFCOMM_INCLUDED == TRUE) +#include "port_api.h" +#include "port_ext.h" +#endif + +#if (defined(GAP_INCLUDED) && GAP_INCLUDED == TRUE) +#include "gap_int.h" +#endif + +#if (defined(BNEP_INCLUDED) && BNEP_INCLUDED == TRUE) +#include "bnep_int.h" +#endif + +#if (defined(PAN_INCLUDED) && PAN_INCLUDED == TRUE) +#include "pan_int.h" +#endif + +#if (defined(HID_HOST_INCLUDED) && HID_HOST_INCLUDED == TRUE ) +#include "hidh_int.h" +#endif + +#if (defined(AVDT_INCLUDED) && AVDT_INCLUDED == TRUE) +#include "avdt_int.h" +#else +extern void avdt_rcv_sync_info (BT_HDR *p_buf); +#endif + +#if (defined(MCA_INCLUDED) && MCA_INCLUDED == TRUE) +#include "mca_api.h" +#include "mca_defs.h" +#include "mca_int.h" +#endif + +#if (defined(BTA_INCLUDED) && BTA_INCLUDED == TRUE) +#include "bta_sys.h" +#endif + +#if (BLE_INCLUDED == TRUE) +#include "gatt_int.h" +#if (SMP_INCLUDED == TRUE) +#include "smp_int.h" +#endif +#include "btm_ble_int.h" +#endif + +#if (defined(BT_APP_DEMO) && BT_APP_DEMO == TRUE) +#include "bt_app_common.h" +#endif + +extern void BTE_InitStack(void); + +/* Define BTU storage area +*/ +#if BTU_DYNAMIC_MEMORY == FALSE +tBTU_CB btu_cb; +#endif + +static xTaskHandle xBtuTaskHandle; +static xQueueHandle xBtuQueue; + + +// Communication queue between btu_task and bta. +extern fixed_queue_t *btu_bta_msg_queue; + +// alarm queue between btu_task and bta +extern fixed_queue_t *btu_bta_alarm_queue; + +// Communication queue between btu_task and hci. +extern fixed_queue_t *btu_hci_msg_queue; + +// General timer queue. +extern fixed_queue_t *btu_general_alarm_queue; +extern hash_map_t *btu_general_alarm_hash_map; +extern pthread_mutex_t btu_general_alarm_lock; + +// Oneshot timer queue. +extern fixed_queue_t *btu_oneshot_alarm_queue; +extern hash_map_t *btu_oneshot_alarm_hash_map; +extern pthread_mutex_t btu_oneshot_alarm_lock; + +// l2cap timer queue. +extern fixed_queue_t *btu_l2cap_alarm_queue; +extern hash_map_t *btu_l2cap_alarm_hash_map; +extern pthread_mutex_t btu_l2cap_alarm_lock; + +extern fixed_queue_t *event_queue; +//extern fixed_queue_t *btif_msg_queue; + +//extern thread_t *bt_workqueue_thread; + +/* Define a function prototype to allow a generic timeout handler */ +typedef void (tUSER_TIMEOUT_FUNC) (TIMER_LIST_ENT *p_tle); + +static void btu_l2cap_alarm_process(TIMER_LIST_ENT *p_tle); +static void btu_general_alarm_process(TIMER_LIST_ENT *p_tle); +static void btu_hci_msg_process(BT_HDR *p_msg); + +#if (defined(BTA_INCLUDED) && BTA_INCLUDED == TRUE) +static void btu_bta_alarm_process(TIMER_LIST_ENT *p_tle); +#endif + +void btu_hci_msg_ready(fixed_queue_t *queue) { + BT_HDR *p_msg; + + while (!fixed_queue_is_empty(queue)) { + p_msg = (BT_HDR *)fixed_queue_dequeue(queue); + btu_hci_msg_process(p_msg); + } +} + +void btu_general_alarm_ready(fixed_queue_t *queue) { + TIMER_LIST_ENT *p_tle; + + while (!fixed_queue_is_empty(queue)) { + p_tle = (TIMER_LIST_ENT *)fixed_queue_dequeue(queue); + btu_general_alarm_process(p_tle); + } +} + +void btu_oneshot_alarm_ready(fixed_queue_t *queue) { + TIMER_LIST_ENT *p_tle; + + while (!fixed_queue_is_empty(queue)) { + p_tle = (TIMER_LIST_ENT *)fixed_queue_dequeue(queue); + btu_general_alarm_process(p_tle); + + switch (p_tle->event) { +#if (defined(BLE_INCLUDED) && BLE_INCLUDED == TRUE) + case BTU_TTYPE_BLE_RANDOM_ADDR: + btm_ble_timeout(p_tle); + break; +#endif + case BTU_TTYPE_USER_FUNC: + { + tUSER_TIMEOUT_FUNC *p_uf = (tUSER_TIMEOUT_FUNC *)p_tle->param; + (*p_uf)(p_tle); + } + break; + + default: + // FAIL + LOG_ERROR("Received unexpected oneshot timer event:0x%x\n", + p_tle->event); + break; + } + } +} + +void btu_l2cap_alarm_ready(fixed_queue_t *queue) { + TIMER_LIST_ENT *p_tle; + + while (!fixed_queue_is_empty(queue)) { + p_tle = (TIMER_LIST_ENT *)fixed_queue_dequeue(queue); + btu_l2cap_alarm_process(p_tle); + } +} + +#if (defined(BTA_INCLUDED) && BTA_INCLUDED == TRUE) +void btu_bta_msg_ready(fixed_queue_t *queue) { + BT_HDR *p_msg; + + while (!fixed_queue_is_empty(queue)) { + p_msg = (BT_HDR *)fixed_queue_dequeue(queue); + bta_sys_event(p_msg); + } +} + +void btu_bta_alarm_ready(fixed_queue_t *queue) { + TIMER_LIST_ENT *p_tle; + + while (!fixed_queue_is_empty(queue)) { + p_tle = (TIMER_LIST_ENT *)fixed_queue_dequeue(queue); + btu_bta_alarm_process(p_tle); + } +} +#endif + +static void btu_hci_msg_process(BT_HDR *p_msg) { + /* Determine the input message type. */ + switch (p_msg->event & BT_EVT_MASK) + { + case BTU_POST_TO_TASK_NO_GOOD_HORRIBLE_HACK: // TODO(zachoverflow): remove this + ((post_to_task_hack_t *)(&p_msg->data[0]))->callback(p_msg); + break; + case BT_EVT_TO_BTU_HCI_ACL: + /* All Acl Data goes to L2CAP */ + l2c_rcv_acl_data (p_msg); + break; + + case BT_EVT_TO_BTU_L2C_SEG_XMIT: + /* L2CAP segment transmit complete */ + l2c_link_segments_xmitted (p_msg); + break; + + case BT_EVT_TO_BTU_HCI_SCO: +#if BTM_SCO_INCLUDED == TRUE + btm_route_sco_data (p_msg); + break; +#endif + + case BT_EVT_TO_BTU_HCI_EVT: + btu_hcif_process_event ((UINT8)(p_msg->event & BT_SUB_EVT_MASK), p_msg); + GKI_freebuf(p_msg); + +#if (defined(HCILP_INCLUDED) && HCILP_INCLUDED == TRUE) + /* If host receives events which it doesn't response to, */ + /* host should start idle timer to enter sleep mode. */ + btu_check_bt_sleep (); +#endif + break; + + case BT_EVT_TO_BTU_HCI_CMD: + btu_hcif_send_cmd ((UINT8)(p_msg->event & BT_SUB_EVT_MASK), p_msg); + break; + + default:; + int i = 0; + uint16_t mask = (UINT16) (p_msg->event & BT_EVT_MASK); + BOOLEAN handled = FALSE; + + for (; !handled && i < BTU_MAX_REG_EVENT; i++) + { + if (btu_cb.event_reg[i].event_cb == NULL) + continue; + + if (mask == btu_cb.event_reg[i].event_range) + { + if (btu_cb.event_reg[i].event_cb) + { + btu_cb.event_reg[i].event_cb(p_msg); + handled = TRUE; + } + } + } + + if (handled == FALSE) + GKI_freebuf (p_msg); + + break; + } + +} + +#if (defined(BTA_INCLUDED) && BTA_INCLUDED == TRUE) +static void btu_bta_alarm_process(TIMER_LIST_ENT *p_tle) { + // call timer callback + if (p_tle->p_cback) { + (*p_tle->p_cback)(p_tle); + } else if (p_tle->event) { + BT_HDR *p_msg; + if ((p_msg = (BT_HDR *) GKI_getbuf(sizeof(BT_HDR))) != NULL) { + p_msg->event = p_tle->event; + p_msg->layer_specific = 0; + //GKI_freebuf(p_msg); + bta_sys_sendmsg(p_msg); + } + } +} +#endif + +/***************************************************************************** +** +** Function btu_task_thread_handler +** +** Description Process BTU Task Thread. +******************************************************************************/ +static void btu_task_thread_handler(void *arg) +{ + //ke_event_clear(KE_EVENT_BTU_TASK_THREAD); + + TaskEvt_t *e; + + for (;;) { + if (pdTRUE == xQueueReceive(xBtuQueue, &e, (portTickType)portMAX_DELAY)) { + + if (e->sig == 0xff) { + fixed_queue_process(btu_hci_msg_queue); +#if (defined(BTA_INCLUDED) && BTA_INCLUDED == TRUE) + fixed_queue_process(btu_bta_msg_queue); + fixed_queue_process(btu_bta_alarm_queue); +#endif + fixed_queue_process(btu_general_alarm_queue); + fixed_queue_process(btu_oneshot_alarm_queue); + fixed_queue_process(btu_l2cap_alarm_queue); + } + } + osi_free(e); + } +} + + +void btu_task_post(void) +{ + TaskEvt_t *evt = (TaskEvt_t *)osi_malloc(sizeof(TaskEvt_t)); + if (evt == NULL) + return; + + evt->sig = 0xff; + evt->par = 0; + + if (xQueueSend(xBtuQueue, &evt, 10/portTICK_RATE_MS) != pdTRUE) { + ets_printf("xBtuQueue failed\n"); + } +} + +void btu_task_start_up(void) { +// ke_event_callback_set(KE_EVENT_BTU_TASK_THREAD, &btu_task_thread_handler); + + xBtuQueue = xQueueCreate(15, sizeof(void *)); + xTaskCreate(btu_task_thread_handler, "BtuT", 8192, NULL, configMAX_PRIORITIES - 1, &xBtuTaskHandle); + +#if (defined(BTA_INCLUDED) && BTA_INCLUDED == TRUE) + fixed_queue_register_dequeue(btu_bta_msg_queue, btu_bta_msg_ready); +#endif + + fixed_queue_register_dequeue(btu_hci_msg_queue, btu_hci_msg_ready); + fixed_queue_register_dequeue(btu_general_alarm_queue, btu_general_alarm_ready); + fixed_queue_register_dequeue(btu_oneshot_alarm_queue, btu_oneshot_alarm_ready); + fixed_queue_register_dequeue(btu_l2cap_alarm_queue, btu_l2cap_alarm_ready); + + /* Initialize the mandatory core stack control blocks + (BTU, BTM, L2CAP, and SDP) + */ + btu_init_core(); + + /* Initialize any optional stack components */ + BTE_InitStack(); + +#if (defined(BTA_INCLUDED) && BTA_INCLUDED == TRUE) + bta_sys_init(); +#endif + + // Inform the bt jni thread initialization is ok. + // btif_transfer_context(btif_init_ok, 0, NULL, 0, NULL); +#if (defined(BT_APP_DEMO) && BT_APP_DEMO == TRUE) + bt_app1_transfer_context(bt_app1_init_ok, 0, NULL, 0, NULL); +#endif +} + +void btu_task_shut_down(void) { + fixed_queue_unregister_dequeue(btu_hci_msg_queue); + fixed_queue_unregister_dequeue(btu_general_alarm_queue); + fixed_queue_unregister_dequeue(btu_oneshot_alarm_queue); + fixed_queue_unregister_dequeue(btu_l2cap_alarm_queue); + +#if (defined(BTA_INCLUDED) && BTA_INCLUDED == TRUE) + fixed_queue_unregister_dequeue(btu_bta_msg_queue); + bta_sys_free(); +#endif + + btu_free_core(); + + vTaskDelete(xBtuTaskHandle); + vQueueDelete(xBtuQueue); +} + +/******************************************************************************* +** +** Function btu_start_timer +** +** Description Start a timer for the specified amount of time. +** NOTE: The timeout resolution is in SECONDS! (Even +** though the timer structure field is ticks) +** +** Returns void +** +*******************************************************************************/ +static void btu_general_alarm_process(TIMER_LIST_ENT *p_tle) { + assert(p_tle != NULL); + + switch (p_tle->event) { + case BTU_TTYPE_BTM_DEV_CTL: + btm_dev_timeout(p_tle); + break; + + case BTU_TTYPE_L2CAP_LINK: + case BTU_TTYPE_L2CAP_CHNL: + case BTU_TTYPE_L2CAP_HOLD: + case BTU_TTYPE_L2CAP_INFO: + case BTU_TTYPE_L2CAP_FCR_ACK: + l2c_process_timeout (p_tle); + break; +#if (defined(SDP_INCLUDED) && SDP_INCLUDED == TRUE) + case BTU_TTYPE_SDP: + sdp_conn_timeout ((tCONN_CB *)p_tle->param); + break; +#endif + case BTU_TTYPE_BTM_RMT_NAME: + btm_inq_rmt_name_failed(); + break; +#if (defined(RFCOMM_INCLUDED) && RFCOMM_INCLUDED == TRUE) + case BTU_TTYPE_RFCOMM_MFC: + case BTU_TTYPE_RFCOMM_PORT: + rfcomm_process_timeout (p_tle); + break; +#endif +#if ((defined(BNEP_INCLUDED) && BNEP_INCLUDED == TRUE)) + case BTU_TTYPE_BNEP: + bnep_process_timeout(p_tle); + break; +#endif + + +#if (defined(AVDT_INCLUDED) && AVDT_INCLUDED == TRUE) + case BTU_TTYPE_AVDT_CCB_RET: + case BTU_TTYPE_AVDT_CCB_RSP: + case BTU_TTYPE_AVDT_CCB_IDLE: + case BTU_TTYPE_AVDT_SCB_TC: + avdt_process_timeout(p_tle); + break; +#endif + +#if (defined(HID_HOST_INCLUDED) && HID_HOST_INCLUDED == TRUE) + case BTU_TTYPE_HID_HOST_REPAGE_TO : + hidh_proc_repage_timeout(p_tle); + break; +#endif + +#if (defined(BLE_INCLUDED) && BLE_INCLUDED == TRUE) + case BTU_TTYPE_BLE_INQUIRY: + case BTU_TTYPE_BLE_GAP_LIM_DISC: + case BTU_TTYPE_BLE_RANDOM_ADDR: + case BTU_TTYPE_BLE_GAP_FAST_ADV: + case BTU_TTYPE_BLE_OBSERVE: + btm_ble_timeout(p_tle); + break; + + case BTU_TTYPE_ATT_WAIT_FOR_RSP: + gatt_rsp_timeout(p_tle); + break; + + case BTU_TTYPE_ATT_WAIT_FOR_IND_ACK: + gatt_ind_ack_timeout(p_tle); + break; +#if (defined(SMP_INCLUDED) && SMP_INCLUDED == TRUE) + case BTU_TTYPE_SMP_PAIRING_CMD: + smp_rsp_timeout(p_tle); + break; +#endif + +#endif + +#if (MCA_INCLUDED == TRUE) + case BTU_TTYPE_MCA_CCB_RSP: + mca_process_timeout(p_tle); + break; +#endif + case BTU_TTYPE_USER_FUNC: + { + tUSER_TIMEOUT_FUNC *p_uf = (tUSER_TIMEOUT_FUNC *)p_tle->param; + (*p_uf)(p_tle); + } + break; + + default:; + int i = 0; + BOOLEAN handled = FALSE; + + for (; !handled && i < BTU_MAX_REG_TIMER; i++) + { + if (btu_cb.timer_reg[i].timer_cb == NULL) + continue; + if (btu_cb.timer_reg[i].p_tle == p_tle) + { + btu_cb.timer_reg[i].timer_cb(p_tle); + handled = TRUE; + } + } + break; + } +} + +void btu_general_alarm_cb(void *data) { + assert(data != NULL); + TIMER_LIST_ENT *p_tle = (TIMER_LIST_ENT *)data; + + fixed_queue_enqueue(btu_general_alarm_queue, p_tle); + //ke_event_set(KE_EVENT_BTU_TASK_THREAD); + btu_task_post(); +} + +void btu_start_timer(TIMER_LIST_ENT *p_tle, UINT16 type, UINT32 timeout_sec) { + osi_alarm_t *alarm = NULL; + + assert(p_tle != NULL); + + // Get the alarm for the timer list entry. + pthread_mutex_lock(&btu_general_alarm_lock); + if (!hash_map_has_key(btu_general_alarm_hash_map, p_tle)) { + alarm = osi_alarm_new("btu_gen", btu_general_alarm_cb, (void *)p_tle, 0); + hash_map_set(btu_general_alarm_hash_map, p_tle, alarm); + } + pthread_mutex_unlock(&btu_general_alarm_lock); + + alarm = hash_map_get(btu_general_alarm_hash_map, p_tle); + if (alarm == NULL) { + LOG_ERROR("%s Unable to create alarm", __func__); + return; + } + osi_alarm_cancel(alarm); + + p_tle->event = type; + // NOTE: This value is in seconds but stored in a ticks field. + p_tle->ticks = timeout_sec; + p_tle->in_use = TRUE; + osi_alarm_set(alarm, (period_ms_t)(timeout_sec * 1000)); +} + +/******************************************************************************* +** +** Function btu_stop_timer +** +** Description Stop a timer. +** +** Returns void +** +*******************************************************************************/ +void btu_stop_timer(TIMER_LIST_ENT *p_tle) { + assert(p_tle != NULL); + + if (p_tle->in_use == FALSE) + return; + p_tle->in_use = FALSE; + + // Get the alarm for the timer list entry. + osi_alarm_t *alarm = hash_map_get(btu_general_alarm_hash_map, p_tle); + if (alarm == NULL) { + LOG_WARN("%s Unable to find expected alarm in hashmap", __func__); + return; + } + osi_alarm_cancel(alarm); +} + +#if defined(QUICK_TIMER_TICKS_PER_SEC) && (QUICK_TIMER_TICKS_PER_SEC > 0) +/******************************************************************************* +** +** Function btu_start_quick_timer +** +** Description Start a timer for the specified amount of time in ticks. +** +** Returns void +** +*******************************************************************************/ +static void btu_l2cap_alarm_process(TIMER_LIST_ENT *p_tle) { + assert(p_tle != NULL); + + switch (p_tle->event) { + case BTU_TTYPE_L2CAP_CHNL: /* monitor or retransmission timer */ + case BTU_TTYPE_L2CAP_FCR_ACK: /* ack timer */ + l2c_process_timeout (p_tle); + break; + + default: + break; + } +} + +static void btu_l2cap_alarm_cb(void *data) { + assert(data != NULL); + TIMER_LIST_ENT *p_tle = (TIMER_LIST_ENT *)data; + + fixed_queue_enqueue(btu_l2cap_alarm_queue, p_tle); + //ke_event_set(KE_EVENT_BTU_TASK_THREAD); + btu_task_post(); +} + +void btu_start_quick_timer(TIMER_LIST_ENT *p_tle, UINT16 type, UINT32 timeout_ticks) { + osi_alarm_t *alarm = NULL; + + assert(p_tle != NULL); + + // Get the alarm for the timer list entry. + pthread_mutex_lock(&btu_l2cap_alarm_lock); + if (!hash_map_has_key(btu_l2cap_alarm_hash_map, p_tle)) { + alarm = osi_alarm_new("btu_l2cap", btu_l2cap_alarm_cb, (void *)p_tle, 0); + hash_map_set(btu_l2cap_alarm_hash_map, p_tle, (void *)alarm); + } + pthread_mutex_unlock(&btu_l2cap_alarm_lock); + + alarm = hash_map_get(btu_l2cap_alarm_hash_map, p_tle); + if (alarm == NULL) { + LOG_ERROR("%s Unable to create alarm", __func__); + return; + } + osi_alarm_cancel(alarm); + + p_tle->event = type; + p_tle->ticks = timeout_ticks; + p_tle->in_use = TRUE; + // The quick timer ticks are 100ms long. + osi_alarm_set(alarm, (period_ms_t)(timeout_ticks * 100)); +} + +/******************************************************************************* +** +** Function btu_stop_quick_timer +** +** Description Stop a timer. +** +** Returns void +** +*******************************************************************************/ +void btu_stop_quick_timer(TIMER_LIST_ENT *p_tle) { + assert(p_tle != NULL); + + if (p_tle->in_use == FALSE) + return; + p_tle->in_use = FALSE; + + // Get the alarm for the timer list entry. + osi_alarm_t *alarm = hash_map_get(btu_l2cap_alarm_hash_map, p_tle); + if (alarm == NULL) { + LOG_WARN("%s Unable to find expected alarm in hashmap", __func__); + return; + } + osi_alarm_cancel(alarm); +} +#endif /* defined(QUICK_TIMER_TICKS_PER_SEC) && (QUICK_TIMER_TICKS_PER_SEC > 0) */ + +void btu_oneshot_alarm_cb(void *data) { + assert(data != NULL); + TIMER_LIST_ENT *p_tle = (TIMER_LIST_ENT *)data; + + btu_stop_timer_oneshot(p_tle); + + fixed_queue_enqueue(btu_oneshot_alarm_queue, p_tle); + //ke_event_set(KE_EVENT_BTU_TASK_THREAD); + btu_task_post(); +} + +/* + * Starts a oneshot timer with a timeout in seconds. + */ +void btu_start_timer_oneshot(TIMER_LIST_ENT *p_tle, UINT16 type, UINT32 timeout_sec) { + osi_alarm_t *alarm = NULL; + + assert(p_tle != NULL); + + // Get the alarm for the timer list entry. + pthread_mutex_lock(&btu_oneshot_alarm_lock); + if (!hash_map_has_key(btu_oneshot_alarm_hash_map, p_tle)) { + alarm = osi_alarm_new("btu_oneshot", btu_oneshot_alarm_cb, (void *)p_tle, 0); + hash_map_set(btu_oneshot_alarm_hash_map, p_tle, alarm); + } + pthread_mutex_unlock(&btu_oneshot_alarm_lock); + + alarm = hash_map_get(btu_oneshot_alarm_hash_map, p_tle); + if (alarm == NULL) { + LOG_ERROR("%s Unable to create alarm", __func__); + return; + } + osi_alarm_cancel(alarm); + + p_tle->event = type; + p_tle->in_use = TRUE; + // NOTE: This value is in seconds but stored in a ticks field. + p_tle->ticks = timeout_sec; + osi_alarm_set(alarm, (period_ms_t)(timeout_sec * 1000)); +} + +void btu_stop_timer_oneshot(TIMER_LIST_ENT *p_tle) { + assert(p_tle != NULL); + + if (p_tle->in_use == FALSE) + return; + p_tle->in_use = FALSE; + + // Get the alarm for the timer list entry. + osi_alarm_t *alarm = hash_map_get(btu_oneshot_alarm_hash_map, p_tle); + if (alarm == NULL) { + LOG_WARN("%s Unable to find expected alarm in hashmap", __func__); + return; + } + osi_alarm_cancel(alarm); +} + +#if (defined(HCILP_INCLUDED) && HCILP_INCLUDED == TRUE) +/******************************************************************************* +** +** Function btu_check_bt_sleep +** +** Description This function is called to check if controller can go to sleep. +** +** Returns void +** +*******************************************************************************/ +void btu_check_bt_sleep (void) +{ + // TODO(zachoverflow) take pending commands into account? + if (l2cb.controller_xmit_window == l2cb.num_lm_acl_bufs) + { + bte_main_lpm_allow_bt_device_sleep(); + } +} +#endif diff --git a/components/bt/bluedroid/stack/gap/gap_api.c b/components/bt/bluedroid/stack/gap/gap_api.c new file mode 100755 index 0000000000..10c392ba50 --- /dev/null +++ b/components/bt/bluedroid/stack/gap/gap_api.c @@ -0,0 +1,75 @@ +/****************************************************************************** + * + * Copyright (C) 2009-2013 Broadcom Corporation + * + * 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. + * + ******************************************************************************/ + +#include + +#include "bt_target.h" +//#include "bt_utils.h" +#include "gap_int.h" + +tGAP_CB gap_cb; + +/******************************************************************************* +** +** Function GAP_SetTraceLevel +** +** Description This function sets the trace level for GAP. If called with +** a value of 0xFF, it simply returns the current trace level. +** +** Returns The new or current trace level +** +*******************************************************************************/ +UINT8 GAP_SetTraceLevel (UINT8 new_level) +{ + if (new_level != 0xFF) + gap_cb.trace_level = new_level; + + return (gap_cb.trace_level); +} + +/******************************************************************************* +** +** Function GAP_Init +** +** Description Initializes the control blocks used by GAP. +** +** This routine should not be called except once per +** stack invocation. +** +** Returns Nothing +** +*******************************************************************************/ +void GAP_Init(void) +{ + memset (&gap_cb, 0, sizeof (tGAP_CB)); + +#if defined(GAP_INITIAL_TRACE_LEVEL) + gap_cb.trace_level = GAP_INITIAL_TRACE_LEVEL; +#else + gap_cb.trace_level = BT_TRACE_LEVEL_NONE; /* No traces */ +#endif + +#if GAP_CONN_INCLUDED == TRUE + gap_conn_init(); +#endif + +#if BLE_INCLUDED == TRUE + gap_attr_db_init(); +#endif +} + diff --git a/components/bt/bluedroid/stack/gap/gap_ble.c b/components/bt/bluedroid/stack/gap/gap_ble.c new file mode 100755 index 0000000000..16ef02dad3 --- /dev/null +++ b/components/bt/bluedroid/stack/gap/gap_ble.c @@ -0,0 +1,810 @@ +/****************************************************************************** + * + * Copyright (C) 2009-2013 Broadcom Corporation + * + * 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. + * + ******************************************************************************/ +#include "bt_target.h" + +#if (defined BLE_INCLUDED && BLE_INCLUDED == TRUE) + +#include "bt_defs.h" +#include +#include "gap_int.h" +#include "gap_api.h" +#include "gattdefs.h" +#include "gatt_api.h" +#include "gatt_int.h" +#include "btm_int.h" +#include "hcimsgs.h" + +#define GAP_CHAR_ICON_SIZE 2 +#define GAP_CHAR_DEV_NAME_SIZE 248 +#define GAP_MAX_NUM_INC_SVR 0 +#define GAP_MAX_ATTR_NUM (2 * GAP_MAX_CHAR_NUM + GAP_MAX_NUM_INC_SVR + 1) +#define GAP_MAX_CHAR_VALUE_SIZE (30 + GAP_CHAR_DEV_NAME_SIZE) + + +#ifndef GAP_ATTR_DB_SIZE +#define GAP_ATTR_DB_SIZE GATT_DB_MEM_SIZE(GAP_MAX_NUM_INC_SVR, GAP_MAX_CHAR_NUM, GAP_MAX_CHAR_VALUE_SIZE) +#endif + +static void gap_ble_s_attr_request_cback (UINT16 conn_id, UINT32 trans_id, tGATTS_REQ_TYPE op_code, tGATTS_DATA *p_data); + +/* client connection callback */ +static void gap_ble_c_connect_cback (tGATT_IF gatt_if, BD_ADDR bda, UINT16 conn_id, BOOLEAN connected, + tGATT_DISCONN_REASON reason, tGATT_TRANSPORT transport); +static void gap_ble_c_cmpl_cback (UINT16 conn_id, tGATTC_OPTYPE op, tGATT_STATUS status, tGATT_CL_COMPLETE *p_data); + +static tGATT_CBACK gap_cback = +{ + gap_ble_c_connect_cback, + gap_ble_c_cmpl_cback, + NULL, + NULL, + gap_ble_s_attr_request_cback, + NULL, + NULL +}; + + + +/******************************************************************************* +** +** Function gap_find_clcb_by_bd_addr +** +** Description The function searches all LCB with macthing bd address +** +** Returns total number of clcb found. +** +*******************************************************************************/ +tGAP_CLCB *gap_find_clcb_by_bd_addr(BD_ADDR bda) +{ + UINT8 i_clcb; + tGAP_CLCB *p_clcb = NULL; + + for (i_clcb = 0, p_clcb= gap_cb.clcb; i_clcb < GAP_MAX_CL; i_clcb++, p_clcb++) + { + if (p_clcb->in_use && !memcmp(p_clcb->bda, bda, BD_ADDR_LEN)) + { + return p_clcb; + } + } + + return NULL; +} + +/******************************************************************************* +** +** Function gap_ble_find_clcb_by_conn_id +** +** Description The function searches all LCB with macthing connection ID +** +** Returns total number of clcb found. +** +*******************************************************************************/ +tGAP_CLCB *gap_ble_find_clcb_by_conn_id(UINT16 conn_id) +{ + UINT8 i_clcb; + tGAP_CLCB *p_clcb = NULL; + + for (i_clcb = 0, p_clcb= gap_cb.clcb; i_clcb < GAP_MAX_CL; i_clcb++, p_clcb++) + { + if (p_clcb->in_use && p_clcb->connected && p_clcb->conn_id == conn_id) + { + return p_clcb; + } + } + + return p_clcb; +} + +/******************************************************************************* +** +** Function gap_clcb_alloc +** +** Description The function allocates a GAP connection link control block +** +** Returns NULL if not found. Otherwise pointer to the connection link block. +** +*******************************************************************************/ +tGAP_CLCB *gap_clcb_alloc (BD_ADDR bda) +{ + UINT8 i_clcb = 0; + tGAP_CLCB *p_clcb = NULL; + + for (i_clcb = 0, p_clcb= gap_cb.clcb; i_clcb < GAP_MAX_CL; i_clcb++, p_clcb++) + { + if (!p_clcb->in_use) + { + memset(p_clcb, 0, sizeof(tGAP_CLCB)); + p_clcb->in_use = TRUE; + memcpy (p_clcb->bda, bda, BD_ADDR_LEN); + break; + } + } + return p_clcb; +} + +/******************************************************************************* +** +** Function gap_ble_dealloc_clcb +** +** Description The function clean up the pending request queue in GAP +** +** Returns none +** +*******************************************************************************/ +void gap_ble_dealloc_clcb(tGAP_CLCB *p_clcb) +{ + tGAP_BLE_REQ *p_q; + + while((p_q = (tGAP_BLE_REQ *)GKI_dequeue(&p_clcb->pending_req_q)) != NULL) + { + /* send callback to all pending requests if being removed*/ + if (p_q->p_cback != NULL) + (*p_q->p_cback)(FALSE, p_clcb->bda, 0, NULL); + + GKI_freebuf (p_q); + } + + memset(p_clcb, 0, sizeof(tGAP_CLCB)); +} + +/******************************************************************************* +** +** Function gap_ble_enqueue_request +** +** Description The function enqueue a GAP client request +** +** Returns TRUE is successul; FALSE otherwise +** +*******************************************************************************/ +BOOLEAN gap_ble_enqueue_request (tGAP_CLCB *p_clcb, UINT16 uuid, tGAP_BLE_CMPL_CBACK *p_cback) +{ + tGAP_BLE_REQ *p_q = (tGAP_BLE_REQ *)GKI_getbuf(sizeof(tGAP_BLE_REQ)); + + if (p_q != NULL) + { + p_q->p_cback = p_cback; + p_q->uuid = uuid; + GKI_enqueue(&p_clcb->pending_req_q, p_q); + return TRUE; + } + + return FALSE; +} +/******************************************************************************* +** +** Function gap_ble_dequeue_request +** +** Description The function dequeue a GAP client request if any +** +** Returns TRUE is successul; FALSE otherwise +** +*******************************************************************************/ +BOOLEAN gap_ble_dequeue_request (tGAP_CLCB *p_clcb, UINT16 * p_uuid, tGAP_BLE_CMPL_CBACK **p_cback) +{ + tGAP_BLE_REQ *p_q = (tGAP_BLE_REQ *)GKI_dequeue(&p_clcb->pending_req_q);; + + if (p_q != NULL) + { + *p_cback = p_q->p_cback; + *p_uuid = p_q->uuid; + GKI_freebuf((void *)p_q); + return TRUE; + } + + return FALSE; +} + +/******************************************************************************* +** GAP Attributes Database Request callback +*******************************************************************************/ +tGATT_STATUS gap_read_attr_value (UINT16 handle, tGATT_VALUE *p_value, BOOLEAN is_long) +{ + tGAP_ATTR *p_db_attr = gap_cb.gatt_attr; + UINT8 *p = p_value->value, i; + UINT16 offset = p_value->offset; + UINT8 *p_dev_name = NULL; + + for (i = 0; i < GAP_MAX_CHAR_NUM; i ++, p_db_attr ++) + { + if (handle == p_db_attr->handle) + { + if (p_db_attr->uuid != GATT_UUID_GAP_DEVICE_NAME && + is_long == TRUE) + return GATT_NOT_LONG; + + switch (p_db_attr->uuid) + { + case GATT_UUID_GAP_DEVICE_NAME: + BTM_ReadLocalDeviceName((char **)&p_dev_name); + if (strlen ((char *)p_dev_name) > GATT_MAX_ATTR_LEN) + p_value->len = GATT_MAX_ATTR_LEN; + else + p_value->len = (UINT16)strlen ((char *)p_dev_name); + + if (offset > p_value->len) + return GATT_INVALID_OFFSET; + else + { + p_value->len -= offset; + p_dev_name += offset; + ARRAY_TO_STREAM(p, p_dev_name, p_value->len); + GAP_TRACE_EVENT("GATT_UUID_GAP_DEVICE_NAME len=0x%04x", p_value->len); + } + break; + + case GATT_UUID_GAP_ICON: + UINT16_TO_STREAM(p, p_db_attr->attr_value.icon); + p_value->len = 2; + break; + + case GATT_UUID_GAP_PREF_CONN_PARAM: + UINT16_TO_STREAM(p, p_db_attr->attr_value.conn_param.int_min); /* int_min */ + UINT16_TO_STREAM(p, p_db_attr->attr_value.conn_param.int_max); /* int_max */ + UINT16_TO_STREAM(p, p_db_attr->attr_value.conn_param.latency); /* latency */ + UINT16_TO_STREAM(p, p_db_attr->attr_value.conn_param.sp_tout); /* sp_tout */ + p_value->len =8; + break; + + /* address resolution */ + case GATT_UUID_GAP_CENTRAL_ADDR_RESOL: + UINT8_TO_STREAM(p, p_db_attr->attr_value.addr_resolution); + p_value->len =1; + break; + } + return GATT_SUCCESS; + } + } + return GATT_NOT_FOUND; +} + +/******************************************************************************* +** GAP Attributes Database Read/Read Blob Request process +*******************************************************************************/ +tGATT_STATUS gap_proc_read (tGATTS_REQ_TYPE type, tGATT_READ_REQ *p_data, tGATTS_RSP *p_rsp) +{ + tGATT_STATUS status = GATT_NO_RESOURCES; + UNUSED(type); + + if (p_data->is_long) + p_rsp->attr_value.offset = p_data->offset; + + p_rsp->attr_value.handle = p_data->handle; + + status = gap_read_attr_value(p_data->handle, &p_rsp->attr_value, p_data->is_long); + + return status; +} + +/****************************************************************************** +** +** Function gap_proc_write_req +** +** Description GAP ATT server process a write request. +** +** Returns void. +** +*******************************************************************************/ +UINT8 gap_proc_write_req( tGATTS_REQ_TYPE type, tGATT_WRITE_REQ *p_data) +{ + tGAP_ATTR *p_db_attr = gap_cb.gatt_attr; + UINT8 i; + UNUSED(type); + + for (i = 0; i < GAP_MAX_CHAR_NUM; i ++, p_db_attr ++) + { + if (p_data-> handle == p_db_attr->handle) + { + return GATT_WRITE_NOT_PERMIT; + } + } + return GATT_NOT_FOUND; + +} + +/****************************************************************************** +** +** Function gap_ble_s_attr_request_cback +** +** Description GAP ATT server attribute access request callback. +** +** Returns void. +** +*******************************************************************************/ +void gap_ble_s_attr_request_cback (UINT16 conn_id, UINT32 trans_id, + tGATTS_REQ_TYPE type, tGATTS_DATA *p_data) +{ + UINT8 status = GATT_INVALID_PDU; + tGATTS_RSP rsp_msg; + BOOLEAN ignore = FALSE; + + GAP_TRACE_EVENT("gap_ble_s_attr_request_cback : recv type (0x%02x)", type); + + memset(&rsp_msg, 0, sizeof(tGATTS_RSP)); + + switch (type) + { + case GATTS_REQ_TYPE_READ: + status = gap_proc_read(type, &p_data->read_req, &rsp_msg); + break; + + case GATTS_REQ_TYPE_WRITE: + if (!p_data->write_req.need_rsp) + ignore = TRUE; + + status = gap_proc_write_req(type, &p_data->write_req); + break; + + case GATTS_REQ_TYPE_WRITE_EXEC: + ignore = TRUE; + GAP_TRACE_EVENT("Ignore GATTS_REQ_TYPE_WRITE_EXEC" ); + break; + + case GATTS_REQ_TYPE_MTU: + GAP_TRACE_EVENT("Get MTU exchange new mtu size: %d", p_data->mtu); + ignore = TRUE; + break; + + default: + GAP_TRACE_EVENT("Unknown/unexpected LE GAP ATT request: 0x%02x", type); + break; + } + + if (!ignore) + GATTS_SendRsp (conn_id, trans_id, status, &rsp_msg); +} + +/******************************************************************************* +** +** Function btm_ble_att_db_init +** +** Description GAP ATT database initalization. +** +** Returns void. +** +*******************************************************************************/ +void gap_attr_db_init(void) +{ + tBT_UUID app_uuid = {LEN_UUID_128,{0}}; + tBT_UUID uuid = {LEN_UUID_16,{UUID_SERVCLASS_GAP_SERVER}}; + UINT16 service_handle; + tGAP_ATTR *p_db_attr = &gap_cb.gatt_attr[0]; + tGATT_STATUS status; + + /* Fill our internal UUID with a fixed pattern 0x82 */ + memset (&app_uuid.uu.uuid128, 0x82, LEN_UUID_128); + memset(gap_cb.gatt_attr, 0, sizeof(tGAP_ATTR) *GAP_MAX_CHAR_NUM); + + gap_cb.gatt_if = GATT_Register(&app_uuid, &gap_cback); + + GATT_StartIf(gap_cb.gatt_if); + + /* Create a GAP service */ + service_handle = GATTS_CreateService (gap_cb.gatt_if, &uuid, 0, GAP_MAX_ATTR_NUM, TRUE); + + GAP_TRACE_EVENT ("gap_attr_db_init service_handle = %d", service_handle); + + /* add Device Name Characteristic + */ + uuid.len = LEN_UUID_16; + uuid.uu.uuid16 = p_db_attr->uuid = GATT_UUID_GAP_DEVICE_NAME; + p_db_attr->handle = GATTS_AddCharacteristic(service_handle, &uuid, GATT_PERM_READ, GATT_CHAR_PROP_BIT_READ); + p_db_attr ++; + + /* add Icon characteristic + */ + uuid.uu.uuid16 = p_db_attr->uuid = GATT_UUID_GAP_ICON; + p_db_attr->handle = GATTS_AddCharacteristic(service_handle, + &uuid, + GATT_PERM_READ, + GATT_CHAR_PROP_BIT_READ); + p_db_attr ++; + +#if ((defined BTM_PERIPHERAL_ENABLED) && (BTM_PERIPHERAL_ENABLED == TRUE)) + /* Only needed for peripheral testing */ + /* add preferred connection parameter characteristic + */ + uuid.uu.uuid16 = p_db_attr->uuid = GATT_UUID_GAP_PREF_CONN_PARAM; + p_db_attr->attr_value.conn_param.int_max = GAP_PREFER_CONN_INT_MAX; /* 6 */ + p_db_attr->attr_value.conn_param.int_min = GAP_PREFER_CONN_INT_MIN; /* 0 */ + p_db_attr->attr_value.conn_param.latency = GAP_PREFER_CONN_LATENCY; /* 0 */ + p_db_attr->attr_value.conn_param.sp_tout = GAP_PREFER_CONN_SP_TOUT; /* 2000 */ + p_db_attr->handle = GATTS_AddCharacteristic(service_handle, + &uuid, + GATT_PERM_READ, + GATT_CHAR_PROP_BIT_READ); + p_db_attr ++; +#endif + + /* add Central address resolution Characteristic */ + uuid.len = LEN_UUID_16; + uuid.uu.uuid16 = p_db_attr->uuid = GATT_UUID_GAP_CENTRAL_ADDR_RESOL; + p_db_attr->handle = GATTS_AddCharacteristic(service_handle, &uuid, + GATT_PERM_READ, GATT_CHAR_PROP_BIT_READ); + p_db_attr->attr_value.addr_resolution = 0; + p_db_attr++; + + /* start service now */ + memset (&app_uuid.uu.uuid128, 0x81, LEN_UUID_128); + + status = GATTS_StartService(gap_cb.gatt_if, service_handle, GAP_TRANSPORT_SUPPORTED ); + + GAP_TRACE_EVENT ("GAP App gatt_if: %d s_hdl = %d start_status=%d", + gap_cb.gatt_if, service_handle, status); + + + +} + +/******************************************************************************* +** +** Function GAP_BleAttrDBUpdate +** +** Description GAP ATT database update. +** +** Returns void. +** +*******************************************************************************/ +void GAP_BleAttrDBUpdate(UINT16 attr_uuid, tGAP_BLE_ATTR_VALUE *p_value) +{ + tGAP_ATTR *p_db_attr = gap_cb.gatt_attr; + UINT8 i = 0; + + GAP_TRACE_EVENT("GAP_BleAttrDBUpdate attr_uuid=0x%04x", attr_uuid); + + for (i = 0; i < GAP_MAX_CHAR_NUM; i ++, p_db_attr ++) + { + if (p_db_attr->uuid == attr_uuid) + { + GAP_TRACE_EVENT("Found attr_uuid=0x%04x", attr_uuid); + + switch (attr_uuid) + { + case GATT_UUID_GAP_ICON: + p_db_attr->attr_value.icon = p_value->icon; + break; + + case GATT_UUID_GAP_PREF_CONN_PARAM: + memcpy((void *)&p_db_attr->attr_value.conn_param, + (const void *)&p_value->conn_param, sizeof(tGAP_BLE_PREF_PARAM)); + break; + + case GATT_UUID_GAP_DEVICE_NAME: + BTM_SetLocalDeviceName((char *)p_value->p_dev_name); + break; + + case GATT_UUID_GAP_CENTRAL_ADDR_RESOL: + p_db_attr->attr_value.addr_resolution = p_value->addr_resolution; + break; + + } + break; + } + } + + return; +} + +/******************************************************************************* +** +** Function gap_ble_send_cl_read_request +** +** Description utility function to send a read request for a GAP charactersitic +** +** Returns TRUE if read started, else FALSE if GAP is busy +** +*******************************************************************************/ +BOOLEAN gap_ble_send_cl_read_request(tGAP_CLCB *p_clcb) +{ + tGATT_READ_PARAM param; + UINT16 uuid = 0; + BOOLEAN started = FALSE; + + if (gap_ble_dequeue_request(p_clcb, &uuid, &p_clcb->p_cback)) + { + memset(¶m, 0, sizeof(tGATT_READ_PARAM)); + + param.service.uuid.len = LEN_UUID_16; + param.service.uuid.uu.uuid16 = uuid; + param.service.s_handle = 1; + param.service.e_handle = 0xFFFF; + param.service.auth_req = 0; + + if (GATTC_Read(p_clcb->conn_id, GATT_READ_BY_TYPE, ¶m) == GATT_SUCCESS) + { + p_clcb->cl_op_uuid = uuid; + started = TRUE; + } + } + + return started; +} + +/******************************************************************************* +** +** Function gap_ble_cl_op_cmpl +** +** Description GAP client operation complete callback +** +** Returns void +** +*******************************************************************************/ +void gap_ble_cl_op_cmpl(tGAP_CLCB *p_clcb, BOOLEAN status, UINT16 len, UINT8 *p_name) +{ + tGAP_BLE_CMPL_CBACK *p_cback = p_clcb->p_cback; + UINT16 op = p_clcb->cl_op_uuid; + + GAP_TRACE_EVENT("gap_ble_cl_op_cmpl status: %d", status); + + p_clcb->cl_op_uuid = 0; + p_clcb->p_cback=NULL; + + if (p_cback && op) + { + GAP_TRACE_EVENT("calling gap_ble_cl_op_cmpl"); + (* p_cback)(status, p_clcb->bda, len, (char *)p_name); + } + + /* if no further activity is requested in callback, drop the link */ + if (p_clcb->connected) + { + if (!gap_ble_send_cl_read_request(p_clcb)) + { + GATT_Disconnect(p_clcb->conn_id); + gap_ble_dealloc_clcb(p_clcb); + } + } +} + +/******************************************************************************* +** +** Function gap_ble_c_connect_cback +** +** Description Client connection callback. +** +** Returns void +** +*******************************************************************************/ +static void gap_ble_c_connect_cback (tGATT_IF gatt_if, BD_ADDR bda, UINT16 conn_id, + BOOLEAN connected, tGATT_DISCONN_REASON reason, + tGATT_TRANSPORT transport) +{ + tGAP_CLCB *p_clcb = gap_find_clcb_by_bd_addr (bda); + + UNUSED(gatt_if); + UNUSED(transport); + + if (p_clcb != NULL) + { + if (connected) + { + p_clcb->conn_id = conn_id; + p_clcb->connected = TRUE; + /* start operation is pending */ + gap_ble_send_cl_read_request(p_clcb); + } + else + { + p_clcb->connected = FALSE; + gap_ble_cl_op_cmpl(p_clcb, FALSE, 0, NULL); + /* clean up clcb */ + gap_ble_dealloc_clcb(p_clcb); + } + } +} + +/******************************************************************************* +** +** Function gap_ble_c_cmpl_cback +** +** Description Client operation complete callback. +** +** Returns void +** +*******************************************************************************/ +static void gap_ble_c_cmpl_cback (UINT16 conn_id, tGATTC_OPTYPE op, tGATT_STATUS status, tGATT_CL_COMPLETE *p_data) + +{ + tGAP_CLCB *p_clcb = gap_ble_find_clcb_by_conn_id(conn_id); + UINT16 op_type; + UINT16 min, max, latency, tout; + UINT16 len; + UINT8 *pp; + + if (p_clcb == NULL) + return; + + op_type = p_clcb->cl_op_uuid; + + GAP_TRACE_EVENT ("gap_ble_c_cmpl_cback() - op_code: 0x%02x status: 0x%02x read_type: 0x%04x", op, status, op_type); + /* Currently we only issue read commands */ + if (op != GATTC_OPTYPE_READ) + return; + + if (status != GATT_SUCCESS) + { + gap_ble_cl_op_cmpl(p_clcb, FALSE, 0, NULL); + return; + } + + pp = p_data->att_value.value; + + switch (op_type) + { + case GATT_UUID_GAP_PREF_CONN_PARAM: + GAP_TRACE_EVENT ("GATT_UUID_GAP_PREF_CONN_PARAM"); + /* Extract the peripheral preferred connection parameters and save them */ + + STREAM_TO_UINT16 (min, pp); + STREAM_TO_UINT16 (max, pp); + STREAM_TO_UINT16 (latency, pp); + STREAM_TO_UINT16 (tout, pp); + + BTM_BleSetPrefConnParams (p_clcb->bda, min, max, latency, tout); + /* release the connection here */ + gap_ble_cl_op_cmpl(p_clcb, TRUE, 0, NULL); + break; + + case GATT_UUID_GAP_DEVICE_NAME: + GAP_TRACE_EVENT ("GATT_UUID_GAP_DEVICE_NAME"); + len = (UINT16)strlen((char *)pp); + if (len > GAP_CHAR_DEV_NAME_SIZE) + len = GAP_CHAR_DEV_NAME_SIZE; + gap_ble_cl_op_cmpl(p_clcb, TRUE, len, pp); + break; + + case GATT_UUID_GAP_CENTRAL_ADDR_RESOL: + gap_ble_cl_op_cmpl(p_clcb, TRUE, 1, pp); + break; + } +} + + +/******************************************************************************* +** +** Function gap_ble_accept_cl_operation +** +** Description Start a process to read peer address resolution capability +** +** Returns TRUE if request accepted +** +*******************************************************************************/ +BOOLEAN gap_ble_accept_cl_operation(BD_ADDR peer_bda, UINT16 uuid, tGAP_BLE_CMPL_CBACK *p_cback) +{ + tGAP_CLCB *p_clcb; + BOOLEAN started = FALSE; + + if (p_cback == NULL && uuid != GATT_UUID_GAP_PREF_CONN_PARAM) + return(started); + + if ((p_clcb = gap_find_clcb_by_bd_addr (peer_bda)) == NULL) + { + if ((p_clcb = gap_clcb_alloc(peer_bda)) == NULL) + { + GAP_TRACE_ERROR("gap_ble_accept_cl_operation max connection reached"); + return started; + } + } + + GAP_TRACE_EVENT ("%s() - BDA: %08x%04x cl_op_uuid: 0x%04x", + __FUNCTION__, + (peer_bda[0]<<24)+(peer_bda[1]<<16)+(peer_bda[2]<<8)+peer_bda[3], + (peer_bda[4]<<8)+peer_bda[5], uuid); + + if (GATT_GetConnIdIfConnected(gap_cb.gatt_if, peer_bda, &p_clcb->conn_id, BT_TRANSPORT_LE)) + p_clcb->connected = TRUE; + + /* hold the link here */ + if (!GATT_Connect(gap_cb.gatt_if, p_clcb->bda, TRUE, BT_TRANSPORT_LE)) + return started; + + /* enqueue the request */ + gap_ble_enqueue_request(p_clcb, uuid, p_cback); + + if (p_clcb->connected && p_clcb->cl_op_uuid == 0) + started = gap_ble_send_cl_read_request(p_clcb); + else /* wait for connection up or pending operation to finish */ + started = TRUE; + + return started; +} +/******************************************************************************* +** +** Function GAP_BleReadPeerPrefConnParams +** +** Description Start a process to read a connected peripheral's preferred +** connection parameters +** +** Returns TRUE if read started, else FALSE if GAP is busy +** +*******************************************************************************/ +BOOLEAN GAP_BleReadPeerPrefConnParams (BD_ADDR peer_bda) +{ + return gap_ble_accept_cl_operation (peer_bda, GATT_UUID_GAP_PREF_CONN_PARAM, NULL); +} + +/******************************************************************************* +** +** Function GAP_BleReadPeerDevName +** +** Description Start a process to read a connected peripheral's device name. +** +** Returns TRUE if request accepted +** +*******************************************************************************/ +BOOLEAN GAP_BleReadPeerDevName (BD_ADDR peer_bda, tGAP_BLE_CMPL_CBACK *p_cback) +{ + return gap_ble_accept_cl_operation (peer_bda, GATT_UUID_GAP_DEVICE_NAME, p_cback); +} + +/******************************************************************************* +** +** Function GAP_BleReadPeerAddressResolutionCap +** +** Description Start a process to read peer address resolution capability +** +** Returns TRUE if request accepted +** +*******************************************************************************/ +BOOLEAN GAP_BleReadPeerAddressResolutionCap (BD_ADDR peer_bda, tGAP_BLE_CMPL_CBACK *p_cback) +{ + return gap_ble_accept_cl_operation(peer_bda, GATT_UUID_GAP_CENTRAL_ADDR_RESOL, p_cback); +} + +/******************************************************************************* +** +** Function GAP_BleCancelReadPeerDevName +** +** Description Cancel reading a peripheral's device name. +** +** Returns TRUE if request accepted +** +*******************************************************************************/ +BOOLEAN GAP_BleCancelReadPeerDevName (BD_ADDR peer_bda) +{ + tGAP_CLCB *p_clcb = gap_find_clcb_by_bd_addr (peer_bda); + + GAP_TRACE_EVENT ("GAP_BleCancelReadPeerDevName() - BDA: %08x%04x cl_op_uuid: 0x%04x", + (peer_bda[0]<<24)+(peer_bda[1]<<16)+(peer_bda[2]<<8)+peer_bda[3], + (peer_bda[4]<<8)+peer_bda[5], (p_clcb == NULL)? 0 : p_clcb->cl_op_uuid); + + if (p_clcb == NULL) + { + GAP_TRACE_ERROR ("Cannot cancel current op is not get dev name"); + return FALSE; + } + + if (!p_clcb->connected) + { + if (!GATT_CancelConnect(gap_cb.gatt_if, peer_bda, TRUE)) + { + GAP_TRACE_ERROR ("Cannot cancel where No connection id"); + return FALSE; + } + } + + gap_ble_cl_op_cmpl(p_clcb, FALSE, 0, NULL); + + return(TRUE); +} + +#endif /* BLE_INCLUDED */ + + + + + diff --git a/components/bt/bluedroid/stack/gap/gap_conn.c b/components/bt/bluedroid/stack/gap/gap_conn.c new file mode 100755 index 0000000000..213baa5f60 --- /dev/null +++ b/components/bt/bluedroid/stack/gap/gap_conn.c @@ -0,0 +1,1284 @@ +/****************************************************************************** + * + * Copyright (C) 2009-2013 Broadcom Corporation + * + * 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. + * + ******************************************************************************/ + + +#include "bt_target.h" +#include "bt_defs.h" +#include "btu.h" +#include "gap_int.h" +#include "l2cdefs.h" +#include "l2c_int.h" +#include +#if GAP_CONN_INCLUDED == TRUE +#include "btm_int.h" + +/********************************************************************************/ +/* L O C A L F U N C T I O N P R O T O T Y P E S */ +/********************************************************************************/ +static void gap_connect_ind (BD_ADDR bd_addr, UINT16 l2cap_cid, UINT16 psm, UINT8 l2cap_id); +static void gap_connect_cfm (UINT16 l2cap_cid, UINT16 result); +static void gap_config_ind (UINT16 l2cap_cid, tL2CAP_CFG_INFO *p_cfg); +static void gap_config_cfm (UINT16 l2cap_cid, tL2CAP_CFG_INFO *p_cfg); +static void gap_disconnect_ind (UINT16 l2cap_cid, BOOLEAN ack_needed); +static void gap_data_ind (UINT16 l2cap_cid, BT_HDR *p_msg); +static void gap_congestion_ind (UINT16 lcid, BOOLEAN is_congested); + +static tGAP_CCB *gap_find_ccb_by_cid (UINT16 cid); +static tGAP_CCB *gap_find_ccb_by_handle (UINT16 handle); +static tGAP_CCB *gap_allocate_ccb (void); +static void gap_release_ccb (tGAP_CCB *p_ccb); + +/******************************************************************************* +** +** Function gap_conn_init +** +** Description This function is called to initialize GAP connection management +** +** Returns void +** +*******************************************************************************/ +void gap_conn_init (void) +{ +#if ((defined AMP_INCLUDED) && (AMP_INCLUDED == TRUE)) + gap_cb.conn.reg_info.pAMP_ConnectInd_Cb = gap_connect_ind; + gap_cb.conn.reg_info.pAMP_ConnectCfm_Cb = gap_connect_cfm; + gap_cb.conn.reg_info.pAMP_ConnectPnd_Cb = NULL; + gap_cb.conn.reg_info.pAMP_ConfigInd_Cb = gap_config_ind; + gap_cb.conn.reg_info.pAMP_ConfigCfm_Cb = gap_config_cfm; + gap_cb.conn.reg_info.pAMP_DisconnectInd_Cb = gap_disconnect_ind; + gap_cb.conn.reg_info.pAMP_DisconnectCfm_Cb = NULL; + gap_cb.conn.reg_info.pAMP_QoSViolationInd_Cb = NULL; + gap_cb.conn.reg_info.pAMP_DataInd_Cb = gap_data_ind; + gap_cb.conn.reg_info.pAMP_CongestionStatus_Cb = gap_congestion_ind; + gap_cb.conn.reg_info.pAMP_TxComplete_Cb = NULL; + gap_cb.conn.reg_info.pAMP_MoveInd_Cb = NULL; + gap_cb.conn.reg_info.pAMP_MoveRsp_Cb = NULL; + gap_cb.conn.reg_info.pAMP_MoveCfm_Cb = NULL; //gap_move_cfm + gap_cb.conn.reg_info.pAMP_MoveCfmRsp_Cb = NULL; //gap_move_cfm_rsp + +#else + gap_cb.conn.reg_info.pL2CA_ConnectInd_Cb = gap_connect_ind; + gap_cb.conn.reg_info.pL2CA_ConnectCfm_Cb = gap_connect_cfm; + gap_cb.conn.reg_info.pL2CA_ConnectPnd_Cb = NULL; + gap_cb.conn.reg_info.pL2CA_ConfigInd_Cb = gap_config_ind; + gap_cb.conn.reg_info.pL2CA_ConfigCfm_Cb = gap_config_cfm; + gap_cb.conn.reg_info.pL2CA_DisconnectInd_Cb = gap_disconnect_ind; + gap_cb.conn.reg_info.pL2CA_DisconnectCfm_Cb = NULL; + gap_cb.conn.reg_info.pL2CA_QoSViolationInd_Cb = NULL; + gap_cb.conn.reg_info.pL2CA_DataInd_Cb = gap_data_ind; + gap_cb.conn.reg_info.pL2CA_CongestionStatus_Cb = gap_congestion_ind; + gap_cb.conn.reg_info.pL2CA_TxComplete_Cb = NULL; +#endif +} + + +/******************************************************************************* +** +** Function GAP_ConnOpen +** +** Description This function is called to open an L2CAP connection. +** +** Parameters: is_server - If TRUE, the connection is not created +** but put into a "listen" mode waiting for +** the remote side to connect. +** +** service_id - Unique service ID from +** BTM_SEC_SERVICE_FIRST_EMPTY (6) +** to BTM_SEC_MAX_SERVICE_RECORDS (32) +** +** p_rem_bda - Pointer to remote BD Address. +** If a server, and we don't care about the +** remote BD Address, then NULL should be passed. +** +** psm - the PSM used for the connection +** +** p_config - Optional pointer to configuration structure. +** If NULL, the default GAP configuration will +** be used. +** +** security - security flags +** chan_mode_mask - (GAP_FCR_CHAN_OPT_BASIC, GAP_FCR_CHAN_OPT_ERTM, +** GAP_FCR_CHAN_OPT_STREAM) +** +** p_cb - Pointer to callback function for events. +** +** Returns handle of the connection if successful, else GAP_INVALID_HANDLE +** +*******************************************************************************/ +UINT16 GAP_ConnOpen (char *p_serv_name, UINT8 service_id, BOOLEAN is_server, + BD_ADDR p_rem_bda, UINT16 psm, tL2CAP_CFG_INFO *p_cfg, + tL2CAP_ERTM_INFO *ertm_info, UINT16 security, UINT8 chan_mode_mask, + tGAP_CONN_CALLBACK *p_cb) +{ + tGAP_CCB *p_ccb; + UINT16 cid; + tBT_UUID bt_uuid = {2, {GAP_PROTOCOL_ID}}; + + GAP_TRACE_EVENT ("GAP_CONN - Open Request"); + + /* Allocate a new CCB. Return if none available. */ + if ((p_ccb = gap_allocate_ccb()) == NULL) + return (GAP_INVALID_HANDLE); + + /* If caller specified a BD address, save it */ + if (p_rem_bda) + { + /* the bd addr is not BT_BD_ANY, then a bd address was specified */ + if (memcmp (p_rem_bda, BT_BD_ANY, BD_ADDR_LEN)) + p_ccb->rem_addr_specified = TRUE; + + memcpy (&p_ccb->rem_dev_address[0], p_rem_bda, BD_ADDR_LEN); + } + else if (!is_server) + { + /* remore addr is not specified and is not a server -> bad */ + return (GAP_INVALID_HANDLE); + } + + /* A client MUST have specified a bd addr to connect with */ + if (!p_ccb->rem_addr_specified && !is_server) + { + gap_release_ccb (p_ccb); + GAP_TRACE_ERROR ("GAP ERROR: Client must specify a remote BD ADDR to connect to!"); + return (GAP_INVALID_HANDLE); + } + + /* Check if configuration was specified */ + if (p_cfg) + p_ccb->cfg = *p_cfg; + + p_ccb->p_callback = p_cb; + + /* If originator, use a dynamic PSM */ +#if ((defined AMP_INCLUDED) && (AMP_INCLUDED == TRUE)) + if (!is_server) + gap_cb.conn.reg_info.pAMP_ConnectInd_Cb = NULL; + else + gap_cb.conn.reg_info.pAMP_ConnectInd_Cb = gap_connect_ind; +#else + if (!is_server) + gap_cb.conn.reg_info.pL2CA_ConnectInd_Cb = NULL; + else + gap_cb.conn.reg_info.pL2CA_ConnectInd_Cb = gap_connect_ind; +#endif + + /* Register the PSM with L2CAP */ + if ((p_ccb->psm = L2CA_REGISTER (psm, &gap_cb.conn.reg_info, + AMP_AUTOSWITCH_ALLOWED|AMP_USE_AMP_IF_POSSIBLE)) == 0) + { + GAP_TRACE_ERROR ("GAP_ConnOpen: Failure registering PSM 0x%04x", psm); + gap_release_ccb (p_ccb); + return (GAP_INVALID_HANDLE); + } + + /* Register with Security Manager for the specific security level */ + p_ccb->service_id = service_id; + if (!BTM_SetSecurityLevel ((UINT8)!is_server, p_serv_name, + p_ccb->service_id, security, p_ccb->psm, 0, 0)) + { + GAP_TRACE_ERROR ("GAP_CONN - Security Error"); + gap_release_ccb (p_ccb); + return (GAP_INVALID_HANDLE); + } + + /* Fill in eL2CAP parameter data */ + if( p_ccb->cfg.fcr_present ) + { + if(ertm_info == NULL) { + p_ccb->ertm_info.preferred_mode = p_ccb->cfg.fcr.mode; + p_ccb->ertm_info.user_rx_pool_id = GAP_DATA_POOL_ID; + p_ccb->ertm_info.user_tx_pool_id = GAP_DATA_POOL_ID; + p_ccb->ertm_info.fcr_rx_pool_id = L2CAP_DEFAULT_ERM_POOL_ID; + p_ccb->ertm_info.fcr_tx_pool_id = L2CAP_DEFAULT_ERM_POOL_ID; + } else { + p_ccb->ertm_info = *ertm_info; + } + } + + /* optional FCR channel modes */ + if(ertm_info != NULL) { + p_ccb->ertm_info.allowed_modes = + (chan_mode_mask) ? chan_mode_mask : (UINT8)L2CAP_FCR_CHAN_OPT_BASIC; + } + + if (is_server) + { + p_ccb->con_flags |= GAP_CCB_FLAGS_SEC_DONE; /* assume btm/l2cap would handle it */ + p_ccb->con_state = GAP_CCB_STATE_LISTENING; + return (p_ccb->gap_handle); + } + else + { + /* We are the originator of this connection */ + p_ccb->con_flags = GAP_CCB_FLAGS_IS_ORIG; + + /* Transition to the next appropriate state, waiting for connection confirm. */ + p_ccb->con_state = GAP_CCB_STATE_CONN_SETUP; + + /* mark security done flag, when security is not required */ + if ((security & (BTM_SEC_OUT_AUTHORIZE | BTM_SEC_OUT_AUTHENTICATE | BTM_SEC_OUT_ENCRYPT) ) == 0) + p_ccb->con_flags |= GAP_CCB_FLAGS_SEC_DONE; + + /* Check if L2CAP started the connection process */ + if (p_rem_bda && ((cid = L2CA_CONNECT_REQ (p_ccb->psm, p_rem_bda, &p_ccb->ertm_info, &bt_uuid)) != 0)) + { + p_ccb->connection_id = cid; + return (p_ccb->gap_handle); + } + else + { + gap_release_ccb (p_ccb); + return (GAP_INVALID_HANDLE); + } + } +} + + +/******************************************************************************* +** +** Function GAP_ConnClose +** +** Description This function is called to close a connection. +** +** Parameters: handle - Handle of the connection returned by GAP_ConnOpen +** +** Returns BT_PASS - closed OK +** GAP_ERR_BAD_HANDLE - invalid handle +** +*******************************************************************************/ +UINT16 GAP_ConnClose (UINT16 gap_handle) +{ + tGAP_CCB *p_ccb = gap_find_ccb_by_handle (gap_handle); + + GAP_TRACE_EVENT ("GAP_CONN - close handle: 0x%x", gap_handle); + + if (p_ccb) + { + /* Check if we have a connection ID */ + if (p_ccb->con_state != GAP_CCB_STATE_LISTENING) + L2CA_DISCONNECT_REQ (p_ccb->connection_id); + + gap_release_ccb (p_ccb); + + return (BT_PASS); + } + + return (GAP_ERR_BAD_HANDLE); +} + + + +/******************************************************************************* +** +** Function GAP_ConnReadData +** +** Description Normally not GKI aware application will call this function +** after receiving GAP_EVT_RXDATA event. +** +** Parameters: handle - Handle of the connection returned in the Open +** p_data - Data area +** max_len - Byte count requested +** p_len - Byte count received +** +** Returns BT_PASS - data read +** GAP_ERR_BAD_HANDLE - invalid handle +** GAP_NO_DATA_AVAIL - no data available +** +*******************************************************************************/ +UINT16 GAP_ConnReadData (UINT16 gap_handle, UINT8 *p_data, UINT16 max_len, UINT16 *p_len) +{ + tGAP_CCB *p_ccb = gap_find_ccb_by_handle (gap_handle); + BT_HDR *p_buf; + UINT16 copy_len; + + if (!p_ccb) + return (GAP_ERR_BAD_HANDLE); + + *p_len = 0; + + p_buf = (BT_HDR *)GKI_getfirst (&p_ccb->rx_queue); + if (!p_buf) + return (GAP_NO_DATA_AVAIL); + + GKI_disable(); + + while (max_len && p_buf) + { + copy_len = (p_buf->len > max_len)?max_len:p_buf->len; + max_len -= copy_len; + *p_len += copy_len; + if (p_data) + { + memcpy (p_data, (UINT8 *)(p_buf + 1) + p_buf->offset, copy_len); + p_data += copy_len; + } + + if (p_buf->len > copy_len) + { + p_buf->offset += copy_len; + p_buf->len -= copy_len; + break; + } + else + { + if (max_len) + { + p_buf = (BT_HDR *)GKI_getnext (p_buf); + } + GKI_freebuf (GKI_dequeue (&p_ccb->rx_queue)); + } + } + + p_ccb->rx_queue_size -= *p_len; + + GKI_enable(); + + GAP_TRACE_EVENT ("GAP_ConnReadData - rx_queue_size left=%d, *p_len=%d", + p_ccb->rx_queue_size, *p_len); + + return (BT_PASS); +} + +/******************************************************************************* +** +** Function GAP_GetRxQueueCnt +** +** Description This function return number of bytes on the rx queue. +** +** Parameters: handle - Handle returned in the GAP_ConnOpen +** p_rx_queue_count - Pointer to return queue count in. +** +** +*******************************************************************************/ +int GAP_GetRxQueueCnt (UINT16 handle, UINT32 *p_rx_queue_count) +{ + tGAP_CCB *p_ccb; + int rc = BT_PASS; + + /* Check that handle is valid */ + if (handle < GAP_MAX_CONNECTIONS) + { + p_ccb = &gap_cb.conn.ccb_pool[handle]; + + if (p_ccb->con_state == GAP_CCB_STATE_CONNECTED) + { + *p_rx_queue_count = p_ccb->rx_queue_size; + } + else + rc = GAP_INVALID_HANDLE; + } + else + rc = GAP_INVALID_HANDLE; + + GAP_TRACE_EVENT ("GAP_GetRxQueueCnt - rc = 0x%04x, rx_queue_count=%d", + rc , *p_rx_queue_count); + + return (rc); +} + +/******************************************************************************* +** +** Function GAP_ConnBTRead +** +** Description Bluetooth aware applications will call this function after receiving +** GAP_EVT_RXDATA event. +** +** Parameters: handle - Handle of the connection returned in the Open +** pp_buf - pointer to address of buffer with data, +** +** Returns BT_PASS - data read +** GAP_ERR_BAD_HANDLE - invalid handle +** GAP_NO_DATA_AVAIL - no data available +** +*******************************************************************************/ +UINT16 GAP_ConnBTRead (UINT16 gap_handle, BT_HDR **pp_buf) +{ + tGAP_CCB *p_ccb = gap_find_ccb_by_handle (gap_handle); + BT_HDR *p_buf; + + if (!p_ccb) + return (GAP_ERR_BAD_HANDLE); + + p_buf = (BT_HDR *)GKI_dequeue (&p_ccb->rx_queue); + + if (p_buf) + { + *pp_buf = p_buf; + + p_ccb->rx_queue_size -= p_buf->len; + return (BT_PASS); + } + else + { + *pp_buf = NULL; + return (GAP_NO_DATA_AVAIL); + } +} + + +/******************************************************************************* +** +** Function GAP_ConnBTWrite +** +** Description Bluetooth Aware applications can call this function to write data. +** +** Parameters: handle - Handle of the connection returned in the Open +** p_buf - pointer to address of buffer with data, +** +** Returns BT_PASS - data read +** GAP_ERR_BAD_HANDLE - invalid handle +** GAP_ERR_BAD_STATE - connection not established +** GAP_INVALID_BUF_OFFSET - buffer offset is invalid +*******************************************************************************/ +UINT16 GAP_ConnBTWrite (UINT16 gap_handle, BT_HDR *p_buf) +{ + tGAP_CCB *p_ccb = gap_find_ccb_by_handle (gap_handle); + + if (!p_ccb) + { + GKI_freebuf (p_buf); + return (GAP_ERR_BAD_HANDLE); + } + + if (p_ccb->con_state != GAP_CCB_STATE_CONNECTED) + { + GKI_freebuf (p_buf); + return (GAP_ERR_BAD_STATE); + } + + if (p_buf->offset < L2CAP_MIN_OFFSET) + { + GKI_freebuf (p_buf); + return (GAP_ERR_BUF_OFFSET); + } + + GKI_enqueue (&p_ccb->tx_queue, p_buf); + + if (p_ccb->is_congested) + { + return (BT_PASS); + } + + /* Send the buffer through L2CAP */ +#if (GAP_CONN_POST_EVT_INCLUDED == TRUE) + gap_send_event (gap_handle); +#else + while ((p_buf = (BT_HDR *)GKI_dequeue (&p_ccb->tx_queue)) != NULL) + { + UINT8 status = L2CA_DATA_WRITE (p_ccb->connection_id, p_buf); + + if (status == L2CAP_DW_CONGESTED) + { + p_ccb->is_congested = TRUE; + break; + } + else if (status != L2CAP_DW_SUCCESS) + return (GAP_ERR_BAD_STATE); + } +#endif + return (BT_PASS); +} + + +/******************************************************************************* +** +** Function GAP_ConnWriteData +** +** Description Normally not GKI aware application will call this function +** to send data to the connection. +** +** Parameters: handle - Handle of the connection returned in the Open +** p_data - Data area +** max_len - Byte count requested +** p_len - Byte count received +** +** Returns BT_PASS - data read +** GAP_ERR_BAD_HANDLE - invalid handle +** GAP_ERR_BAD_STATE - connection not established +** GAP_CONGESTION - system is congested +** +*******************************************************************************/ +UINT16 GAP_ConnWriteData (UINT16 gap_handle, UINT8 *p_data, UINT16 max_len, UINT16 *p_len) +{ + tGAP_CCB *p_ccb = gap_find_ccb_by_handle (gap_handle); + BT_HDR *p_buf; + + *p_len = 0; + + if (!p_ccb) + return (GAP_ERR_BAD_HANDLE); + + if (p_ccb->con_state != GAP_CCB_STATE_CONNECTED) + return (GAP_ERR_BAD_STATE); + + while (max_len) + { + if (p_ccb->cfg.fcr.mode == L2CAP_FCR_ERTM_MODE) + { + if ((p_buf = (BT_HDR *)GKI_getpoolbuf (p_ccb->ertm_info.user_tx_pool_id)) == NULL) + return (GAP_ERR_CONGESTED); + } + else + { + if ((p_buf = (BT_HDR *)GKI_getpoolbuf (GAP_DATA_POOL_ID)) == NULL) + return (GAP_ERR_CONGESTED); + } + + p_buf->offset = L2CAP_MIN_OFFSET; + p_buf->len = (p_ccb->rem_mtu_size < max_len) ? p_ccb->rem_mtu_size : max_len; + p_buf->event = BT_EVT_TO_BTU_SP_DATA; + + memcpy ((UINT8 *)(p_buf + 1) + p_buf->offset, p_data, p_buf->len); + + *p_len += p_buf->len; + max_len -= p_buf->len; + p_data += p_buf->len; + + GAP_TRACE_EVENT ("GAP_WriteData %d bytes", p_buf->len); + + GKI_enqueue (&p_ccb->tx_queue, p_buf); + } + + if (p_ccb->is_congested) + { + return (BT_PASS); + } + + /* Send the buffer through L2CAP */ +#if (GAP_CONN_POST_EVT_INCLUDED == TRUE) + gap_send_event (gap_handle); +#else + while ((p_buf = (BT_HDR *)GKI_dequeue (&p_ccb->tx_queue)) != NULL) + { + UINT8 status = L2CA_DATA_WRITE (p_ccb->connection_id, p_buf); + + if (status == L2CAP_DW_CONGESTED) + { + p_ccb->is_congested = TRUE; + break; + } + else if (status != L2CAP_DW_SUCCESS) + return (GAP_ERR_BAD_STATE); + } +#endif + return (BT_PASS); +} + + +/******************************************************************************* +** +** Function GAP_ConnReconfig +** +** Description Applications can call this function to reconfigure the connection. +** +** Parameters: handle - Handle of the connection +** p_cfg - Pointer to new configuration +** +** Returns BT_PASS - config process started +** GAP_ERR_BAD_HANDLE - invalid handle +** +*******************************************************************************/ +UINT16 GAP_ConnReconfig (UINT16 gap_handle, tL2CAP_CFG_INFO *p_cfg) +{ + tGAP_CCB *p_ccb = gap_find_ccb_by_handle (gap_handle); + + if (!p_ccb) + return (GAP_ERR_BAD_HANDLE); + + p_ccb->cfg = *p_cfg; + + if (p_ccb->con_state == GAP_CCB_STATE_CONNECTED) + L2CA_CONFIG_REQ (p_ccb->connection_id, p_cfg); + + return (BT_PASS); +} + + + +/******************************************************************************* +** +** Function GAP_ConnSetIdleTimeout +** +** Description Higher layers call this function to set the idle timeout for +** a connection, or for all future connections. The "idle timeout" +** is the amount of time that a connection can remain up with +** no L2CAP channels on it. A timeout of zero means that the +** connection will be torn down immediately when the last channel +** is removed. A timeout of 0xFFFF means no timeout. Values are +** in seconds. +** +** Parameters: handle - Handle of the connection +** timeout - in secs +** 0 = immediate disconnect when last channel is removed +** 0xFFFF = no idle timeout +** +** Returns BT_PASS - config process started +** GAP_ERR_BAD_HANDLE - invalid handle +** +*******************************************************************************/ +UINT16 GAP_ConnSetIdleTimeout (UINT16 gap_handle, UINT16 timeout) +{ + tGAP_CCB *p_ccb; + + if ((p_ccb = gap_find_ccb_by_handle (gap_handle)) == NULL) + return (GAP_ERR_BAD_HANDLE); + + if (L2CA_SetIdleTimeout (p_ccb->connection_id, timeout, FALSE)) + return (BT_PASS); + else + return (GAP_ERR_BAD_HANDLE); +} + + + +/******************************************************************************* +** +** Function GAP_ConnGetRemoteAddr +** +** Description This function is called to get the remote BD address +** of a connection. +** +** Parameters: handle - Handle of the connection returned by GAP_ConnOpen +** +** Returns BT_PASS - closed OK +** GAP_ERR_BAD_HANDLE - invalid handle +** +*******************************************************************************/ +UINT8 *GAP_ConnGetRemoteAddr (UINT16 gap_handle) +{ + tGAP_CCB *p_ccb = gap_find_ccb_by_handle (gap_handle); + + GAP_TRACE_EVENT ("GAP_ConnGetRemoteAddr gap_handle = %d", gap_handle); + + if ((p_ccb) && (p_ccb->con_state > GAP_CCB_STATE_LISTENING)) + { + GAP_TRACE_EVENT("GAP_ConnGetRemoteAddr bda :0x%02x:0x%02x:0x%02x:0x%02x:0x%02x:0x%02x\n", \ + p_ccb->rem_dev_address[0],p_ccb->rem_dev_address[1],p_ccb->rem_dev_address[2], + p_ccb->rem_dev_address[3],p_ccb->rem_dev_address[4],p_ccb->rem_dev_address[5]); + return (p_ccb->rem_dev_address); + } + else + { + GAP_TRACE_EVENT ("GAP_ConnGetRemoteAddr return Error "); + return (NULL); + } +} + + +/******************************************************************************* +** +** Function GAP_ConnGetRemMtuSize +** +** Description Returns the remote device's MTU size +** +** Parameters: handle - Handle of the connection +** +** Returns UINT16 - maximum size buffer that can be transmitted to the peer +** +*******************************************************************************/ +UINT16 GAP_ConnGetRemMtuSize (UINT16 gap_handle) +{ + tGAP_CCB *p_ccb; + + if ((p_ccb = gap_find_ccb_by_handle (gap_handle)) == NULL) + return (0); + + return (p_ccb->rem_mtu_size); +} + +/******************************************************************************* +** +** Function GAP_ConnGetL2CAPCid +** +** Description Returns the L2CAP channel id +** +** Parameters: handle - Handle of the connection +** +** Returns UINT16 - The L2CAP channel id +** 0, if error +** +*******************************************************************************/ +UINT16 GAP_ConnGetL2CAPCid (UINT16 gap_handle) +{ + tGAP_CCB *p_ccb; + + if ((p_ccb = gap_find_ccb_by_handle (gap_handle)) == NULL) + return (0); + + return (p_ccb->connection_id); +} + + +/******************************************************************************* +** +** Function gap_connect_ind +** +** Description This function handles an inbound connection indication +** from L2CAP. This is the case where we are acting as a +** server. +** +** Returns void +** +*******************************************************************************/ +static void gap_connect_ind (BD_ADDR bd_addr, UINT16 l2cap_cid, UINT16 psm, UINT8 l2cap_id) +{ + UINT16 xx; + tGAP_CCB *p_ccb; + tBT_UUID bt_uuid = {2, {GAP_PROTOCOL_ID}}; + + /* See if we have a CCB listening for the connection */ + for (xx = 0, p_ccb = gap_cb.conn.ccb_pool; xx < GAP_MAX_CONNECTIONS; xx++, p_ccb++) + { + if ((p_ccb->con_state == GAP_CCB_STATE_LISTENING) + && (p_ccb->psm == psm) + && ((p_ccb->rem_addr_specified == FALSE) + || (!memcmp (bd_addr, p_ccb->rem_dev_address, BD_ADDR_LEN)))) + break; + } + + if (xx == GAP_MAX_CONNECTIONS) + { + GAP_TRACE_WARNING("*******"); + GAP_TRACE_WARNING("WARNING: GAP Conn Indication for Unexpected Bd Addr...Disconnecting"); + GAP_TRACE_WARNING("*******"); + + /* Disconnect because it is an unexpected connection */ + L2CA_DISCONNECT_REQ (l2cap_cid); + return; + } + + /* Transition to the next appropriate state, waiting for config setup. */ + p_ccb->con_state = GAP_CCB_STATE_CFG_SETUP; + + /* Save the BD Address and Channel ID. */ + memcpy (&p_ccb->rem_dev_address[0], bd_addr, BD_ADDR_LEN); + p_ccb->connection_id = l2cap_cid; + + /* Send response to the L2CAP layer. */ + L2CA_CONNECT_RSP (bd_addr, l2cap_id, l2cap_cid, L2CAP_CONN_OK, L2CAP_CONN_OK, &p_ccb->ertm_info, &bt_uuid); + + GAP_TRACE_EVENT("GAP_CONN - Rcvd L2CAP conn ind, CID: 0x%x", p_ccb->connection_id); + + /* Send a Configuration Request. */ + L2CA_CONFIG_REQ (l2cap_cid, &p_ccb->cfg); +} + +/******************************************************************************* +** +** Function gap_checks_con_flags +** +** Description This function processes the L2CAP configuration indication +** event. +** +** Returns void +** +*******************************************************************************/ +static void gap_checks_con_flags (tGAP_CCB *p_ccb) +{ + GAP_TRACE_EVENT ("gap_checks_con_flags conn_flags:0x%x, ", p_ccb->con_flags); + /* if all the required con_flags are set, report the OPEN event now */ + if ((p_ccb->con_flags & GAP_CCB_FLAGS_CONN_DONE) == GAP_CCB_FLAGS_CONN_DONE) + { + p_ccb->con_state = GAP_CCB_STATE_CONNECTED; + + p_ccb->p_callback (p_ccb->gap_handle, GAP_EVT_CONN_OPENED); + } +} + +/******************************************************************************* +** +** Function gap_sec_check_complete +** +** Description The function called when Security Manager finishes +** verification of the service side connection +** +** Returns void +** +*******************************************************************************/ +static void gap_sec_check_complete (BD_ADDR bd_addr, tBT_TRANSPORT transport, void *p_ref_data, UINT8 res) +{ + tGAP_CCB *p_ccb = (tGAP_CCB *)p_ref_data; + UNUSED(bd_addr); + UNUSED (transport); + + GAP_TRACE_EVENT ("gap_sec_check_complete conn_state:%d, conn_flags:0x%x, status:%d", + p_ccb->con_state, p_ccb->con_flags, res); + if (p_ccb->con_state == GAP_CCB_STATE_IDLE) + return; + + if (res == BTM_SUCCESS) + { + p_ccb->con_flags |= GAP_CCB_FLAGS_SEC_DONE; + gap_checks_con_flags (p_ccb); + } + else + { + /* security failed - disconnect the channel */ + L2CA_DISCONNECT_REQ (p_ccb->connection_id); + } +} + +/******************************************************************************* +** +** Function gap_connect_cfm +** +** Description This function handles the connect confirm events +** from L2CAP. This is the case when we are acting as a +** client and have sent a connect request. +** +** Returns void +** +*******************************************************************************/ +static void gap_connect_cfm (UINT16 l2cap_cid, UINT16 result) +{ + tGAP_CCB *p_ccb; + + /* Find CCB based on CID */ + if ((p_ccb = gap_find_ccb_by_cid (l2cap_cid)) == NULL) + return; + + /* initiate security process, if needed */ + if ( (p_ccb->con_flags & GAP_CCB_FLAGS_SEC_DONE) == 0) + { + btm_sec_mx_access_request (p_ccb->rem_dev_address, p_ccb->psm, TRUE, + 0, 0, &gap_sec_check_complete, p_ccb); + } + + /* If the connection response contains success status, then */ + /* Transition to the next state and startup the timer. */ + if ((result == L2CAP_CONN_OK) && (p_ccb->con_state == GAP_CCB_STATE_CONN_SETUP)) + { + p_ccb->con_state = GAP_CCB_STATE_CFG_SETUP; + + /* Send a Configuration Request. */ + L2CA_CONFIG_REQ (l2cap_cid, &p_ccb->cfg); + } + else + { + /* Tell the user if he has a callback */ + if (p_ccb->p_callback) + (*p_ccb->p_callback) (p_ccb->gap_handle, GAP_EVT_CONN_CLOSED); + + gap_release_ccb (p_ccb); + } +} + +/******************************************************************************* +** +** Function gap_config_ind +** +** Description This function processes the L2CAP configuration indication +** event. +** +** Returns void +** +*******************************************************************************/ +static void gap_config_ind (UINT16 l2cap_cid, tL2CAP_CFG_INFO *p_cfg) +{ + tGAP_CCB *p_ccb; + UINT16 local_mtu_size; + + /* Find CCB based on CID */ + if ((p_ccb = gap_find_ccb_by_cid (l2cap_cid)) == NULL) + return; + + /* Remember the remote MTU size */ + + if (p_ccb->cfg.fcr.mode == L2CAP_FCR_ERTM_MODE) + { + local_mtu_size = GKI_get_pool_bufsize (p_ccb->ertm_info.user_tx_pool_id) + - sizeof(BT_HDR) - L2CAP_MIN_OFFSET; + } + else + local_mtu_size = L2CAP_MTU_SIZE; + + if ((!p_cfg->mtu_present)||(p_cfg->mtu > local_mtu_size)) + { + p_ccb->rem_mtu_size = local_mtu_size; + } + else + p_ccb->rem_mtu_size = p_cfg->mtu; + + /* For now, always accept configuration from the other side */ + p_cfg->flush_to_present = FALSE; + p_cfg->mtu_present = FALSE; + p_cfg->result = L2CAP_CFG_OK; + p_cfg->fcs_present = FALSE; + + L2CA_CONFIG_RSP (l2cap_cid, p_cfg); + + p_ccb->con_flags |= GAP_CCB_FLAGS_HIS_CFG_DONE; + + gap_checks_con_flags (p_ccb); +} + + +/******************************************************************************* +** +** Function gap_config_cfm +** +** Description This function processes the L2CAP configuration confirmation +** event. +** +** Returns void +** +*******************************************************************************/ +static void gap_config_cfm (UINT16 l2cap_cid, tL2CAP_CFG_INFO *p_cfg) +{ + tGAP_CCB *p_ccb; + + /* Find CCB based on CID */ + if ((p_ccb = gap_find_ccb_by_cid (l2cap_cid)) == NULL) + return; + + if (p_cfg->result == L2CAP_CFG_OK) + { + p_ccb->con_flags |= GAP_CCB_FLAGS_MY_CFG_DONE; + + + if (p_ccb->cfg.fcr_present) + p_ccb->cfg.fcr.mode = p_cfg->fcr.mode; + else + p_ccb->cfg.fcr.mode = L2CAP_FCR_BASIC_MODE; + + gap_checks_con_flags (p_ccb); + } + else + { + p_ccb->p_callback (p_ccb->gap_handle, GAP_EVT_CONN_CLOSED); + gap_release_ccb (p_ccb); + } +} + + +/******************************************************************************* +** +** Function gap_disconnect_ind +** +** Description This function handles a disconnect event from L2CAP. If +** requested to, we ack the disconnect before dropping the CCB +** +** Returns void +** +*******************************************************************************/ +static void gap_disconnect_ind (UINT16 l2cap_cid, BOOLEAN ack_needed) +{ + tGAP_CCB *p_ccb; + + GAP_TRACE_EVENT ("GAP_CONN - Rcvd L2CAP disc, CID: 0x%x", l2cap_cid); + + /* Find CCB based on CID */ + if ((p_ccb = gap_find_ccb_by_cid (l2cap_cid)) == NULL) + return; + + if (ack_needed) + L2CA_DISCONNECT_RSP (l2cap_cid); + + p_ccb->p_callback (p_ccb->gap_handle, GAP_EVT_CONN_CLOSED); + gap_release_ccb (p_ccb); +} + + +/******************************************************************************* +** +** Function gap_data_ind +** +** Description This function is called when data is received from L2CAP. +** +** Returns void +** +*******************************************************************************/ +static void gap_data_ind (UINT16 l2cap_cid, BT_HDR *p_msg) +{ + tGAP_CCB *p_ccb; + + /* Find CCB based on CID */ + if ((p_ccb = gap_find_ccb_by_cid (l2cap_cid)) == NULL) + { + GKI_freebuf (p_msg); + return; + } + + if (p_ccb->con_state == GAP_CCB_STATE_CONNECTED) + { + GKI_enqueue (&p_ccb->rx_queue, p_msg); + + p_ccb->rx_queue_size += p_msg->len; + /* + GAP_TRACE_EVENT ("gap_data_ind - rx_queue_size=%d, msg len=%d", + p_ccb->rx_queue_size, p_msg->len); + */ + + p_ccb->p_callback (p_ccb->gap_handle, GAP_EVT_CONN_DATA_AVAIL); + } + else + { + GKI_freebuf (p_msg); + } +} + + +/******************************************************************************* +** +** Function gap_congestion_ind +** +** Description This is a callback function called by L2CAP when +** data L2CAP congestion status changes +** +*******************************************************************************/ +static void gap_congestion_ind (UINT16 lcid, BOOLEAN is_congested) +{ + tGAP_CCB *p_ccb; + UINT16 event; + BT_HDR *p_buf; + UINT8 status; + + GAP_TRACE_EVENT ("GAP_CONN - Rcvd L2CAP Is Congested (%d), CID: 0x%x", + is_congested, lcid); + + /* Find CCB based on CID */ + if ((p_ccb = gap_find_ccb_by_cid (lcid)) == NULL) + return; + + p_ccb->is_congested = is_congested; + + event = (is_congested) ? GAP_EVT_CONN_CONGESTED : GAP_EVT_CONN_UNCONGESTED; + p_ccb->p_callback (p_ccb->gap_handle, event); + + if (!is_congested) + { + while ((p_buf = (BT_HDR *)GKI_dequeue (&p_ccb->tx_queue)) != NULL) + { + status = L2CA_DATA_WRITE (p_ccb->connection_id, p_buf); + + if (status == L2CAP_DW_CONGESTED) + { + p_ccb->is_congested = TRUE; + break; + } + else if (status != L2CAP_DW_SUCCESS) + break; + } + } +} + + +/******************************************************************************* +** +** Function gap_find_ccb_by_cid +** +** Description This function searches the CCB table for an entry with the +** passed CID. +** +** Returns the CCB address, or NULL if not found. +** +*******************************************************************************/ +static tGAP_CCB *gap_find_ccb_by_cid (UINT16 cid) +{ + UINT16 xx; + tGAP_CCB *p_ccb; + + /* Look through each connection control block */ + for (xx = 0, p_ccb = gap_cb.conn.ccb_pool; xx < GAP_MAX_CONNECTIONS; xx++, p_ccb++) + { + if ((p_ccb->con_state != GAP_CCB_STATE_IDLE) && (p_ccb->connection_id == cid)) + return (p_ccb); + } + + /* If here, not found */ + return (NULL); +} + + +/******************************************************************************* +** +** Function gap_find_ccb_by_handle +** +** Description This function searches the CCB table for an entry with the +** passed handle. +** +** Returns the CCB address, or NULL if not found. +** +*******************************************************************************/ +static tGAP_CCB *gap_find_ccb_by_handle (UINT16 handle) +{ + tGAP_CCB *p_ccb; + + /* Check that handle is valid */ + if (handle < GAP_MAX_CONNECTIONS) + { + p_ccb = &gap_cb.conn.ccb_pool[handle]; + + if (p_ccb->con_state != GAP_CCB_STATE_IDLE) + return (p_ccb); + } + + /* If here, handle points to invalid connection */ + return (NULL); +} + + +/******************************************************************************* +** +** Function gap_allocate_ccb +** +** Description This function allocates a new CCB. +** +** Returns CCB address, or NULL if none available. +** +*******************************************************************************/ +static tGAP_CCB *gap_allocate_ccb (void) +{ + UINT16 xx; + tGAP_CCB *p_ccb; + + /* Look through each connection control block for a free one */ + for (xx = 0, p_ccb = gap_cb.conn.ccb_pool; xx < GAP_MAX_CONNECTIONS; xx++, p_ccb++) + { + if (p_ccb->con_state == GAP_CCB_STATE_IDLE) + { + memset (p_ccb, 0, sizeof (tGAP_CCB)); + + p_ccb->gap_handle = xx; + p_ccb->rem_mtu_size = L2CAP_MTU_SIZE; + + return (p_ccb); + } + } + + /* If here, no free CCB found */ + return (NULL); +} + + +/******************************************************************************* +** +** Function gap_release_ccb +** +** Description This function releases a CCB. +** +** Returns void +** +*******************************************************************************/ +static void gap_release_ccb (tGAP_CCB *p_ccb) +{ + UINT16 xx; + UINT16 psm = p_ccb->psm; + UINT8 service_id = p_ccb->service_id; + + /* Drop any buffers we may be holding */ + p_ccb->rx_queue_size = 0; + + while (p_ccb->rx_queue._p_first) + GKI_freebuf (GKI_dequeue (&p_ccb->rx_queue)); + + while (p_ccb->tx_queue._p_first) + GKI_freebuf (GKI_dequeue (&p_ccb->tx_queue)); + + p_ccb->con_state = GAP_CCB_STATE_IDLE; + + /* If no-one else is using the PSM, deregister from L2CAP */ + for (xx = 0, p_ccb = gap_cb.conn.ccb_pool; xx < GAP_MAX_CONNECTIONS; xx++, p_ccb++) + { + if ((p_ccb->con_state != GAP_CCB_STATE_IDLE) && (p_ccb->psm == psm)) + return; + } + + /* Free the security record for this PSM */ + BTM_SecClrService(service_id); + L2CA_DEREGISTER (psm); +} + +#if (GAP_CONN_POST_EVT_INCLUDED == TRUE) + +/******************************************************************************* +** +** Function gap_send_event +** +** Description Send BT_EVT_TO_GAP_MSG event to BTU task +** +** Returns None +** +*******************************************************************************/ +void gap_send_event (UINT16 gap_handle) +{ + BT_HDR *p_msg; + + if ((p_msg = (BT_HDR*)GKI_getbuf(BT_HDR_SIZE)) != NULL) + { + p_msg->event = BT_EVT_TO_GAP_MSG; + p_msg->len = 0; + p_msg->offset = 0; + p_msg->layer_specific = gap_handle; + + GKI_send_msg(BTU_TASK, BTU_HCI_RCV_MBOX, p_msg); + } + else + { + GAP_TRACE_ERROR("Unable to allocate message buffer for event."); + } +} + +/******************************************************************************* +** +** Function gap_proc_btu_event +** +** Description Event handler for BT_EVT_TO_GAP_MSG event from BTU task +** +** Returns None +** +*******************************************************************************/ +void gap_proc_btu_event(BT_HDR *p_msg) +{ + tGAP_CCB *p_ccb = gap_find_ccb_by_handle (p_msg->layer_specific); + UINT8 status; + BT_HDR *p_buf; + + if (!p_ccb) + { + return; + } + + if (p_ccb->con_state != GAP_CCB_STATE_CONNECTED) + { + return; + } + + if (p_ccb->is_congested) + { + return; + } + + /* Send the buffer through L2CAP */ + + while ((p_buf = (BT_HDR *)GKI_dequeue (&p_ccb->tx_queue)) != NULL) + { + status = L2CA_DATA_WRITE (p_ccb->connection_id, p_buf); + + if (status == L2CAP_DW_CONGESTED) + { + p_ccb->is_congested = TRUE; + break; + } + else if (status != L2CAP_DW_SUCCESS) + break; + } + +} +#endif /* (GAP_CONN_POST_EVT_INCLUDED == TRUE) */ +#endif /* GAP_CONN_INCLUDED */ diff --git a/components/bt/bluedroid/stack/gap/gap_utils.c b/components/bt/bluedroid/stack/gap/gap_utils.c new file mode 100755 index 0000000000..16f1571072 --- /dev/null +++ b/components/bt/bluedroid/stack/gap/gap_utils.c @@ -0,0 +1,142 @@ +/****************************************************************************** + * + * Copyright (C) 2009-2013 Broadcom Corporation + * + * 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. + * + ******************************************************************************/ + +#include +#include "bt_target.h" +//#include "bt_utils.h" +#include "gap_int.h" + +/******************************************************************************* +** +** Function gap_allocate_cb +** +** Description Look through the GAP Control Blocks for a free one. +** +** Returns Pointer to the control block or NULL if not found +** +*******************************************************************************/ +tGAP_INFO *gap_allocate_cb (void) +{ + tGAP_INFO *p_cb = &gap_cb.blk[0]; + UINT8 x; + + for (x = 0; x < GAP_MAX_BLOCKS; x++, p_cb++) + { + if (!p_cb->in_use) + { + memset (p_cb, 0, sizeof (tGAP_INFO)); + + p_cb->in_use = TRUE; + p_cb->index = x; + p_cb->p_data = (void *)NULL; + return (p_cb); + } + } + + /* If here, no free control blocks found */ + return (NULL); +} + + +/******************************************************************************* +** +** Function gap_free_cb +** +** Description Release GAP control block. +** +** Returns Pointer to the control block or NULL if not found +** +*******************************************************************************/ +void gap_free_cb (tGAP_INFO *p_cb) +{ + if (p_cb) + { + p_cb->gap_cback = NULL; + p_cb->in_use = FALSE; + } +} + + +/******************************************************************************* +** +** Function gap_is_service_busy +** +** Description Look through the GAP Control Blocks that are in use +** and check to see if the event waiting for is the command +** requested. +** +** Returns TRUE if already in use +** FALSE if not busy +** +*******************************************************************************/ +BOOLEAN gap_is_service_busy (UINT16 request) +{ + tGAP_INFO *p_cb = &gap_cb.blk[0]; + UINT8 x; + + for (x = 0; x < GAP_MAX_BLOCKS; x++, p_cb++) + { + if (p_cb->in_use && p_cb->event == request) + return (TRUE); + } + + /* If here, service is not busy */ + return (FALSE); +} + + +/******************************************************************************* +** +** Function gap_convert_btm_status +** +** Description Converts a BTM error status into a GAP error status +** +** +** Returns GAP_UNKNOWN_BTM_STATUS is returned if not recognized +** +*******************************************************************************/ +UINT16 gap_convert_btm_status (tBTM_STATUS btm_status) +{ + switch (btm_status) + { + case BTM_SUCCESS: + return (BT_PASS); + + case BTM_CMD_STARTED: + return (GAP_CMD_INITIATED); + + case BTM_BUSY: + return (GAP_ERR_BUSY); + + case BTM_MODE_UNSUPPORTED: + case BTM_ILLEGAL_VALUE: + return (GAP_ERR_ILL_PARM); + + case BTM_WRONG_MODE: + return (GAP_DEVICE_NOT_UP); + + case BTM_UNKNOWN_ADDR: + return (GAP_BAD_BD_ADDR); + + case BTM_DEVICE_TIMEOUT: + return (GAP_ERR_TIMEOUT); + + default: + return (GAP_ERR_PROCESSING); + } +} diff --git a/components/bt/bluedroid/stack/gatt/att_protocol.c b/components/bt/bluedroid/stack/gatt/att_protocol.c new file mode 100755 index 0000000000..00512e2c99 --- /dev/null +++ b/components/bt/bluedroid/stack/gatt/att_protocol.c @@ -0,0 +1,634 @@ +/****************************************************************************** + * + * Copyright (C) 2008-2014 Broadcom Corporation + * + * 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 ATT protocol functions + * + ******************************************************************************/ + +#include "bt_target.h" + +#if BLE_INCLUDED == TRUE + +#include "gatt_int.h" +#include "l2c_api.h" + +#define GATT_HDR_FIND_TYPE_VALUE_LEN 21 +#define GATT_OP_CODE_SIZE 1 +/********************************************************************** +** ATT protocl message building utility * +***********************************************************************/ +/******************************************************************************* +** +** Function attp_build_mtu_exec_cmd +** +** Description Build a exchange MTU request +** +** Returns None. +** +*******************************************************************************/ +BT_HDR *attp_build_mtu_cmd(UINT8 op_code, UINT16 rx_mtu) +{ + BT_HDR *p_buf = NULL; + UINT8 *p; + + if ((p_buf = (BT_HDR *)GKI_getbuf(sizeof(BT_HDR) + GATT_HDR_SIZE + L2CAP_MIN_OFFSET)) != NULL) + { + p = (UINT8 *)(p_buf + 1) + L2CAP_MIN_OFFSET; + + UINT8_TO_STREAM (p, op_code); + UINT16_TO_STREAM (p, rx_mtu); + + p_buf->offset = L2CAP_MIN_OFFSET; + p_buf->len = GATT_HDR_SIZE; /* opcode + 2 bytes mtu */ + } + return p_buf; +} +/******************************************************************************* +** +** Function attp_build_exec_write_cmd +** +** Description Build a execute write request or response. +** +** Returns None. +** +*******************************************************************************/ +BT_HDR *attp_build_exec_write_cmd (UINT8 op_code, UINT8 flag) +{ + BT_HDR *p_buf = NULL; + UINT8 *p; + + if ((p_buf = (BT_HDR *)GKI_getpoolbuf(GATT_BUF_POOL_ID)) != NULL) + { + p = (UINT8 *)(p_buf + 1) + L2CAP_MIN_OFFSET; + + p_buf->offset = L2CAP_MIN_OFFSET; + p_buf->len = GATT_OP_CODE_SIZE; + + UINT8_TO_STREAM (p, op_code); + + if (op_code == GATT_REQ_EXEC_WRITE) + { + flag &= GATT_PREP_WRITE_EXEC; + UINT8_TO_STREAM (p, flag); + p_buf->len += 1; + } + + } + + return p_buf; +} + +/******************************************************************************* +** +** Function attp_build_err_cmd +** +** Description Build a exchange MTU request +** +** Returns None. +** +*******************************************************************************/ +BT_HDR *attp_build_err_cmd(UINT8 cmd_code, UINT16 err_handle, UINT8 reason) +{ + BT_HDR *p_buf = NULL; + UINT8 *p; + + if ((p_buf = (BT_HDR *)GKI_getbuf(sizeof(BT_HDR) + L2CAP_MIN_OFFSET + 5)) != NULL) + { + p = (UINT8 *)(p_buf + 1) + L2CAP_MIN_OFFSET; + + UINT8_TO_STREAM (p, GATT_RSP_ERROR); + UINT8_TO_STREAM (p, cmd_code); + UINT16_TO_STREAM(p, err_handle); + UINT8_TO_STREAM (p, reason); + + p_buf->offset = L2CAP_MIN_OFFSET; + /* GATT_HDR_SIZE (1B ERR_RSP op code+ 2B handle) + 1B cmd_op_code + 1B status */ + p_buf->len = GATT_HDR_SIZE + 1 + 1; + } + return p_buf; +} +/******************************************************************************* +** +** Function attp_build_browse_cmd +** +** Description Build a read information request or read by type request +** +** Returns None. +** +*******************************************************************************/ +BT_HDR *attp_build_browse_cmd(UINT8 op_code, UINT16 s_hdl, UINT16 e_hdl, tBT_UUID uuid) +{ + BT_HDR *p_buf = NULL; + UINT8 *p; + + if ((p_buf = (BT_HDR *)GKI_getbuf(sizeof(BT_HDR) + 8 + L2CAP_MIN_OFFSET)) != NULL) + { + p = (UINT8 *)(p_buf + 1) + L2CAP_MIN_OFFSET; + /* Describe the built message location and size */ + p_buf->offset = L2CAP_MIN_OFFSET; + p_buf->len = GATT_OP_CODE_SIZE + 4; + + UINT8_TO_STREAM (p, op_code); + UINT16_TO_STREAM (p, s_hdl); + UINT16_TO_STREAM (p, e_hdl); + p_buf->len += gatt_build_uuid_to_stream(&p, uuid); + } + + return p_buf; +} +/******************************************************************************* +** +** Function attp_build_read_handles_cmd +** +** Description Build a read by type and value request. +** +** Returns pointer to the command buffer. +** +*******************************************************************************/ +BT_HDR *attp_build_read_by_type_value_cmd (UINT16 payload_size, tGATT_FIND_TYPE_VALUE *p_value_type) +{ + BT_HDR *p_buf = NULL; + UINT8 *p; + UINT16 len = p_value_type->value_len; + + if ((p_buf = (BT_HDR *)GKI_getbuf((UINT16)(sizeof(BT_HDR) + payload_size + L2CAP_MIN_OFFSET))) != NULL) + { + p = (UINT8 *)(p_buf + 1) + L2CAP_MIN_OFFSET; + + p_buf->offset = L2CAP_MIN_OFFSET; + p_buf->len = 5; /* opcode + s_handle + e_handle */ + + UINT8_TO_STREAM (p, GATT_REQ_FIND_TYPE_VALUE); + UINT16_TO_STREAM (p, p_value_type->s_handle); + UINT16_TO_STREAM (p, p_value_type->e_handle); + + p_buf->len += gatt_build_uuid_to_stream(&p, p_value_type->uuid); + + if (p_value_type->value_len + p_buf->len > payload_size ) + len = payload_size - p_buf->len; + + memcpy (p, p_value_type->value, len); + p_buf->len += len; + } + + return p_buf; +} +/******************************************************************************* +** +** Function attp_build_read_multi_cmd +** +** Description Build a read multiple request +** +** Returns None. +** +*******************************************************************************/ +BT_HDR *attp_build_read_multi_cmd(UINT16 payload_size, UINT16 num_handle, UINT16 *p_handle) +{ + BT_HDR *p_buf = NULL; + UINT8 *p, i = 0; + + if ((p_buf = (BT_HDR *)GKI_getbuf((UINT16)(sizeof(BT_HDR) + num_handle * 2 + 1 + L2CAP_MIN_OFFSET))) != NULL) + { + p = (UINT8 *)(p_buf + 1) + L2CAP_MIN_OFFSET; + + p_buf->offset = L2CAP_MIN_OFFSET; + p_buf->len = 1; + + UINT8_TO_STREAM (p, GATT_REQ_READ_MULTI); + + for (i = 0; i < num_handle && p_buf->len + 2 <= payload_size; i ++) + { + UINT16_TO_STREAM (p, *(p_handle + i)); + p_buf->len += 2; + } + } + + return p_buf; +} +/******************************************************************************* +** +** Function attp_build_handle_cmd +** +** Description Build a read /read blob request +** +** Returns None. +** +*******************************************************************************/ +BT_HDR *attp_build_handle_cmd(UINT8 op_code, UINT16 handle, UINT16 offset) +{ + BT_HDR *p_buf = NULL; + UINT8 *p; + + if ((p_buf = (BT_HDR *)GKI_getbuf(sizeof(BT_HDR) + 5 + L2CAP_MIN_OFFSET)) != NULL) + { + p = (UINT8 *)(p_buf + 1) + L2CAP_MIN_OFFSET; + + p_buf->offset = L2CAP_MIN_OFFSET; + + UINT8_TO_STREAM (p, op_code); + p_buf->len = 1; + + UINT16_TO_STREAM (p, handle); + p_buf->len += 2; + + if (op_code == GATT_REQ_READ_BLOB) + { + UINT16_TO_STREAM (p, offset); + p_buf->len += 2; + } + + } + + return p_buf; +} +/******************************************************************************* +** +** Function attp_build_opcode_cmd +** +** Description Build a request/response with opcode only. +** +** Returns None. +** +*******************************************************************************/ +BT_HDR *attp_build_opcode_cmd(UINT8 op_code) +{ + BT_HDR *p_buf = NULL; + UINT8 *p; + + if ((p_buf = (BT_HDR *)GKI_getbuf(sizeof(BT_HDR) + 1 + L2CAP_MIN_OFFSET)) != NULL) + { + p = (UINT8 *)(p_buf + 1) + L2CAP_MIN_OFFSET; + p_buf->offset = L2CAP_MIN_OFFSET; + + UINT8_TO_STREAM (p, op_code); + p_buf->len = 1; + } + + return p_buf; +} +/******************************************************************************* +** +** Function attp_build_value_cmd +** +** Description Build a attribute value request +** +** Returns None. +** +*******************************************************************************/ +BT_HDR *attp_build_value_cmd (UINT16 payload_size, UINT8 op_code, UINT16 handle, + UINT16 offset, UINT16 len, UINT8 *p_data) +{ + BT_HDR *p_buf = NULL; + UINT8 *p, *pp, pair_len, *p_pair_len; + + if ((p_buf = (BT_HDR *)GKI_getbuf((UINT16)(sizeof(BT_HDR) + payload_size + L2CAP_MIN_OFFSET))) != NULL) + { + p = pp =(UINT8 *)(p_buf + 1) + L2CAP_MIN_OFFSET; + + UINT8_TO_STREAM (p, op_code); + p_buf->offset = L2CAP_MIN_OFFSET; + p_buf->len = 1; + + if (op_code == GATT_RSP_READ_BY_TYPE) + { + p_pair_len = p; + pair_len = len + 2; + UINT8_TO_STREAM (p, pair_len); + p_buf->len += 1; + } + if (op_code != GATT_RSP_READ_BLOB && op_code != GATT_RSP_READ) + { + UINT16_TO_STREAM (p, handle); + p_buf->len += 2; + } + + if (op_code == GATT_REQ_PREPARE_WRITE ||op_code == GATT_RSP_PREPARE_WRITE ) + { + UINT16_TO_STREAM (p, offset); + p_buf->len += 2; + } + + if (len > 0 && p_data != NULL) + { + /* ensure data not exceed MTU size */ + if (payload_size - p_buf->len < len) + { + len = payload_size - p_buf->len; + /* update handle value pair length */ + if (op_code == GATT_RSP_READ_BY_TYPE) + *p_pair_len = (len + 2); + + GATT_TRACE_WARNING("attribute value too long, to be truncated to %d", len); + } + + ARRAY_TO_STREAM (p, p_data, len); + p_buf->len += len; + } + } + return p_buf; +} + +/******************************************************************************* +** +** Function attp_send_msg_to_l2cap +** +** Description Send message to L2CAP. +** +*******************************************************************************/ +tGATT_STATUS attp_send_msg_to_l2cap(tGATT_TCB *p_tcb, BT_HDR *p_toL2CAP) +{ + UINT16 l2cap_ret; + + + if (p_tcb->att_lcid == L2CAP_ATT_CID) + l2cap_ret = L2CA_SendFixedChnlData (L2CAP_ATT_CID, p_tcb->peer_bda, p_toL2CAP); + else + l2cap_ret = (UINT16) L2CA_DataWrite (p_tcb->att_lcid, p_toL2CAP); + + if (l2cap_ret == L2CAP_DW_FAILED) + { + GATT_TRACE_ERROR("ATT failed to pass msg:0x%0x to L2CAP", + *((UINT8 *)(p_toL2CAP + 1) + p_toL2CAP->offset)); + return GATT_INTERNAL_ERROR; + } + else if (l2cap_ret == L2CAP_DW_CONGESTED) + { + GATT_TRACE_DEBUG("ATT congested, message accepted"); + return GATT_CONGESTED; + } + return GATT_SUCCESS; +} + +/******************************************************************************* +** +** Function attp_build_sr_msg +** +** Description Build ATT Server PDUs. +** +*******************************************************************************/ +BT_HDR *attp_build_sr_msg(tGATT_TCB *p_tcb, UINT8 op_code, tGATT_SR_MSG *p_msg) +{ + BT_HDR *p_cmd = NULL; + UINT16 offset = 0; + + switch (op_code) + { + case GATT_RSP_READ_BLOB: + case GATT_RSP_PREPARE_WRITE: + GATT_TRACE_EVENT ("ATT_RSP_READ_BLOB/GATT_RSP_PREPARE_WRITE: len = %d offset = %d", + p_msg->attr_value.len, p_msg->attr_value.offset); + offset = p_msg->attr_value.offset; +/* Coverity: [FALSE-POSITIVE error] intended fall through */ +/* Missing break statement between cases in switch statement */ + /* fall through */ + case GATT_RSP_READ_BY_TYPE: + case GATT_RSP_READ: + case GATT_HANDLE_VALUE_NOTIF: + case GATT_HANDLE_VALUE_IND: + p_cmd = attp_build_value_cmd(p_tcb->payload_size, + op_code, + p_msg->attr_value.handle, + offset, + p_msg->attr_value.len, + p_msg->attr_value.value); + break; + + case GATT_RSP_WRITE: + p_cmd = attp_build_opcode_cmd(op_code); + break; + + case GATT_RSP_ERROR: + p_cmd = attp_build_err_cmd(p_msg->error.cmd_code, p_msg->error.handle, p_msg->error.reason); + break; + + case GATT_RSP_EXEC_WRITE: + p_cmd = attp_build_exec_write_cmd(op_code, 0); + break; + + case GATT_RSP_MTU: + p_cmd = attp_build_mtu_cmd(op_code, p_msg->mtu); + break; + + default: + GATT_TRACE_DEBUG("attp_build_sr_msg: unknown op code = %d", op_code); + break; + } + + if (!p_cmd) + GATT_TRACE_ERROR("No resources"); + + return p_cmd; +} + +/******************************************************************************* +** +** Function attp_send_sr_msg +** +** Description This function sends the server response or indication message +** to client. +** +** Parameter p_tcb: pointer to the connecton control block. +** p_msg: pointer to message parameters structure. +** +** Returns GATT_SUCCESS if sucessfully sent; otherwise error code. +** +** +*******************************************************************************/ +tGATT_STATUS attp_send_sr_msg (tGATT_TCB *p_tcb, BT_HDR *p_msg) +{ + tGATT_STATUS cmd_sent = GATT_NO_RESOURCES; + + if (p_tcb != NULL) + { + if (p_msg != NULL) + { + p_msg->offset = L2CAP_MIN_OFFSET; + cmd_sent = attp_send_msg_to_l2cap (p_tcb, p_msg); + } + } + return cmd_sent; +} + +/******************************************************************************* +** +** Function attp_cl_send_cmd +** +** Description Send a ATT command or enqueue it. +** +** Returns GATT_SUCCESS if command sent +** GATT_CONGESTED if command sent but channel congested +** GATT_CMD_STARTED if command queue up in GATT +** GATT_ERROR if command sending failure +** +*******************************************************************************/ +tGATT_STATUS attp_cl_send_cmd(tGATT_TCB *p_tcb, UINT16 clcb_idx, UINT8 cmd_code, BT_HDR *p_cmd) +{ + tGATT_STATUS att_ret = GATT_SUCCESS; + + if (p_tcb != NULL) + { + cmd_code &= ~GATT_AUTH_SIGN_MASK; + + /* no pending request or value confirmation */ + if (p_tcb->pending_cl_req == p_tcb->next_slot_inq || + cmd_code == GATT_HANDLE_VALUE_CONF) + { + att_ret = attp_send_msg_to_l2cap(p_tcb, p_cmd); + if (att_ret == GATT_CONGESTED || att_ret == GATT_SUCCESS) + { + /* do not enq cmd if handle value confirmation or set request */ + if (cmd_code != GATT_HANDLE_VALUE_CONF && cmd_code != GATT_CMD_WRITE) + { + gatt_start_rsp_timer (clcb_idx); + gatt_cmd_enq(p_tcb, clcb_idx, FALSE, cmd_code, NULL); + } + } + else + att_ret = GATT_INTERNAL_ERROR; + } + else + { + att_ret = GATT_CMD_STARTED; + gatt_cmd_enq(p_tcb, clcb_idx, TRUE, cmd_code, p_cmd); + } + } + else + att_ret = GATT_ERROR; + + return att_ret; +} +/******************************************************************************* +** +** Function attp_send_cl_msg +** +** Description This function sends the client request or confirmation message +** to server. +** +** Parameter p_tcb: pointer to the connectino control block. +** clcb_idx: clcb index +** op_code: message op code. +** p_msg: pointer to message parameters structure. +** +** Returns GATT_SUCCESS if sucessfully sent; otherwise error code. +** +** +*******************************************************************************/ +tGATT_STATUS attp_send_cl_msg (tGATT_TCB *p_tcb, UINT16 clcb_idx, UINT8 op_code, tGATT_CL_MSG *p_msg) +{ + tGATT_STATUS status = GATT_NO_RESOURCES; + BT_HDR *p_cmd = NULL; + UINT16 offset = 0, handle; + + if (p_tcb != NULL) + { + switch (op_code) + { + case GATT_REQ_MTU: + if (p_msg->mtu <= GATT_MAX_MTU_SIZE) + { + p_tcb->payload_size = p_msg->mtu; + p_cmd = attp_build_mtu_cmd(GATT_REQ_MTU, p_msg->mtu); + } + else + status = GATT_ILLEGAL_PARAMETER; + break; + + case GATT_REQ_FIND_INFO: + case GATT_REQ_READ_BY_TYPE: + case GATT_REQ_READ_BY_GRP_TYPE: + if (GATT_HANDLE_IS_VALID (p_msg->browse.s_handle) && + GATT_HANDLE_IS_VALID (p_msg->browse.e_handle) && + p_msg->browse.s_handle <= p_msg->browse.e_handle) + { + p_cmd = attp_build_browse_cmd(op_code, + p_msg->browse.s_handle, + p_msg->browse.e_handle, + p_msg->browse.uuid); + } + else + status = GATT_ILLEGAL_PARAMETER; + break; + + case GATT_REQ_READ_BLOB: + offset = p_msg->read_blob.offset; + /* fall through */ + case GATT_REQ_READ: + handle = (op_code == GATT_REQ_READ) ? p_msg->handle: p_msg->read_blob.handle; + /* handle checking */ + if (GATT_HANDLE_IS_VALID (handle)) + { + p_cmd = attp_build_handle_cmd(op_code, handle, offset); + } + else + status = GATT_ILLEGAL_PARAMETER; + break; + + case GATT_HANDLE_VALUE_CONF: + p_cmd = attp_build_opcode_cmd(op_code); + break; + + case GATT_REQ_PREPARE_WRITE: + offset = p_msg->attr_value.offset; + /* fall through */ + case GATT_REQ_WRITE: + case GATT_CMD_WRITE: + case GATT_SIGN_CMD_WRITE: + if (GATT_HANDLE_IS_VALID (p_msg->attr_value.handle)) + { + p_cmd = attp_build_value_cmd (p_tcb->payload_size, + op_code, p_msg->attr_value.handle, + offset, + p_msg->attr_value.len, + p_msg->attr_value.value); + } + else + status = GATT_ILLEGAL_PARAMETER; + break; + + case GATT_REQ_EXEC_WRITE: + p_cmd = attp_build_exec_write_cmd(op_code, p_msg->exec_write); + break; + + case GATT_REQ_FIND_TYPE_VALUE: + p_cmd = attp_build_read_by_type_value_cmd(p_tcb->payload_size, &p_msg->find_type_value); + break; + + case GATT_REQ_READ_MULTI: + p_cmd = attp_build_read_multi_cmd(p_tcb->payload_size, + p_msg->read_multi.num_handles, + p_msg->read_multi.handles); + break; + + default: + break; + } + + if (p_cmd != NULL) + status = attp_cl_send_cmd(p_tcb, clcb_idx, op_code, p_cmd); + + } + else + { + GATT_TRACE_ERROR("Peer device not connected"); + } + + return status; +} +#endif diff --git a/components/bt/bluedroid/stack/gatt/gatt_api.c b/components/bt/bluedroid/stack/gatt/gatt_api.c new file mode 100755 index 0000000000..d5ddb19b8a --- /dev/null +++ b/components/bt/bluedroid/stack/gatt/gatt_api.c @@ -0,0 +1,1631 @@ +/****************************************************************************** + * + * Copyright (C) 1999-2012 Broadcom Corporation + * + * 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 GATT interface functions + * + ******************************************************************************/ +#include "bt_target.h" + + +#if defined(BTA_GATT_INCLUDED) && (BTA_GATT_INCLUDED == TRUE) + +#include "gki.h" +//#include +#include +#include "gatt_api.h" +#include "gatt_int.h" +#include "l2c_api.h" +#include "btm_int.h" + + +/******************************************************************************* +** +** Function GATT_SetTraceLevel +** +** Description This function sets the trace level. If called with +** a value of 0xFF, it simply returns the current trace level. +** +** Input Parameters: +** level: The level to set the GATT tracing to: +** 0xff-returns the current setting. +** 0-turns off tracing. +** >= 1-Errors. +** >= 2-Warnings. +** >= 3-APIs. +** >= 4-Events. +** >= 5-Debug. +** +** Returns The new or current trace level +** +*******************************************************************************/ +UINT8 GATT_SetTraceLevel (UINT8 new_level) +{ + if (new_level != 0xFF) + gatt_cb.trace_level = new_level; + + return(gatt_cb.trace_level); +} + +/***************************************************************************** +** +** GATT SERVER API +** +******************************************************************************/ +/******************************************************************************* +** +** Function GATTS_AddHandleRange +** +** Description This function add the allocated handles range for the specifed +** application UUID, service UUID and service instance +** +** Parameter p_hndl_range: pointer to allocated handles information +** +** Returns TRUE if handle range is added sucessfully; otherwise FALSE. +** +*******************************************************************************/ + +BOOLEAN GATTS_AddHandleRange(tGATTS_HNDL_RANGE *p_hndl_range) +{ + tGATT_HDL_LIST_ELEM *p_buf; + BOOLEAN status= FALSE; + + if ((p_buf = gatt_alloc_hdl_buffer()) != NULL) + { + p_buf->asgn_range = *p_hndl_range; + status = gatt_add_an_item_to_list(&gatt_cb.hdl_list_info, p_buf); + } + return status; +} + + +/******************************************************************************* +** +** Function GATTS_NVRegister +** +** Description Application manager calls this function to register for +** NV save callback function. There can be one and only one +** NV save callback function. +** +** Parameter p_cb_info : callback informaiton +** +** Returns TRUE if registered OK, else FALSE +** +*******************************************************************************/ +BOOLEAN GATTS_NVRegister (tGATT_APPL_INFO *p_cb_info) +{ + BOOLEAN status= FALSE; + if (p_cb_info) + { + gatt_cb.cb_info = *p_cb_info; + status = TRUE; + gatt_init_srv_chg(); + } + + return status; +} + +/******************************************************************************* +** +** Function GATTS_CreateService +** +** Description This function is called to reserve a block of handles for a service. +** +** *** It should be called only once per service instance *** +** +** Parameter gatt_if : application if +** p_svc_uuid : service UUID +** svc_inst : instance of the service inside the application +** num_handles : number of handles needed by the service. +** is_pri : is a primary service or not. +** +** Returns service handle if sucessful, otherwise 0. +** +*******************************************************************************/ +UINT16 GATTS_CreateService (tGATT_IF gatt_if, tBT_UUID *p_svc_uuid, + UINT16 svc_inst, UINT16 num_handles, BOOLEAN is_pri) +{ + + tGATT_HDL_LIST_INFO *p_list_info= &gatt_cb.hdl_list_info; + tGATT_HDL_LIST_ELEM *p_list=NULL; + UINT16 s_hdl=0; + BOOLEAN save_hdl=FALSE; + tGATTS_PENDING_NEW_SRV_START *p_buf=NULL; + tGATT_REG *p_reg = gatt_get_regcb(gatt_if); + tBT_UUID *p_app_uuid128; + + + GATT_TRACE_API ("GATTS_CreateService" ); + + if (p_reg == NULL) + { + GATT_TRACE_ERROR ("Inavlid gatt_if=%d", gatt_if); + return(0); + } + + p_app_uuid128 = &p_reg->app_uuid128; + + if ((p_list = gatt_find_hdl_buffer_by_app_id(p_app_uuid128, p_svc_uuid, svc_inst)) != NULL) + { + s_hdl = p_list->asgn_range.s_handle; + GATT_TRACE_DEBUG ("Service already been created!!"); + } + else + { + if ( (p_svc_uuid->len == LEN_UUID_16) && (p_svc_uuid->uu.uuid16 == UUID_SERVCLASS_GATT_SERVER)) + { + s_hdl= gatt_cb.hdl_cfg.gatt_start_hdl; + } + else if ((p_svc_uuid->len == LEN_UUID_16) && (p_svc_uuid->uu.uuid16 == UUID_SERVCLASS_GAP_SERVER)) + { + s_hdl= gatt_cb.hdl_cfg.gap_start_hdl; + } + else + { + p_list = p_list_info->p_first; + + if (p_list) + { + s_hdl = p_list->asgn_range.e_handle + 1; + } + + if (s_hdl < gatt_cb.hdl_cfg.app_start_hdl) + { + + s_hdl= gatt_cb.hdl_cfg.app_start_hdl; + } + save_hdl = TRUE; + } + + /* check for space */ + if (num_handles > (0xFFFF - s_hdl + 1)) + { + GATT_TRACE_ERROR ("GATTS_ReserveHandles: no handles, s_hdl: %u needed: %u", s_hdl, num_handles); + return(0); + } + + if ( (p_list = gatt_alloc_hdl_buffer()) == NULL) + { + /* No free entry */ + GATT_TRACE_ERROR ("GATTS_ReserveHandles: no free handle blocks"); + return(0); + } + + p_list->asgn_range.app_uuid128 = *p_app_uuid128; + p_list->asgn_range.svc_uuid = *p_svc_uuid; + p_list->asgn_range.svc_inst = svc_inst; + p_list->asgn_range.s_handle = s_hdl; + p_list->asgn_range.e_handle = s_hdl+num_handles-1; + p_list->asgn_range.is_primary = is_pri; + + gatt_add_an_item_to_list(p_list_info, p_list); + + if (save_hdl) + { + if (gatt_cb.cb_info.p_nv_save_callback) + (*gatt_cb.cb_info.p_nv_save_callback)(TRUE, &p_list->asgn_range); + /* add a pending new service change item to the list */ + if ( (p_buf = gatt_add_pending_new_srv_start(&p_list->asgn_range)) == NULL) + { + /* No free entry */ + GATT_TRACE_ERROR ("gatt_add_pending_new_srv_start: no free blocks"); + + if (p_list) + { + gatt_remove_an_item_from_list(p_list_info, p_list); + gatt_free_hdl_buffer(p_list); + } + return(0); + } + + GATT_TRACE_DEBUG ("Add a new srv chg item"); + } + } + + if (!gatts_init_service_db(&p_list->svc_db, p_svc_uuid, is_pri, s_hdl , num_handles)) + { + GATT_TRACE_ERROR ("GATTS_ReserveHandles: service DB initialization failed"); + if (p_list) + { + gatt_remove_an_item_from_list(p_list_info, p_list); + gatt_free_hdl_buffer(p_list); + } + + if (p_buf) + GKI_freebuf (GKI_remove_from_queue (&gatt_cb.pending_new_srv_start_q, p_buf)); + return(0); + } + + GATT_TRACE_DEBUG ("GATTS_CreateService(success): handles needed:%u s_hdl=%u e_hdl=%u %s[%x] is_primary=%d", + num_handles, p_list->asgn_range.s_handle , p_list->asgn_range.e_handle, + ((p_list->asgn_range.svc_uuid.len == 2) ? "uuid16": "uuid128" ), + p_list->asgn_range.svc_uuid.uu.uuid16, + p_list->asgn_range.is_primary); + + return(s_hdl); +} + +/******************************************************************************* +** +** Function GATTS_AddIncludeService +** +** Description This function is called to add an included service. +** +** Parameter service_handle : To which service this included service is added to. +** include_svc_handle : included service handle. +** +** Returns included service attribute handle. If 0, add included service +** fail. +** +*******************************************************************************/ +UINT16 GATTS_AddIncludeService (UINT16 service_handle, UINT16 include_svc_handle) + +{ + tGATT_HDL_LIST_ELEM *p_decl, *p_incl_decl; + + if ((p_decl = gatt_find_hdl_buffer_by_handle(service_handle)) == NULL) + { + GATT_TRACE_DEBUG("Service not created"); + return 0; + } + if ((p_incl_decl = gatt_find_hdl_buffer_by_handle(include_svc_handle)) == NULL) + { + GATT_TRACE_DEBUG("Included Service not created"); + return 0; + } + + return gatts_add_included_service(&p_decl->svc_db, + p_incl_decl->asgn_range.s_handle, + p_incl_decl->asgn_range.e_handle, + p_incl_decl->asgn_range.svc_uuid); +} +/******************************************************************************* +** +** Function GATTS_AddCharacteristic +** +** Description This function is called to add a characteristic into a service. +** It will add a characteristic declaration and characteristic +** value declaration into the service database identified by the +** service handle. +** +** Parameter service_handle : To which service this included service is added to. +** char_uuid : Characteristic UUID. +** perm : Characteristic value declaration attribute permission. +** property : Characteristic Properties +** +** Returns Characteristic value declaration attribute handle. 0 if failed. +** +*******************************************************************************/ +UINT16 GATTS_AddCharacteristic (UINT16 service_handle, tBT_UUID *p_char_uuid, + tGATT_PERM perm,tGATT_CHAR_PROP property) +{ + tGATT_HDL_LIST_ELEM *p_decl; + + if ((p_decl = gatt_find_hdl_buffer_by_handle(service_handle)) == NULL) + { + GATT_TRACE_DEBUG("Service not created"); + return 0; + } + /* data validity checking */ + if ( ((property & GATT_CHAR_PROP_BIT_AUTH) && !(perm & GATT_WRITE_SIGNED_PERM)) || + ((perm & GATT_WRITE_SIGNED_PERM) && !(property & GATT_CHAR_PROP_BIT_AUTH)) ) + { + GATT_TRACE_DEBUG("Invalid configuration property=0x%x perm=0x%x ", property, perm); + return 0; + } + + return gatts_add_characteristic(&p_decl->svc_db, + perm, + property, + p_char_uuid); +} +/******************************************************************************* +** +** Function GATTS_AddCharDescriptor +** +** Description This function is called to add a characteristic descriptor +** into a service database. Add descriptor should follow add char +** to which it belongs, and next add char should be done only +** after all add descriptors for the previous char. +** +** Parameter service_handle : To which service this characteristic descriptor +** is added to. +** perm : Characteristic value declaration attribute +** permission. +** p_descr_uuid : Characteristic descriptor UUID +** +** Returns Characteristic descriptor attribute handle. 0 if add +** characteristic descriptor failed. +** +*******************************************************************************/ +UINT16 GATTS_AddCharDescriptor (UINT16 service_handle, + tGATT_PERM perm, + tBT_UUID * p_descr_uuid) +{ + tGATT_HDL_LIST_ELEM *p_decl; + + if ((p_decl = gatt_find_hdl_buffer_by_handle(service_handle)) == NULL) + { + GATT_TRACE_DEBUG("Service not created"); + return 0; + } + if (p_descr_uuid == NULL || + (p_descr_uuid->len != LEN_UUID_128 && p_descr_uuid->len != LEN_UUID_16 + && p_descr_uuid->len != LEN_UUID_32)) + { + GATT_TRACE_DEBUG("Illegal parameter"); + return 0; + } + + return gatts_add_char_descr(&p_decl->svc_db, + perm, + p_descr_uuid); + +} +/******************************************************************************* +** +** Function GATTS_DeleteService +** +** Description This function is called to delete a service. +** +** Parameter gatt_if : application interface +** p_svc_uuid : service UUID +** svc_inst : instance of the service inside the application +** +** Returns TRUE if operation succeed, FALSE if handle block was not found. +** +*******************************************************************************/ +BOOLEAN GATTS_DeleteService (tGATT_IF gatt_if, tBT_UUID *p_svc_uuid, UINT16 svc_inst) +{ + + tGATT_HDL_LIST_INFO *p_list_info= &gatt_cb.hdl_list_info; + tGATT_HDL_LIST_ELEM *p_list=NULL; + UINT8 i_sreg; + tGATTS_PENDING_NEW_SRV_START *p_buf; + tGATT_REG *p_reg = gatt_get_regcb(gatt_if); + tBT_UUID *p_app_uuid128; + + GATT_TRACE_DEBUG ("GATTS_DeleteService"); + + if (p_reg == NULL) + { + GATT_TRACE_ERROR ("Applicaiton not foud"); + return(FALSE); + } + p_app_uuid128 = &p_reg->app_uuid128; + + if ((p_list = gatt_find_hdl_buffer_by_app_id(p_app_uuid128, p_svc_uuid, svc_inst)) == NULL) + { + GATT_TRACE_ERROR ("No Service found"); + return(FALSE); + } + + if ( (p_buf = gatt_sr_is_new_srv_chg(&p_list->asgn_range.app_uuid128, + &p_list->asgn_range.svc_uuid, + p_list->asgn_range.svc_inst)) != NULL) + { + GATT_TRACE_DEBUG ("Delete a new service changed item - the service has not yet started"); + GKI_freebuf (GKI_remove_from_queue (&gatt_cb.pending_new_srv_start_q, p_buf)); + } + else + { + gatt_proc_srv_chg(); + } + + if ((i_sreg = gatt_sr_find_i_rcb_by_app_id (p_app_uuid128, + p_svc_uuid, + svc_inst)) != GATT_MAX_SR_PROFILES) + { + GATTS_StopService(gatt_cb.sr_reg[i_sreg].s_hdl); + } + + GATT_TRACE_DEBUG ("released handles s_hdl=%u e_hdl=%u", + p_list->asgn_range.s_handle , p_list->asgn_range.e_handle ); + + if ( (p_list->asgn_range.s_handle >= gatt_cb.hdl_cfg.app_start_hdl) + && gatt_cb.cb_info.p_nv_save_callback) + (*gatt_cb.cb_info.p_nv_save_callback)(FALSE, &p_list->asgn_range); + + gatt_remove_an_item_from_list(p_list_info, p_list); + gatt_free_hdl_buffer(p_list); + + return(TRUE); +} + +/******************************************************************************* +** +** Function GATTS_StartService +** +** Description This function is called to start a service with GATT +** +** Parameter gatt_if : service handle. +** p_cback : application service callback functions. +** sup_transport : supported transport(s) for this primary service +** +** return GATT_SUCCESS if sucessfully started; otherwise error code. +** +*******************************************************************************/ +tGATT_STATUS GATTS_StartService (tGATT_IF gatt_if, UINT16 service_handle, + tGATT_TRANSPORT sup_transport) +{ + tGATT_SR_REG *p_sreg; + tGATT_HDL_LIST_ELEM *p_list=NULL; + UINT8 i_sreg; + tBT_UUID *p_uuid; + tGATT_REG *p_reg = gatt_get_regcb(gatt_if); + + tGATTS_PENDING_NEW_SRV_START *p_buf; + + GATT_TRACE_API ("GATTS_StartService"); + + if (p_reg == NULL) + { + /* Not found */ + GATT_TRACE_ERROR ("Applicaiton not found "); + return GATT_NOT_FOUND; + } + + if ((p_list = gatt_find_hdl_buffer_by_handle(service_handle)) == NULL) + { + /* Not found */ + GATT_TRACE_ERROR ("no service found"); + return GATT_NOT_FOUND; + } + + if (gatt_sr_find_i_rcb_by_app_id (&p_list->asgn_range.app_uuid128, + &p_list->asgn_range.svc_uuid, + p_list->asgn_range.svc_inst) != GATT_MAX_SR_PROFILES) + { + GATT_TRACE_ERROR ("Duplicate Service start - Service already started"); + return GATT_SERVICE_STARTED; + } + + /*this is a new application servoce start */ + if ((i_sreg = gatt_sr_alloc_rcb(p_list)) == GATT_MAX_SR_PROFILES) + { + GATT_TRACE_ERROR ("GATTS_StartService: no free server registration block"); + return GATT_NO_RESOURCES; + } + + p_sreg = &gatt_cb.sr_reg[i_sreg]; + p_sreg->gatt_if = gatt_if; + + switch (sup_transport) + { + case GATT_TRANSPORT_BR_EDR: + case GATT_TRANSPORT_LE_BR_EDR: + if (p_sreg->type == GATT_UUID_PRI_SERVICE) + { + p_uuid = gatts_get_service_uuid (p_sreg->p_db); + + p_sreg->sdp_handle = gatt_add_sdp_record(p_uuid, p_sreg->s_hdl, p_sreg->e_hdl); + } + break; + default: + break; + } + + gatts_update_srv_list_elem(i_sreg, p_sreg->s_hdl, + p_list->asgn_range.is_primary); + + gatt_add_a_srv_to_list(&gatt_cb.srv_list_info, &gatt_cb.srv_list[i_sreg]); + + GATT_TRACE_DEBUG ("allocated i_sreg=%d ",i_sreg); + + GATT_TRACE_DEBUG ("s_hdl=%d e_hdl=%d type=0x%x svc_inst=%d sdp_hdl=0x%x", + p_sreg->s_hdl,p_sreg->e_hdl, + p_sreg->type, p_sreg->service_instance, + p_sreg->sdp_handle); + + + if ( (p_buf = gatt_sr_is_new_srv_chg(&p_list->asgn_range.app_uuid128, + &p_list->asgn_range.svc_uuid, + p_list->asgn_range.svc_inst)) != NULL) + { + gatt_proc_srv_chg(); + /* remove the new service element after the srv changed processing is completed*/ + + GKI_freebuf (GKI_remove_from_queue (&gatt_cb.pending_new_srv_start_q, p_buf)); + } + return GATT_SUCCESS; +} + +/******************************************************************************* +** +** Function GATTS_StopService +** +** Description This function is called to stop a service +** +** Parameter service_handle : this is the start handle of a service +** +** Returns None. +** +*******************************************************************************/ +void GATTS_StopService (UINT16 service_handle) +{ + UINT8 ii = gatt_sr_find_i_rcb_by_handle(service_handle); + + GATT_TRACE_API("GATTS_StopService %u", service_handle); + + /* Index 0 is reserved for GATT, and is never stopped */ + if ( (ii > 0) && (ii < GATT_MAX_SR_PROFILES) && (gatt_cb.sr_reg[ii].in_use) ) + { + if (gatt_cb.sr_reg[ii].sdp_handle) + { + SDP_DeleteRecord(gatt_cb.sr_reg[ii].sdp_handle); + } + gatt_remove_a_srv_from_list(&gatt_cb.srv_list_info, &gatt_cb.srv_list[ii]); + gatt_cb.srv_list[ii].in_use = FALSE; + memset (&gatt_cb.sr_reg[ii], 0, sizeof(tGATT_SR_REG)); + } + else + { + GATT_TRACE_ERROR("GATTS_StopService service_handle: %u is not in use", service_handle); + } +} +/******************************************************************************* +** +** Function GATTs_HandleValueIndication +** +** Description This function sends a handle value indication to a client. +** +** Parameter conn_id: connection identifier. +** attr_handle: Attribute handle of this handle value indication. +** val_len: Length of the indicated attribute value. +** p_val: Pointer to the indicated attribute value data. +** +** Returns GATT_SUCCESS if sucessfully sent or queued; otherwise error code. +** +*******************************************************************************/ +tGATT_STATUS GATTS_HandleValueIndication (UINT16 conn_id, UINT16 attr_handle, UINT16 val_len, UINT8 *p_val) +{ + tGATT_STATUS cmd_status = GATT_NO_RESOURCES; + + tGATT_VALUE indication; + BT_HDR *p_msg; + tGATT_VALUE *p_buf; + tGATT_IF gatt_if = GATT_GET_GATT_IF(conn_id); + UINT8 tcb_idx = GATT_GET_TCB_IDX(conn_id); + tGATT_REG *p_reg = gatt_get_regcb(gatt_if); + tGATT_TCB *p_tcb = gatt_get_tcb_by_idx(tcb_idx); + + + GATT_TRACE_API ("GATTS_HandleValueIndication"); + if ( (p_reg == NULL) || (p_tcb == NULL)) + { + GATT_TRACE_ERROR ("GATTS_HandleValueIndication Unknown conn_id: %u ", conn_id); + return(tGATT_STATUS) GATT_INVALID_CONN_ID; + } + + if (! GATT_HANDLE_IS_VALID (attr_handle)) + return GATT_ILLEGAL_PARAMETER; + + indication.conn_id = conn_id; + indication.handle = attr_handle; + indication.len = val_len; + memcpy (indication.value, p_val, val_len); + indication.auth_req = GATT_AUTH_REQ_NONE; + + if (GATT_HANDLE_IS_VALID(p_tcb->indicate_handle)) + { + GATT_TRACE_DEBUG ("Add a pending indication"); + if ((p_buf = gatt_add_pending_ind(p_tcb, &indication)) !=NULL) + { + cmd_status = GATT_SUCCESS; + } + else + { + cmd_status = GATT_NO_RESOURCES; + } + } + else + { + + if ( (p_msg = attp_build_sr_msg (p_tcb, GATT_HANDLE_VALUE_IND, (tGATT_SR_MSG *)&indication)) != NULL) + { + cmd_status = attp_send_sr_msg (p_tcb, p_msg); + + if (cmd_status == GATT_SUCCESS || cmd_status == GATT_CONGESTED) + { + p_tcb->indicate_handle = indication.handle; + gatt_start_conf_timer(p_tcb); + } + } + } + return cmd_status; +} + +/******************************************************************************* +** +** Function GATTS_HandleValueNotification +** +** Description This function sends a handle value notification to a client. +** +** Parameter conn_id: connection identifier. +** attr_handle: Attribute handle of this handle value indication. +** val_len: Length of the indicated attribute value. +** p_val: Pointer to the indicated attribute value data. +** +** Returns GATT_SUCCESS if sucessfully sent; otherwise error code. +** +*******************************************************************************/ +tGATT_STATUS GATTS_HandleValueNotification (UINT16 conn_id, UINT16 attr_handle, + UINT16 val_len, UINT8 *p_val) +{ + tGATT_STATUS cmd_sent = GATT_ILLEGAL_PARAMETER; + BT_HDR *p_buf; + tGATT_VALUE notif; + tGATT_IF gatt_if = GATT_GET_GATT_IF(conn_id); + UINT8 tcb_idx = GATT_GET_TCB_IDX(conn_id); + tGATT_REG *p_reg = gatt_get_regcb(gatt_if); + tGATT_TCB *p_tcb = gatt_get_tcb_by_idx(tcb_idx); + + GATT_TRACE_API ("GATTS_HandleValueNotification"); + + if ( (p_reg == NULL) || (p_tcb == NULL)) + { + GATT_TRACE_ERROR ("GATTS_HandleValueNotification Unknown conn_id: %u ", conn_id); + return(tGATT_STATUS) GATT_INVALID_CONN_ID; + } + + if (GATT_HANDLE_IS_VALID (attr_handle)) + { + notif.handle = attr_handle; + notif.len = val_len; + memcpy (notif.value, p_val, val_len); + notif.auth_req = GATT_AUTH_REQ_NONE;; + + if ((p_buf = attp_build_sr_msg (p_tcb, GATT_HANDLE_VALUE_NOTIF, (tGATT_SR_MSG *)¬if)) + != NULL) + { + cmd_sent = attp_send_sr_msg (p_tcb, p_buf); + } + else + cmd_sent = GATT_NO_RESOURCES; + } + return cmd_sent; +} + +/******************************************************************************* +** +** Function GATTS_SendRsp +** +** Description This function sends the server response to client. +** +** Parameter conn_id: connection identifier. +** trans_id: transaction id +** status: response status +** p_msg: pointer to message parameters structure. +** +** Returns GATT_SUCCESS if sucessfully sent; otherwise error code. +** +*******************************************************************************/ +tGATT_STATUS GATTS_SendRsp (UINT16 conn_id, UINT32 trans_id, + tGATT_STATUS status, tGATTS_RSP *p_msg) +{ + tGATT_STATUS cmd_sent = GATT_ILLEGAL_PARAMETER; + tGATT_IF gatt_if = GATT_GET_GATT_IF(conn_id); + UINT8 tcb_idx = GATT_GET_TCB_IDX(conn_id); + tGATT_REG *p_reg = gatt_get_regcb(gatt_if); + tGATT_TCB *p_tcb = gatt_get_tcb_by_idx(tcb_idx); + + GATT_TRACE_API ("GATTS_SendRsp: conn_id: %u trans_id: %u Status: 0x%04x", + conn_id, trans_id, status); + + if ( (p_reg == NULL) || (p_tcb == NULL)) + { + GATT_TRACE_ERROR ("GATTS_SendRsp Unknown conn_id: %u ", conn_id); + return(tGATT_STATUS) GATT_INVALID_CONN_ID; + } + + if (p_tcb->sr_cmd.trans_id != trans_id) + { + GATT_TRACE_ERROR ("GATTS_SendRsp conn_id: %u waiting for op_code = %02x", + conn_id, p_tcb->sr_cmd.op_code); + + return(GATT_WRONG_STATE); + } + /* Process App response */ + cmd_sent = gatt_sr_process_app_rsp (p_tcb, gatt_if, trans_id, p_tcb->sr_cmd.op_code, status, p_msg); + + return cmd_sent; +} + +/*******************************************************************************/ +/* GATT Profile Srvr Functions */ +/*******************************************************************************/ + +/*******************************************************************************/ +/* */ +/* GATT CLIENT APIs */ +/* */ +/*******************************************************************************/ + + +/******************************************************************************* +** +** Function GATTC_ConfigureMTU +** +** Description This function is called to configure the ATT MTU size. +** +** Parameters conn_id: connection identifier. +** mtu - attribute MTU size.. +** +** Returns GATT_SUCCESS if command started successfully. +** +*******************************************************************************/ +tGATT_STATUS GATTC_ConfigureMTU (UINT16 conn_id, UINT16 mtu) +{ + UINT8 ret = GATT_NO_RESOURCES; + tGATT_IF gatt_if=GATT_GET_GATT_IF(conn_id); + UINT8 tcb_idx = GATT_GET_TCB_IDX(conn_id); + tGATT_TCB *p_tcb = gatt_get_tcb_by_idx(tcb_idx); + tGATT_REG *p_reg = gatt_get_regcb(gatt_if); + + tGATT_CLCB *p_clcb; + + GATT_TRACE_API ("GATTC_ConfigureMTU conn_id=%d mtu=%d", conn_id, mtu ); + + /* Validate that the link is BLE, not BR/EDR */ + if (p_tcb->transport != BT_TRANSPORT_LE) + { + return GATT_ERROR; + } + + if ( (p_tcb == NULL) || (p_reg==NULL) || (mtu < GATT_DEF_BLE_MTU_SIZE) || (mtu > GATT_MAX_MTU_SIZE)) + { + return GATT_ILLEGAL_PARAMETER; + } + + if (gatt_is_clcb_allocated(conn_id)) + { + GATT_TRACE_ERROR("GATTC_ConfigureMTU GATT_BUSY conn_id = %d", conn_id); + return GATT_BUSY; + } + + if ((p_clcb = gatt_clcb_alloc(conn_id)) != NULL) + { + p_clcb->p_tcb->payload_size = mtu; + p_clcb->operation = GATTC_OPTYPE_CONFIG; + + ret = attp_send_cl_msg (p_clcb->p_tcb, p_clcb->clcb_idx, GATT_REQ_MTU, (tGATT_CL_MSG *)&mtu); + } + + return ret; +} + +/******************************************************************************* +** +** Function GATTC_Discover +** +** Description This function is called to do a discovery procedure on ATT server. +** +** Parameters conn_id: connection identifier. +** disc_type:discovery type. +** p_param: parameters of discovery requirement. +** +** Returns GATT_SUCCESS if command received/sent successfully. +** +*******************************************************************************/ +tGATT_STATUS GATTC_Discover (UINT16 conn_id, tGATT_DISC_TYPE disc_type, + tGATT_DISC_PARAM *p_param) +{ + tGATT_STATUS status = GATT_SUCCESS; + tGATT_CLCB *p_clcb; + tGATT_IF gatt_if=GATT_GET_GATT_IF(conn_id); + UINT8 tcb_idx = GATT_GET_TCB_IDX(conn_id); + tGATT_TCB *p_tcb = gatt_get_tcb_by_idx(tcb_idx); + tGATT_REG *p_reg = gatt_get_regcb(gatt_if); + + + GATT_TRACE_API ("GATTC_Discover conn_id=%d disc_type=%d",conn_id, disc_type); + + if ( (p_tcb == NULL) || (p_reg==NULL) ||(p_param == NULL) || + (disc_type >= GATT_DISC_MAX)) + { + GATT_TRACE_ERROR("GATTC_Discover Illegal param: disc_type %d conn_id = %d", disc_type, conn_id); + return GATT_ILLEGAL_PARAMETER; + } + + + if (gatt_is_clcb_allocated(conn_id)) + { + GATT_TRACE_ERROR("GATTC_Discover GATT_BUSY conn_id = %d", conn_id); + return GATT_BUSY; + } + + + if ((p_clcb = gatt_clcb_alloc(conn_id)) != NULL ) + { + if (!GATT_HANDLE_IS_VALID(p_param->s_handle) || + !GATT_HANDLE_IS_VALID(p_param->e_handle) || + /* search by type does not have a valid UUID param */ + (disc_type == GATT_DISC_SRVC_BY_UUID && + p_param->service.len == 0)) + { + gatt_clcb_dealloc(p_clcb); + return GATT_ILLEGAL_PARAMETER; + } + + p_clcb->operation = GATTC_OPTYPE_DISCOVERY; + p_clcb->op_subtype = disc_type; + p_clcb->s_handle = p_param->s_handle; + p_clcb->e_handle = p_param->e_handle; + p_clcb->uuid = p_param->service; + + gatt_act_discovery(p_clcb); + } + else + { + status = GATT_NO_RESOURCES; + } + return status; +} + +/******************************************************************************* +** +** Function GATTC_Read +** +** Description This function is called to read the value of an attribute from +** the server. +** +** Parameters conn_id: connection identifier. +** type - attribute read type. +** p_read - read operation parameters. +** +** Returns GATT_SUCCESS if command started successfully. +** +*******************************************************************************/ +tGATT_STATUS GATTC_Read (UINT16 conn_id, tGATT_READ_TYPE type, tGATT_READ_PARAM *p_read) +{ + tGATT_STATUS status = GATT_SUCCESS; + tGATT_CLCB *p_clcb; + tGATT_READ_MULTI *p_read_multi; + tGATT_IF gatt_if=GATT_GET_GATT_IF(conn_id); + UINT8 tcb_idx = GATT_GET_TCB_IDX(conn_id); + tGATT_TCB *p_tcb = gatt_get_tcb_by_idx(tcb_idx); + tGATT_REG *p_reg = gatt_get_regcb(gatt_if); + + + GATT_TRACE_API ("GATTC_Read conn_id=%d type=%d", conn_id, type); + + if ( (p_tcb == NULL) || (p_reg==NULL) || (p_read == NULL) || ((type >= GATT_READ_MAX) || (type == 0))) + { + GATT_TRACE_ERROR("GATT_Read Illegal param: conn_id %d, type 0%d,", conn_id, type); + return GATT_ILLEGAL_PARAMETER; + } + + if (gatt_is_clcb_allocated(conn_id)) + { + GATT_TRACE_ERROR("GATTC_Read GATT_BUSY conn_id = %d", conn_id); + return GATT_BUSY; + } + + if ( (p_clcb = gatt_clcb_alloc(conn_id)) != NULL ) + { + p_clcb->operation = GATTC_OPTYPE_READ; + p_clcb->op_subtype = type; + p_clcb->auth_req = p_read->by_handle.auth_req; + p_clcb->counter = 0; + + switch (type) + { + case GATT_READ_BY_TYPE: + case GATT_READ_CHAR_VALUE: + p_clcb->s_handle = p_read->service.s_handle; + p_clcb->e_handle = p_read->service.e_handle; + memcpy(&p_clcb->uuid, &p_read->service.uuid, sizeof(tBT_UUID)); + break; + case GATT_READ_MULTIPLE: + p_clcb->s_handle = 0; + /* copy multiple handles in CB */ + p_read_multi = (tGATT_READ_MULTI *)GKI_getbuf(sizeof(tGATT_READ_MULTI)); + p_clcb->p_attr_buf = (UINT8*)p_read_multi; + memcpy (p_read_multi, &p_read->read_multiple, sizeof(tGATT_READ_MULTI)); + case GATT_READ_BY_HANDLE: + case GATT_READ_PARTIAL: + memset(&p_clcb->uuid, 0, sizeof(tBT_UUID)); + p_clcb->s_handle = p_read->by_handle.handle; + + if (type == GATT_READ_PARTIAL) + { + p_clcb->counter = p_read->partial.offset; + } + + break; + default: + break; + } + /* start security check */ + if (gatt_security_check_start(p_clcb) == FALSE) + { + status = GATT_NO_RESOURCES; + gatt_clcb_dealloc(p_clcb); + } + } + else + { + status = GATT_NO_RESOURCES; + } + return status; +} + +/******************************************************************************* +** +** Function GATTC_Write +** +** Description This function is called to write the value of an attribute to +** the server. +** +** Parameters conn_id: connection identifier. +** type - attribute write type. +** p_write - write operation parameters. +** +** Returns GATT_SUCCESS if command started successfully. +** +*******************************************************************************/ +tGATT_STATUS GATTC_Write (UINT16 conn_id, tGATT_WRITE_TYPE type, tGATT_VALUE *p_write) +{ + tGATT_STATUS status = GATT_SUCCESS; + tGATT_CLCB *p_clcb; + tGATT_VALUE *p; + tGATT_IF gatt_if=GATT_GET_GATT_IF(conn_id); + UINT8 tcb_idx = GATT_GET_TCB_IDX(conn_id); + tGATT_TCB *p_tcb = gatt_get_tcb_by_idx(tcb_idx); + tGATT_REG *p_reg = gatt_get_regcb(gatt_if); + + if ( (p_tcb == NULL) || (p_reg==NULL) || (p_write == NULL) || + ((type != GATT_WRITE) && (type != GATT_WRITE_PREPARE) && (type != GATT_WRITE_NO_RSP)) ) + { + GATT_TRACE_ERROR("GATT_Write Illegal param: conn_id %d, type 0%d,", conn_id, type); + return GATT_ILLEGAL_PARAMETER; + } + + if (gatt_is_clcb_allocated(conn_id)) + { + GATT_TRACE_ERROR("GATTC_Write GATT_BUSY conn_id = %d", conn_id); + return GATT_BUSY; + } + + if ((p_clcb = gatt_clcb_alloc(conn_id)) != NULL ) + { + p_clcb->operation = GATTC_OPTYPE_WRITE; + p_clcb->op_subtype = type; + p_clcb->auth_req = p_write->auth_req; + + if (( p_clcb->p_attr_buf = (UINT8 *)GKI_getbuf((UINT16)sizeof(tGATT_VALUE))) != NULL) + { + memcpy(p_clcb->p_attr_buf, (void *)p_write, sizeof(tGATT_VALUE)); + + p = (tGATT_VALUE *)p_clcb->p_attr_buf; + if (type == GATT_WRITE_PREPARE) + { + p_clcb->start_offset = p_write->offset; + p->offset = 0; + } + + if (gatt_security_check_start(p_clcb) == FALSE) + { + status = GATT_NO_RESOURCES; + } + } + else + { + status = GATT_NO_RESOURCES; + } + + if (status == GATT_NO_RESOURCES) + gatt_clcb_dealloc(p_clcb); + } + else + { + status = GATT_NO_RESOURCES; + } + return status; +} + + +/******************************************************************************* +** +** Function GATTC_ExecuteWrite +** +** Description This function is called to send an Execute write request to +** the server. +** +** Parameters conn_id: connection identifier. +** is_execute - to execute or cancel the prepare write requet(s) +** +** Returns GATT_SUCCESS if command started successfully. +** +*******************************************************************************/ +tGATT_STATUS GATTC_ExecuteWrite (UINT16 conn_id, BOOLEAN is_execute) +{ + tGATT_STATUS status = GATT_SUCCESS; + tGATT_CLCB *p_clcb; + tGATT_EXEC_FLAG flag; + tGATT_IF gatt_if=GATT_GET_GATT_IF(conn_id); + UINT8 tcb_idx = GATT_GET_TCB_IDX(conn_id); + tGATT_TCB *p_tcb = gatt_get_tcb_by_idx(tcb_idx); + tGATT_REG *p_reg = gatt_get_regcb(gatt_if); + + GATT_TRACE_API ("GATTC_ExecuteWrite conn_id=%d is_execute=%d", conn_id, is_execute); + + if ( (p_tcb == NULL) || (p_reg==NULL) ) + { + GATT_TRACE_ERROR("GATTC_ExecuteWrite Illegal param: conn_id %d", conn_id); + return GATT_ILLEGAL_PARAMETER; + } + + if (gatt_is_clcb_allocated(conn_id)) + { + GATT_TRACE_ERROR("GATTC_Write GATT_BUSY conn_id = %d", conn_id); + return GATT_BUSY; + } + + if ((p_clcb = gatt_clcb_alloc(conn_id)) != NULL) + { + p_clcb->operation = GATTC_OPTYPE_EXE_WRITE; + flag = is_execute ? GATT_PREP_WRITE_EXEC : GATT_PREP_WRITE_CANCEL; + gatt_send_queue_write_cancel (p_clcb->p_tcb, p_clcb, flag); + } + else + { + GATT_TRACE_ERROR("Unable to allocate client CB for conn_id %d ", conn_id); + status = GATT_NO_RESOURCES; + } + return status; +} + +/******************************************************************************* +** +** Function GATTC_SendHandleValueConfirm +** +** Description This function is called to send a handle value confirmation +** as response to a handle value notification from server. +** +** Parameters conn_id: connection identifier. +** handle: the handle of the attribute confirmation. +** +** Returns GATT_SUCCESS if command started successfully. +** +*******************************************************************************/ +tGATT_STATUS GATTC_SendHandleValueConfirm (UINT16 conn_id, UINT16 handle) +{ + tGATT_STATUS ret = GATT_ILLEGAL_PARAMETER; + tGATT_TCB *p_tcb=gatt_get_tcb_by_idx(GATT_GET_TCB_IDX(conn_id)); + + GATT_TRACE_API ("GATTC_SendHandleValueConfirm conn_id=%d handle=0x%x", conn_id, handle); + + if (p_tcb) + { + if (p_tcb->ind_count > 0 ) + { + btu_stop_timer (&p_tcb->ind_ack_timer_ent); + + GATT_TRACE_DEBUG ("notif_count=%d ", p_tcb->ind_count); + /* send confirmation now */ + ret = attp_send_cl_msg(p_tcb, 0, GATT_HANDLE_VALUE_CONF, (tGATT_CL_MSG *)&handle); + + p_tcb->ind_count = 0; + + } + else + { + GATT_TRACE_DEBUG ("GATTC_SendHandleValueConfirm - conn_id: %u - ignored not waiting for indicaiton ack", conn_id); + ret = GATT_SUCCESS; + } + } + else + { + GATT_TRACE_ERROR ("GATTC_SendHandleValueConfirm - Unknown conn_id: %u", conn_id); + } + return ret; +} + + +/*******************************************************************************/ +/* */ +/* GATT APIs */ +/* */ +/*******************************************************************************/ +/******************************************************************************* +** +** Function GATT_SetIdleTimeout +** +** Description This function (common to both client and server) sets the idle +** timeout for a tansport connection +** +** Parameter bd_addr: target device bd address. +** idle_tout: timeout value in seconds. +** +** Returns void +** +*******************************************************************************/ +void GATT_SetIdleTimeout (BD_ADDR bd_addr, UINT16 idle_tout, tBT_TRANSPORT transport) +{ + tGATT_TCB *p_tcb; + BOOLEAN status = FALSE; + + if ((p_tcb = gatt_find_tcb_by_addr (bd_addr, transport)) != NULL) + { + if (p_tcb->att_lcid == L2CAP_ATT_CID) + { + status = L2CA_SetFixedChannelTout (bd_addr, L2CAP_ATT_CID, idle_tout); + + if (idle_tout == GATT_LINK_IDLE_TIMEOUT_WHEN_NO_APP) + L2CA_SetIdleTimeoutByBdAddr(p_tcb->peer_bda, + GATT_LINK_IDLE_TIMEOUT_WHEN_NO_APP, BT_TRANSPORT_LE); + } + else + { + status = L2CA_SetIdleTimeout (p_tcb->att_lcid, idle_tout, FALSE); + } + } + + GATT_TRACE_API ("GATT_SetIdleTimeout idle_tout=%d status=%d(1-OK 0-not performed)", + idle_tout, status); +} + + +/******************************************************************************* +** +** Function GATT_Register +** +** Description This function is called to register an application +** with GATT +** +** Parameter p_app_uuid128: Application UUID +** p_cb_info: callback functions. +** +** Returns 0 for error, otherwise the index of the client registered with GATT +** +*******************************************************************************/ +tGATT_IF GATT_Register (tBT_UUID *p_app_uuid128, tGATT_CBACK *p_cb_info) +{ + tGATT_REG *p_reg; + UINT8 i_gatt_if=0; + tGATT_IF gatt_if=0; + + GATT_TRACE_API ("GATT_Register"); + gatt_dbg_display_uuid(*p_app_uuid128); + + for (i_gatt_if = 0, p_reg = gatt_cb.cl_rcb; i_gatt_if < GATT_MAX_APPS; i_gatt_if++, p_reg++) + { + if (p_reg->in_use && !memcmp(p_app_uuid128->uu.uuid128, p_reg->app_uuid128.uu.uuid128, LEN_UUID_128)) + { + GATT_TRACE_ERROR("application already registered."); + return 0; + } + } + + for (i_gatt_if = 0, p_reg = gatt_cb.cl_rcb; i_gatt_if < GATT_MAX_APPS; i_gatt_if++, p_reg++) + { + if (!p_reg->in_use) + { + memset(p_reg, 0 , sizeof(tGATT_REG)); + i_gatt_if++; /* one based number */ + p_reg->app_uuid128 = *p_app_uuid128; + gatt_if = + p_reg->gatt_if = (tGATT_IF)i_gatt_if; + p_reg->app_cb = *p_cb_info; + p_reg->in_use = TRUE; + + break; + } + } + GATT_TRACE_API ("allocated gatt_if=%d", gatt_if); + return gatt_if; +} + + +/******************************************************************************* +** +** Function GATT_Deregister +** +** Description This function deregistered the application from GATT. +** +** Parameters gatt_if: applicaiton interface. +** +** Returns None. +** +*******************************************************************************/ +void GATT_Deregister (tGATT_IF gatt_if) +{ + tGATT_REG *p_reg = gatt_get_regcb(gatt_if); + tGATT_TCB *p_tcb; + tGATT_CLCB *p_clcb; + UINT8 i, ii, j; + tGATT_SR_REG *p_sreg; + + GATT_TRACE_API ("GATT_Deregister gatt_if=%d", gatt_if); + /* Index 0 is GAP and is never deregistered */ + if ( (gatt_if == 0) || (p_reg == NULL) ) + { + GATT_TRACE_ERROR ("GATT_Deregister with invalid gatt_if: %u", gatt_if); + return; + } + + /* stop all services */ + /* todo an applcaiton can not be deregistered if its services is also used by other application + deregisteration need to bed performed in an orderly fashion + no check for now */ + + for (ii = 0, p_sreg = gatt_cb.sr_reg; ii < GATT_MAX_SR_PROFILES; ii++, p_sreg++) + { + if (p_sreg->in_use && (p_sreg->gatt_if == gatt_if)) + { + GATTS_StopService(p_sreg->s_hdl); + } + } + + /* free all services db buffers if owned by this application */ + gatt_free_srvc_db_buffer_app_id(&p_reg->app_uuid128); + + /* When an application deregisters, check remove the link associated with the app */ + + for (i=0, p_tcb = gatt_cb.tcb; i < GATT_MAX_PHY_CHANNEL; i++, p_tcb++) + { + if (p_tcb->in_use) + { + if (gatt_get_ch_state(p_tcb) != GATT_CH_CLOSE) + { + gatt_update_app_use_link_flag(gatt_if, p_tcb, FALSE, FALSE); + if (!gatt_num_apps_hold_link(p_tcb)) + { + /* this will disconnect the link or cancel the pending connect request at lower layer*/ + gatt_disconnect(p_tcb); + } + } + + for (j = 0, p_clcb= &gatt_cb.clcb[j]; j < GATT_CL_MAX_LCB; j++, p_clcb++) + { + if (p_clcb->in_use && + (p_clcb->p_reg->gatt_if == gatt_if) && + (p_clcb->p_tcb->tcb_idx == p_tcb->tcb_idx)) + { + btu_stop_timer(&p_clcb->rsp_timer_ent); + gatt_clcb_dealloc (p_clcb); + break; + } + } + } + } + + gatt_deregister_bgdev_list(gatt_if); + /* update the listen mode */ +#if (defined(BLE_PERIPHERAL_MODE_SUPPORT) && (BLE_PERIPHERAL_MODE_SUPPORT == TRUE)) + GATT_Listen(gatt_if, FALSE, NULL); +#endif + + memset (p_reg, 0, sizeof(tGATT_REG)); +} + + +/******************************************************************************* +** +** Function GATT_StartIf +** +** Description This function is called after registration to start receiving +** callbacks for registered interface. Function may call back +** with connection status and queued notifications +** +** Parameter gatt_if: applicaiton interface. +** +** Returns None. +** +*******************************************************************************/ +void GATT_StartIf (tGATT_IF gatt_if) +{ + tGATT_REG *p_reg; + tGATT_TCB *p_tcb; + BD_ADDR bda; + UINT8 start_idx, found_idx; + UINT16 conn_id; + tGATT_TRANSPORT transport ; + + GATT_TRACE_API ("GATT_StartIf gatt_if=%d", gatt_if); + if ((p_reg = gatt_get_regcb(gatt_if)) != NULL) + { + start_idx = 0; + while (gatt_find_the_connected_bda(start_idx, bda, &found_idx, &transport)) + { + p_tcb = gatt_find_tcb_by_addr(bda, transport); + if (p_reg->app_cb.p_conn_cb && p_tcb) + { + conn_id = GATT_CREATE_CONN_ID(p_tcb->tcb_idx, gatt_if); + (*p_reg->app_cb.p_conn_cb)(gatt_if, bda, conn_id, TRUE, 0, transport); + } + start_idx = ++found_idx; + } + } +} + + +/******************************************************************************* +** +** Function GATT_Connect +** +** Description This function initiate a connecttion to a remote device on GATT +** channel. +** +** Parameters gatt_if: applicaiton interface +** bd_addr: peer device address. +** is_direct: is a direct conenection or a background auto connection +** +** Returns TRUE if connection started; FALSE if connection start failure. +** +*******************************************************************************/ +BOOLEAN GATT_Connect (tGATT_IF gatt_if, BD_ADDR bd_addr, BOOLEAN is_direct, tBT_TRANSPORT transport) +{ + tGATT_REG *p_reg; + BOOLEAN status = FALSE; + + GATT_TRACE_API ("GATT_Connect gatt_if=%d", gatt_if); + + /* Make sure app is registered */ + if ((p_reg = gatt_get_regcb(gatt_if)) == NULL) + { + GATT_TRACE_ERROR("GATT_Connect - gatt_if =%d is not registered", gatt_if); + return(FALSE); + } + + if (is_direct) + status = gatt_act_connect (p_reg, bd_addr, transport); + else + { + if (transport == BT_TRANSPORT_LE) + status = gatt_update_auto_connect_dev(gatt_if,TRUE, bd_addr, TRUE); + else + { + GATT_TRACE_ERROR("Unsupported transport for background connection"); + } + } + + return status; + +} + +/******************************************************************************* +** +** Function GATT_CancelConnect +** +** Description This function terminate the connection initaition to a remote +** device on GATT channel. +** +** Parameters gatt_if: client interface. If 0 used as unconditionally disconnect, +** typically used for direct connection cancellation. +** bd_addr: peer device address. +** +** Returns TRUE if connection started; FALSE if connection start failure. +** +*******************************************************************************/ +BOOLEAN GATT_CancelConnect (tGATT_IF gatt_if, BD_ADDR bd_addr, BOOLEAN is_direct){ + tGATT_REG *p_reg; + tGATT_TCB *p_tcb; + BOOLEAN status = TRUE; + tGATT_IF temp_gatt_if; + UINT8 start_idx, found_idx; + + GATT_TRACE_API ("GATT_CancelConnect gatt_if=%d", gatt_if); + + if ((gatt_if != 0) && ((p_reg = gatt_get_regcb(gatt_if)) == NULL)) + { + GATT_TRACE_ERROR("GATT_CancelConnect - gatt_if =%d is not registered", gatt_if); + return(FALSE); + } + + if (is_direct) + { + if (!gatt_if) + { + GATT_TRACE_DEBUG("GATT_CancelConnect - unconditional"); + start_idx = 0; + /* only LE connection can be cancelled */ + p_tcb = gatt_find_tcb_by_addr(bd_addr, BT_TRANSPORT_LE); + if (p_tcb && gatt_num_apps_hold_link(p_tcb)) + { + while (status && gatt_find_app_hold_link(p_tcb, start_idx, &found_idx, &temp_gatt_if)) + { + status = gatt_cancel_open(temp_gatt_if, bd_addr); + start_idx = ++found_idx; + } + } + else + { + GATT_TRACE_ERROR("GATT_CancelConnect - no app found"); + status = FALSE; + } + } + else + { + status = gatt_cancel_open(gatt_if, bd_addr); + } + } + else + { + if (!gatt_if) + { + if (gatt_get_num_apps_for_bg_dev(bd_addr)) + { + while (gatt_find_app_for_bg_dev(bd_addr, &temp_gatt_if)) + gatt_remove_bg_dev_for_app(temp_gatt_if, bd_addr); + } + else + { + GATT_TRACE_ERROR("GATT_CancelConnect -no app associated with the bg device for unconditional removal"); + status = FALSE; + } + } + else + { + status = gatt_remove_bg_dev_for_app(gatt_if, bd_addr); + } + } + + return status; +} + +/******************************************************************************* +** +** Function GATT_Disconnect +** +** Description This function disconnect the GATT channel for this registered +** application. +** +** Parameters conn_id: connection identifier. +** +** Returns GATT_SUCCESS if disconnected. +** +*******************************************************************************/ +tGATT_STATUS GATT_Disconnect (UINT16 conn_id) +{ + tGATT_STATUS ret = GATT_ILLEGAL_PARAMETER; + tGATT_TCB *p_tcb=NULL; + tGATT_IF gatt_if=GATT_GET_GATT_IF(conn_id); + UINT8 tcb_idx = GATT_GET_TCB_IDX(conn_id); + + GATT_TRACE_API ("GATT_Disconnect conn_id=%d ", conn_id); + + p_tcb = gatt_get_tcb_by_idx(tcb_idx); + + if (p_tcb) + { + gatt_update_app_use_link_flag(gatt_if, p_tcb, FALSE, FALSE); + if (!gatt_num_apps_hold_link(p_tcb)) + { + gatt_disconnect(p_tcb); + } + ret = GATT_SUCCESS; + } + return ret; +} + + +/******************************************************************************* +** +** Function GATT_GetConnectionInfor +** +** Description This function use conn_id to find its associated BD address and applciation +** interface +** +** Parameters conn_id: connection id (input) +** p_gatt_if: applicaiton interface (output) +** bd_addr: peer device address. (output) +** +** Returns TRUE the ligical link information is found for conn_id +** +*******************************************************************************/ +BOOLEAN GATT_GetConnectionInfor(UINT16 conn_id, tGATT_IF *p_gatt_if, BD_ADDR bd_addr, + tBT_TRANSPORT *p_transport) +{ + + tGATT_IF gatt_if = GATT_GET_GATT_IF(conn_id); + tGATT_REG *p_reg = gatt_get_regcb(gatt_if); + UINT8 tcb_idx = GATT_GET_TCB_IDX(conn_id); + tGATT_TCB *p_tcb= gatt_get_tcb_by_idx(tcb_idx); + BOOLEAN status=FALSE; + + GATT_TRACE_API ("GATT_GetConnectionInfor conn_id=%d", conn_id); + + if (p_tcb && p_reg ) + { + memcpy(bd_addr, p_tcb->peer_bda, BD_ADDR_LEN); + *p_gatt_if = gatt_if; + *p_transport = p_tcb->transport; + status = TRUE; + } + return status; +} + + +/******************************************************************************* +** +** Function GATT_GetConnIdIfConnected +** +** Description This function find the conn_id if the logical link for BD address +** and applciation interface is connected +** +** Parameters gatt_if: applicaiton interface (input) +** bd_addr: peer device address. (input) +** p_conn_id: connection id (output) +** transport: transport option +** +** Returns TRUE the logical link is connected +** +*******************************************************************************/ +BOOLEAN GATT_GetConnIdIfConnected(tGATT_IF gatt_if, BD_ADDR bd_addr, UINT16 *p_conn_id, + tBT_TRANSPORT transport) +{ + tGATT_REG *p_reg = gatt_get_regcb(gatt_if); + tGATT_TCB *p_tcb= gatt_find_tcb_by_addr(bd_addr, transport); + BOOLEAN status=FALSE; + + if (p_reg && p_tcb && (gatt_get_ch_state(p_tcb) == GATT_CH_OPEN) ) + { + *p_conn_id = GATT_CREATE_CONN_ID(p_tcb->tcb_idx, gatt_if); + status = TRUE; + } + + GATT_TRACE_API ("GATT_GetConnIdIfConnected status=%d", status); + return status; +} + + +/******************************************************************************* +** +** Function GATT_Listen +** +** Description This function start or stop LE advertisement and listen for +** connection. +** +** Parameters gatt_if: applicaiton interface +** p_bd_addr: listen for specific address connection, or NULL for +** listen to all device connection. +** start: start or stop listening. +** +** Returns TRUE if advertisement is started; FALSE if adv start failure. +** +*******************************************************************************/ +BOOLEAN GATT_Listen (tGATT_IF gatt_if, BOOLEAN start, BD_ADDR_PTR bd_addr) +{ + tGATT_REG *p_reg; + + GATT_TRACE_API ("GATT_Listen gatt_if=%d", gatt_if); + + /* Make sure app is registered */ + if ((p_reg = gatt_get_regcb(gatt_if)) == NULL) + { + GATT_TRACE_ERROR("GATT_Listen - gatt_if =%d is not registered", gatt_if); + return(FALSE); + } + + if (bd_addr != NULL) + { + gatt_update_auto_connect_dev(gatt_if,start, bd_addr, FALSE); + } + else + { + p_reg->listening = start ? GATT_LISTEN_TO_ALL : GATT_LISTEN_TO_NONE; + } + + return gatt_update_listen_mode(); +} + +#endif + diff --git a/components/bt/bluedroid/stack/gatt/gatt_attr.c b/components/bt/bluedroid/stack/gatt/gatt_attr.c new file mode 100755 index 0000000000..a6cc271aed --- /dev/null +++ b/components/bt/bluedroid/stack/gatt/gatt_attr.c @@ -0,0 +1,515 @@ +/****************************************************************************** + * + * Copyright (C) 2008-2012 Broadcom Corporation + * + * 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 main GATT server attributes access request + * handling functions. + * + ******************************************************************************/ + +#include "bt_target.h" +//#include "bt_utils.h" + +#include "gatt_api.h" +#include "gatt_int.h" + +#if BLE_INCLUDED == TRUE + +#define GATTP_MAX_NUM_INC_SVR 0 +#define GATTP_MAX_CHAR_NUM 2 +#define GATTP_MAX_ATTR_NUM (GATTP_MAX_CHAR_NUM * 2 + GATTP_MAX_NUM_INC_SVR + 1) +#define GATTP_MAX_CHAR_VALUE_SIZE 50 + +#ifndef GATTP_ATTR_DB_SIZE +#define GATTP_ATTR_DB_SIZE GATT_DB_MEM_SIZE(GATTP_MAX_NUM_INC_SVR, GATTP_MAX_CHAR_NUM, GATTP_MAX_CHAR_VALUE_SIZE) +#endif + +static void gatt_request_cback(UINT16 conn_id, UINT32 trans_id, UINT8 op_code, tGATTS_DATA *p_data); +static void gatt_connect_cback(tGATT_IF gatt_if, BD_ADDR bda, UINT16 conn_id, BOOLEAN connected, + tGATT_DISCONN_REASON reason, tBT_TRANSPORT transport); +static void gatt_disc_res_cback(UINT16 conn_id, tGATT_DISC_TYPE disc_type, tGATT_DISC_RES *p_data); +static void gatt_disc_cmpl_cback(UINT16 conn_id, tGATT_DISC_TYPE disc_type, tGATT_STATUS status); +static void gatt_cl_op_cmpl_cback(UINT16 conn_id, tGATTC_OPTYPE op, tGATT_STATUS status, + tGATT_CL_COMPLETE *p_data); + +static void gatt_cl_start_config_ccc(tGATT_PROFILE_CLCB *p_clcb); + + +static tGATT_CBACK gatt_profile_cback = +{ + gatt_connect_cback, + gatt_cl_op_cmpl_cback, + gatt_disc_res_cback, + gatt_disc_cmpl_cback, + gatt_request_cback, + NULL, + NULL +} ; + +/******************************************************************************* +** +** Function gatt_profile_find_conn_id_by_bd_addr +** +** Description Find the connection ID by remote address +** +** Returns Connection ID +** +*******************************************************************************/ +UINT16 gatt_profile_find_conn_id_by_bd_addr(BD_ADDR remote_bda) +{ + UINT16 conn_id = GATT_INVALID_CONN_ID; + GATT_GetConnIdIfConnected (gatt_cb.gatt_if, remote_bda, &conn_id, BT_TRANSPORT_LE); + return conn_id; +} + +/******************************************************************************* +** +** Function gatt_profile_find_clcb_by_conn_id +** +** Description find clcb by Connection ID +** +** Returns Pointer to the found link conenction control block. +** +*******************************************************************************/ +static tGATT_PROFILE_CLCB *gatt_profile_find_clcb_by_conn_id(UINT16 conn_id) +{ + UINT8 i_clcb; + tGATT_PROFILE_CLCB *p_clcb = NULL; + + for (i_clcb = 0, p_clcb= gatt_cb.profile_clcb; i_clcb < GATT_MAX_APPS; i_clcb++, p_clcb++) + { + if (p_clcb->in_use && p_clcb->conn_id == conn_id) + return p_clcb; + } + + return NULL; +} + +/******************************************************************************* +** +** Function gatt_profile_find_clcb_by_bd_addr +** +** Description The function searches all LCBs with macthing bd address. +** +** Returns Pointer to the found link conenction control block. +** +*******************************************************************************/ +static tGATT_PROFILE_CLCB *gatt_profile_find_clcb_by_bd_addr(BD_ADDR bda, tBT_TRANSPORT transport) +{ + UINT8 i_clcb; + tGATT_PROFILE_CLCB *p_clcb = NULL; + + for (i_clcb = 0, p_clcb= gatt_cb.profile_clcb; i_clcb < GATT_MAX_APPS; i_clcb++, p_clcb++) + { + if (p_clcb->in_use && p_clcb->transport == transport && + p_clcb->connected && !memcmp(p_clcb->bda, bda, BD_ADDR_LEN)) + return p_clcb; + } + + return NULL; +} + +/******************************************************************************* +** +** Function gatt_profile_clcb_alloc +** +** Description The function allocates a GATT profile connection link control block +** +** Returns NULL if not found. Otherwise pointer to the connection link block. +** +*******************************************************************************/ +tGATT_PROFILE_CLCB *gatt_profile_clcb_alloc (UINT16 conn_id, BD_ADDR bda, tBT_TRANSPORT tranport) +{ + UINT8 i_clcb = 0; + tGATT_PROFILE_CLCB *p_clcb = NULL; + + for (i_clcb = 0, p_clcb= gatt_cb.profile_clcb; i_clcb < GATT_MAX_APPS; i_clcb++, p_clcb++) + { + if (!p_clcb->in_use) + { + p_clcb->in_use = TRUE; + p_clcb->conn_id = conn_id; + p_clcb->connected = TRUE; + p_clcb->transport = tranport; + memcpy (p_clcb->bda, bda, BD_ADDR_LEN); + break; + } + } + if(i_clcb < GATT_MAX_APPS) + return p_clcb; + + return NULL; +} + +/******************************************************************************* +** +** Function gatt_profile_clcb_dealloc +** +** Description The function deallocates a GATT profile connection link control block +** +** Returns void +** +*******************************************************************************/ +void gatt_profile_clcb_dealloc (tGATT_PROFILE_CLCB *p_clcb) +{ + memset(p_clcb, 0, sizeof(tGATT_PROFILE_CLCB)); +} + +/******************************************************************************* +** +** Function gatt_request_cback +** +** Description GATT profile attribute access request callback. +** +** Returns void. +** +*******************************************************************************/ +static void gatt_request_cback (UINT16 conn_id, UINT32 trans_id, tGATTS_REQ_TYPE type, + tGATTS_DATA *p_data) +{ + UINT8 status = GATT_INVALID_PDU; + tGATTS_RSP rsp_msg ; + BOOLEAN ignore = FALSE; + + memset(&rsp_msg, 0, sizeof(tGATTS_RSP)); + + switch (type) + { + case GATTS_REQ_TYPE_READ: + status = GATT_READ_NOT_PERMIT; + break; + + case GATTS_REQ_TYPE_WRITE: + status = GATT_WRITE_NOT_PERMIT; + break; + + case GATTS_REQ_TYPE_WRITE_EXEC: + case GATT_CMD_WRITE: + ignore = TRUE; + GATT_TRACE_EVENT("Ignore GATT_REQ_EXEC_WRITE/WRITE_CMD" ); + break; + + case GATTS_REQ_TYPE_MTU: + GATT_TRACE_EVENT("Get MTU exchange new mtu size: %d", p_data->mtu); + ignore = TRUE; + break; + + default: + GATT_TRACE_EVENT("Unknown/unexpected LE GAP ATT request: 0x%02x", type); + break; + } + + if (!ignore) + GATTS_SendRsp (conn_id, trans_id, status, &rsp_msg); + +} + +/******************************************************************************* +** +** Function gatt_connect_cback +** +** Description Gatt profile connection callback. +** +** Returns void +** +*******************************************************************************/ +static void gatt_connect_cback (tGATT_IF gatt_if, BD_ADDR bda, UINT16 conn_id, + BOOLEAN connected, tGATT_DISCONN_REASON reason, + tBT_TRANSPORT transport) +{ + UNUSED(gatt_if); + + GATT_TRACE_EVENT ("%s: from %08x%04x connected:%d conn_id=%d reason = 0x%04x", __FUNCTION__, + (bda[0]<<24)+(bda[1]<<16)+(bda[2]<<8)+bda[3], + (bda[4]<<8)+bda[5], connected, conn_id, reason); + + tGATT_PROFILE_CLCB *p_clcb = gatt_profile_find_clcb_by_bd_addr(bda, transport); + if (p_clcb == NULL) + return; + + if (connected) + { + p_clcb->conn_id = conn_id; + p_clcb->connected = TRUE; + + if (p_clcb->ccc_stage == GATT_SVC_CHANGED_CONNECTING) + { + p_clcb->ccc_stage ++; + gatt_cl_start_config_ccc(p_clcb); + } + } else { + gatt_profile_clcb_dealloc(p_clcb); + } +} + +/******************************************************************************* +** +** Function gatt_profile_db_init +** +** Description Initializa the GATT profile attribute database. +** +*******************************************************************************/ +void gatt_profile_db_init (void) +{ + tBT_UUID app_uuid = {LEN_UUID_128, {0}}; + tBT_UUID uuid = {LEN_UUID_16, {UUID_SERVCLASS_GATT_SERVER}}; + UINT16 service_handle = 0; + tGATT_STATUS status; + + /* Fill our internal UUID with a fixed pattern 0x81 */ + memset (&app_uuid.uu.uuid128, 0x81, LEN_UUID_128); + + + /* Create a GATT profile service */ + gatt_cb.gatt_if = GATT_Register(&app_uuid, &gatt_profile_cback); + GATT_StartIf(gatt_cb.gatt_if); + + service_handle = GATTS_CreateService (gatt_cb.gatt_if , &uuid, 0, GATTP_MAX_ATTR_NUM, TRUE); + /* add Service Changed characteristic + */ + uuid.uu.uuid16 = gatt_cb.gattp_attr.uuid = GATT_UUID_GATT_SRV_CHGD; + gatt_cb.gattp_attr.service_change = 0; + gatt_cb.gattp_attr.handle = + gatt_cb.handle_of_h_r = GATTS_AddCharacteristic(service_handle, &uuid, 0, GATT_CHAR_PROP_BIT_INDICATE); + + GATT_TRACE_DEBUG ("gatt_profile_db_init: handle of service changed%d", + gatt_cb.handle_of_h_r ); + + /* start service + */ + status = GATTS_StartService (gatt_cb.gatt_if, service_handle, GATTP_TRANSPORT_SUPPORTED ); + + GATT_TRACE_DEBUG ("gatt_profile_db_init: gatt_if=%d start status%d", + gatt_cb.gatt_if, status); +} + +/******************************************************************************* +** +** Function gatt_config_ccc_complete +** +** Description The function finish the service change ccc configuration +** +** Returns void +** +*******************************************************************************/ +static void gatt_config_ccc_complete(tGATT_PROFILE_CLCB *p_clcb) +{ + GATT_Disconnect(p_clcb->conn_id); + gatt_profile_clcb_dealloc(p_clcb); +} + +/******************************************************************************* +** +** Function gatt_disc_res_cback +** +** Description Gatt profile discovery result callback +** +** Returns void +** +*******************************************************************************/ +static void gatt_disc_res_cback (UINT16 conn_id, tGATT_DISC_TYPE disc_type, tGATT_DISC_RES *p_data) +{ + tGATT_PROFILE_CLCB *p_clcb = gatt_profile_find_clcb_by_conn_id(conn_id); + + if (p_clcb == NULL) + return; + + switch (disc_type) + { + case GATT_DISC_SRVC_BY_UUID:/* stage 1 */ + p_clcb->e_handle = p_data->value.group_value.e_handle; + p_clcb->ccc_result ++; + break; + + case GATT_DISC_CHAR:/* stage 2 */ + p_clcb->s_handle = p_data->value.dclr_value.val_handle; + p_clcb->ccc_result ++; + break; + + case GATT_DISC_CHAR_DSCPT: /* stage 3 */ + if (p_data->type.uu.uuid16 == GATT_UUID_CHAR_CLIENT_CONFIG) + { + p_clcb->s_handle = p_data->handle; + p_clcb->ccc_result ++; + } + break; + } +} + +/******************************************************************************* +** +** Function gatt_disc_cmpl_cback +** +** Description Gatt profile discovery complete callback +** +** Returns void +** +*******************************************************************************/ +static void gatt_disc_cmpl_cback (UINT16 conn_id, tGATT_DISC_TYPE disc_type, tGATT_STATUS status) +{ + tGATT_PROFILE_CLCB *p_clcb = gatt_profile_find_clcb_by_conn_id(conn_id); + + if (p_clcb == NULL) + return; + + if (status == GATT_SUCCESS && p_clcb->ccc_result > 0) + { + p_clcb->ccc_result = 0; + p_clcb->ccc_stage ++; + gatt_cl_start_config_ccc(p_clcb); + } else { + GATT_TRACE_ERROR("%s() - Register for service changed indication failure", __FUNCTION__); + /* free the connection */ + gatt_config_ccc_complete (p_clcb); + } +} + +/******************************************************************************* +** +** Function gatt_cl_op_cmpl_cback +** +** Description Gatt profile client operation complete callback +** +** Returns void +** +*******************************************************************************/ +static void gatt_cl_op_cmpl_cback (UINT16 conn_id, tGATTC_OPTYPE op, + tGATT_STATUS status, tGATT_CL_COMPLETE *p_data) +{ + tGATT_PROFILE_CLCB *p_clcb = gatt_profile_find_clcb_by_conn_id(conn_id); + + if (p_clcb == NULL) + return; + + if (op == GATTC_OPTYPE_WRITE) + { + GATT_TRACE_DEBUG("%s() - ccc write status : %d", __FUNCTION__, status); + } + + /* free the connection */ + gatt_config_ccc_complete (p_clcb); +} + +/******************************************************************************* +** +** Function gatt_cl_start_config_ccc +** +** Description Gatt profile start configure service change CCC +** +** Returns void +** +*******************************************************************************/ +static void gatt_cl_start_config_ccc(tGATT_PROFILE_CLCB *p_clcb) +{ + tGATT_DISC_PARAM srvc_disc_param; + tGATT_VALUE ccc_value; + + GATT_TRACE_DEBUG("%s() - stage: %d", __FUNCTION__, p_clcb->ccc_stage); + + memset (&srvc_disc_param, 0 , sizeof(tGATT_DISC_PARAM)); + memset (&ccc_value, 0 , sizeof(tGATT_VALUE)); + + switch(p_clcb->ccc_stage) + { + case GATT_SVC_CHANGED_SERVICE: /* discover GATT service */ + srvc_disc_param.s_handle = 1; + srvc_disc_param.e_handle = 0xffff; + srvc_disc_param.service.len = 2; + srvc_disc_param.service.uu.uuid16 = UUID_SERVCLASS_GATT_SERVER; + if (GATTC_Discover (p_clcb->conn_id, GATT_DISC_SRVC_BY_UUID, &srvc_disc_param) != GATT_SUCCESS) + { + GATT_TRACE_ERROR("%s() - ccc service error", __FUNCTION__); + gatt_config_ccc_complete(p_clcb); + } + break; + + case GATT_SVC_CHANGED_CHARACTERISTIC: /* discover service change char */ + srvc_disc_param.s_handle = 1; + srvc_disc_param.e_handle = p_clcb->e_handle; + srvc_disc_param.service.len = 2; + srvc_disc_param.service.uu.uuid16 = GATT_UUID_GATT_SRV_CHGD; + if (GATTC_Discover (p_clcb->conn_id, GATT_DISC_CHAR, &srvc_disc_param) != GATT_SUCCESS) + { + GATT_TRACE_ERROR("%s() - ccc char error", __FUNCTION__); + gatt_config_ccc_complete(p_clcb); + } + break; + + case GATT_SVC_CHANGED_DESCRIPTOR: /* discover service change ccc */ + srvc_disc_param.s_handle = p_clcb->s_handle; + srvc_disc_param.e_handle = p_clcb->e_handle; + if (GATTC_Discover (p_clcb->conn_id, GATT_DISC_CHAR_DSCPT, &srvc_disc_param) != GATT_SUCCESS) + { + GATT_TRACE_ERROR("%s() - ccc char descriptor error", __FUNCTION__); + gatt_config_ccc_complete(p_clcb); + } + break; + + case GATT_SVC_CHANGED_CONFIGURE_CCCD: /* write ccc */ + ccc_value.handle = p_clcb->s_handle; + ccc_value.len = 2; + ccc_value.value[0] = GATT_CLT_CONFIG_INDICATION; + if (GATTC_Write (p_clcb->conn_id, GATT_WRITE, &ccc_value) != GATT_SUCCESS) + { + GATT_TRACE_ERROR("%s() - write ccc error", __FUNCTION__); + gatt_config_ccc_complete(p_clcb); + } + break; + } +} + +/******************************************************************************* +** +** Function GATT_ConfigServiceChangeCCC +** +** Description Configure service change indication on remote device +** +** Returns none +** +*******************************************************************************/ +void GATT_ConfigServiceChangeCCC (BD_ADDR remote_bda, BOOLEAN enable, tBT_TRANSPORT transport) +{ + UINT16 conn_id = GATT_INVALID_CONN_ID; + tGATT_PROFILE_CLCB *p_clcb = gatt_profile_find_clcb_by_bd_addr (remote_bda, transport); + + if (p_clcb == NULL) + p_clcb = gatt_profile_clcb_alloc (0, remote_bda, transport); + + if (p_clcb == NULL) + return; + + if (GATT_GetConnIdIfConnected (gatt_cb.gatt_if, remote_bda, &p_clcb->conn_id, transport)) + { + p_clcb->connected = TRUE; + } + /* hold the link here */ + GATT_Connect(gatt_cb.gatt_if, remote_bda, TRUE, transport); + p_clcb->ccc_stage = GATT_SVC_CHANGED_CONNECTING; + + if (!p_clcb->connected) + { + /* wait for connection */ + return; + } + + p_clcb->ccc_stage ++; + gatt_cl_start_config_ccc(p_clcb); +} + +#endif /* BLE_INCLUDED */ diff --git a/components/bt/bluedroid/stack/gatt/gatt_auth.c b/components/bt/bluedroid/stack/gatt/gatt_auth.c new file mode 100755 index 0000000000..42a19939db --- /dev/null +++ b/components/bt/bluedroid/stack/gatt/gatt_auth.c @@ -0,0 +1,536 @@ +/****************************************************************************** + * + * Copyright (C) 1999-2012 Broadcom Corporation + * + * 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 GATT authentication handling functions + * + ******************************************************************************/ +#include "bt_target.h" +//#include "bt_utils.h" + +#if BLE_INCLUDED == TRUE +#include +#include "gki.h" + +#include "gatt_int.h" +#include "gatt_api.h" +#include "btm_int.h" + +/******************************************************************************* +** +** Function gatt_sign_data +** +** Description This function sign the data for write command. +** +** Returns TRUE if encrypted, otherwise FALSE. +** +*******************************************************************************/ +static BOOLEAN gatt_sign_data (tGATT_CLCB *p_clcb) +{ + tGATT_VALUE *p_attr = (tGATT_VALUE *)p_clcb->p_attr_buf; + UINT8 *p_data = NULL, *p; + UINT16 payload_size = p_clcb->p_tcb->payload_size; + BOOLEAN status = FALSE; + UINT8 *p_signature; + + /* do not need to mark channel securoty activity for data signing */ + gatt_set_sec_act(p_clcb->p_tcb, GATT_SEC_OK); + + p_data = (UINT8 *)GKI_getbuf((UINT16)(p_attr->len + 3)); /* 3 = 2 byte handle + opcode */ + + if (p_data != NULL) + { + p = p_data; + UINT8_TO_STREAM(p, GATT_SIGN_CMD_WRITE); + UINT16_TO_STREAM(p, p_attr->handle); + ARRAY_TO_STREAM(p, p_attr->value, p_attr->len); + + /* sign data length should be attribulte value length plus 2B handle + 1B op code */ + if ((payload_size - GATT_AUTH_SIGN_LEN - 3) < p_attr->len) + p_attr->len = payload_size - GATT_AUTH_SIGN_LEN - 3; + + p_signature = p_attr->value + p_attr->len; + if (BTM_BleDataSignature(p_clcb->p_tcb->peer_bda, + p_data, + (UINT16)(p_attr->len + 3), /* 3 = 2 byte handle + opcode */ + p_signature)) + { + p_attr->len += BTM_BLE_AUTH_SIGN_LEN; + gatt_set_ch_state(p_clcb->p_tcb, GATT_CH_OPEN); + gatt_act_write(p_clcb, GATT_SEC_SIGN_DATA); + } + else + { + gatt_end_operation(p_clcb, GATT_INTERNAL_ERROR, NULL); + } + + GKI_freebuf(p_data); + } + + return status; +} + +/******************************************************************************* +** +** Function gatt_verify_signature +** +** Description This function start to verify the sign data when receiving +** the data from peer device. +** +** Returns +** +*******************************************************************************/ +void gatt_verify_signature(tGATT_TCB *p_tcb, BT_HDR *p_buf) +{ + UINT16 cmd_len; + UINT8 op_code; + UINT8 *p, *p_orig = (UINT8 *)(p_buf + 1) + p_buf->offset; + UINT32 counter; + + if (p_buf->len < GATT_AUTH_SIGN_LEN + 4) { + GATT_TRACE_ERROR("%s: Data length %u less than expected %u", + __func__, p_buf->len, GATT_AUTH_SIGN_LEN + 4); + return; + } + cmd_len = p_buf->len - GATT_AUTH_SIGN_LEN + 4; + p = p_orig + cmd_len - 4; + STREAM_TO_UINT32(counter, p); + + if (BTM_BleVerifySignature(p_tcb->peer_bda, p_orig, cmd_len, counter, p)) + { + STREAM_TO_UINT8(op_code, p_orig); + gatt_server_handle_client_req (p_tcb, op_code, (UINT16)(p_buf->len - 1), p_orig); + } + else + { + /* if this is a bad signature, assume from attacker, ignore it */ + GATT_TRACE_ERROR("Signature Verification Failed, data ignored"); + } + + return; +} +/******************************************************************************* +** +** Function gatt_sec_check_complete +** +** Description security check complete and proceed to data sending action. +** +** Returns void. +** +*******************************************************************************/ +void gatt_sec_check_complete(BOOLEAN sec_check_ok, tGATT_CLCB *p_clcb, UINT8 sec_act) +{ + if (p_clcb && p_clcb->p_tcb && GKI_queue_is_empty(&p_clcb->p_tcb->pending_enc_clcb)) + gatt_set_sec_act(p_clcb->p_tcb, GATT_SEC_NONE); + + if (!sec_check_ok) + { + gatt_end_operation(p_clcb, GATT_AUTH_FAIL, NULL); + } + else if (p_clcb->operation == GATTC_OPTYPE_WRITE) + { + gatt_act_write(p_clcb, sec_act); + } + else if (p_clcb->operation == GATTC_OPTYPE_READ) + { + gatt_act_read(p_clcb, p_clcb->counter); + } +} +/******************************************************************************* +** +** Function gatt_enc_cmpl_cback +** +** Description link encryption complete callback. +** +** Returns +** +*******************************************************************************/ +void gatt_enc_cmpl_cback(BD_ADDR bd_addr, tBT_TRANSPORT transport, void *p_ref_data, tBTM_STATUS result) +{ + tGATT_TCB *p_tcb; + UINT8 sec_flag; + BOOLEAN status = FALSE; + tGATT_PENDING_ENC_CLCB *p_buf; + UINT16 count; + UNUSED(p_ref_data); + + GATT_TRACE_DEBUG("gatt_enc_cmpl_cback"); + if ((p_tcb = gatt_find_tcb_by_addr(bd_addr, transport)) != NULL) + { + if (gatt_get_sec_act(p_tcb) == GATT_SEC_ENC_PENDING) + return; + + if ((p_buf = (tGATT_PENDING_ENC_CLCB *)GKI_dequeue (&p_tcb->pending_enc_clcb)) != NULL) + { + if (result == BTM_SUCCESS) + { + if (gatt_get_sec_act(p_tcb) == GATT_SEC_ENCRYPT_MITM ) + { + BTM_GetSecurityFlagsByTransport(bd_addr, &sec_flag, transport); + + if (sec_flag & BTM_SEC_FLAG_LKEY_AUTHED) + { + status = TRUE; + } + } + else + { + status = TRUE; + } + } + gatt_sec_check_complete(status , p_buf->p_clcb, p_tcb->sec_act); + GKI_freebuf(p_buf); + /* start all other pending operation in queue */ + count = GKI_queue_length(&p_tcb->pending_enc_clcb); + for (; count > 0; count --) + { + if ((p_buf = (tGATT_PENDING_ENC_CLCB *)GKI_dequeue (&p_tcb->pending_enc_clcb)) != NULL) + { + gatt_security_check_start(p_buf->p_clcb); + GKI_freebuf(p_buf); + } + else + break; + } + } + else + { + GATT_TRACE_ERROR("Unknown operation encryption completed"); + } + } + else + { + GATT_TRACE_ERROR("enc callback for unknown bd_addr"); + } +} + +/******************************************************************************* +** +** Function gatt_notify_enc_cmpl +** +** Description link encryption complete notification for all encryption process +** initiated outside GATT. +** +** Returns +** +*******************************************************************************/ +void gatt_notify_enc_cmpl(BD_ADDR bd_addr) +{ + tGATT_TCB *p_tcb; + tGATT_PENDING_ENC_CLCB *p_buf; + UINT16 count; + UINT8 i = 0; + + if ((p_tcb = gatt_find_tcb_by_addr(bd_addr, BT_TRANSPORT_LE)) != NULL) + { + for (i = 0; i < GATT_MAX_APPS; i++) + { + if (gatt_cb.cl_rcb[i].in_use && gatt_cb.cl_rcb[i].app_cb.p_enc_cmpl_cb) + { + (*gatt_cb.cl_rcb[i].app_cb.p_enc_cmpl_cb)(gatt_cb.cl_rcb[i].gatt_if, bd_addr); + } + } + + if (gatt_get_sec_act(p_tcb) == GATT_SEC_ENC_PENDING) + { + gatt_set_sec_act(p_tcb, GATT_SEC_NONE); + + count = GKI_queue_length(&p_tcb->pending_enc_clcb); + + for (; count > 0; count --) + { + if ((p_buf = (tGATT_PENDING_ENC_CLCB *)GKI_dequeue (&p_tcb->pending_enc_clcb)) != NULL) + { + gatt_security_check_start(p_buf->p_clcb); + GKI_freebuf(p_buf); + } + else + break; + } + } + } + else + { + GATT_TRACE_DEBUG("notify GATT for encryption completion of unknown device"); + } + return; +} +/******************************************************************************* +** +** Function gatt_set_sec_act +** +** Description This function set the sec_act in clcb +** +** Returns none +** +*******************************************************************************/ +void gatt_set_sec_act(tGATT_TCB *p_tcb, tGATT_SEC_ACTION sec_act) +{ + if (p_tcb) + { + p_tcb->sec_act = sec_act; + } +} +/******************************************************************************* +** +** Function gatt_get_sec_act +** +** Description This function get the sec_act in clcb +** +** Returns none +** +*******************************************************************************/ +tGATT_SEC_ACTION gatt_get_sec_act(tGATT_TCB *p_tcb) +{ + tGATT_SEC_ACTION sec_act = GATT_SEC_NONE; + if (p_tcb) + { + sec_act = p_tcb->sec_act; + } + return sec_act; +} +/******************************************************************************* +** +** Function gatt_determine_sec_act +** +** Description This routine determine the security action based on auth_request and +** current link status +** +** Returns tGATT_SEC_ACTION security action +** +*******************************************************************************/ +tGATT_SEC_ACTION gatt_determine_sec_act(tGATT_CLCB *p_clcb ) +{ + tGATT_SEC_ACTION act = GATT_SEC_OK; + UINT8 sec_flag; + tGATT_TCB *p_tcb = p_clcb->p_tcb; + tGATT_AUTH_REQ auth_req = p_clcb->auth_req; + BOOLEAN is_link_encrypted= FALSE; + BOOLEAN is_link_key_known=FALSE; + BOOLEAN is_key_mitm=FALSE; + UINT8 key_type; + tBTM_BLE_SEC_REQ_ACT sec_act = BTM_LE_SEC_NONE; + + if (auth_req == GATT_AUTH_REQ_NONE ) + return act; + + BTM_GetSecurityFlagsByTransport(p_tcb->peer_bda, &sec_flag, p_clcb->p_tcb->transport); + + btm_ble_link_sec_check(p_tcb->peer_bda, auth_req, &sec_act); + + /* if a encryption is pending, need to wait */ + if (sec_act == BTM_BLE_SEC_REQ_ACT_DISCARD && + auth_req != GATT_AUTH_REQ_NONE) + return GATT_SEC_ENC_PENDING; + + if (sec_flag & (BTM_SEC_FLAG_ENCRYPTED| BTM_SEC_FLAG_LKEY_KNOWN)) + { + if (sec_flag & BTM_SEC_FLAG_ENCRYPTED) + is_link_encrypted = TRUE; + + is_link_key_known = TRUE; + + if (sec_flag & BTM_SEC_FLAG_LKEY_AUTHED) + is_key_mitm = TRUE; + } + + /* first check link key upgrade required or not */ + switch (auth_req) + { + case GATT_AUTH_REQ_MITM: + case GATT_AUTH_REQ_SIGNED_MITM: + if (!is_key_mitm) + act = GATT_SEC_ENCRYPT_MITM; + break; + + case GATT_AUTH_REQ_NO_MITM: + case GATT_AUTH_REQ_SIGNED_NO_MITM: + if (!is_link_key_known) + act = GATT_SEC_ENCRYPT_NO_MITM; + break; + default: + break; + } + + /* now check link needs to be encrypted or not if the link key upgrade is not required */ + if (act == GATT_SEC_OK) + { + if (p_tcb->transport == BT_TRANSPORT_LE && + (p_clcb->operation == GATTC_OPTYPE_WRITE) && + (p_clcb->op_subtype == GATT_WRITE_NO_RSP)) + { + /* this is a write command request + check data signing required or not */ + if (!is_link_encrypted) + { + btm_ble_get_enc_key_type(p_tcb->peer_bda, &key_type); + + if ( (key_type & BTM_LE_KEY_LCSRK) && + ((auth_req == GATT_AUTH_REQ_SIGNED_NO_MITM) || + (auth_req == GATT_AUTH_REQ_SIGNED_MITM))) + { + act = GATT_SEC_SIGN_DATA; + } + else + { + act = GATT_SEC_ENCRYPT; + } + } + } + else + { + if (!is_link_encrypted) + { + act = GATT_SEC_ENCRYPT; + } + } + + } + + return act ; + +} + + + +/******************************************************************************* +** +** Function gatt_get_link_encrypt_status +** +** Description This routine get the encryption status of the specified link +** +** +** Returns tGATT_STATUS link encryption status +** +*******************************************************************************/ +tGATT_STATUS gatt_get_link_encrypt_status(tGATT_TCB *p_tcb) +{ + tGATT_STATUS encrypt_status = GATT_NOT_ENCRYPTED; + UINT8 sec_flag=0; + + BTM_GetSecurityFlagsByTransport(p_tcb->peer_bda, &sec_flag, p_tcb->transport); + + if ((sec_flag & BTM_SEC_FLAG_ENCRYPTED) && (sec_flag & BTM_SEC_FLAG_LKEY_KNOWN)) + { + encrypt_status = GATT_ENCRYPED_NO_MITM; + if (sec_flag & BTM_SEC_FLAG_LKEY_AUTHED) + encrypt_status = GATT_ENCRYPED_MITM; + } + + GATT_TRACE_DEBUG("gatt_get_link_encrypt_status status=0x%x",encrypt_status); + return encrypt_status ; +} + + +/******************************************************************************* +** +** Function gatt_convert_sec_action +** +** Description Convert GATT security action enum into equivalent BTM BLE security action enum +** +** Returns BOOLEAN TRUE - conversation is successful +** +*******************************************************************************/ +static BOOLEAN gatt_convert_sec_action(tGATT_SEC_ACTION gatt_sec_act, tBTM_BLE_SEC_ACT *p_btm_sec_act ) +{ + BOOLEAN status = TRUE; + switch (gatt_sec_act) + { + case GATT_SEC_ENCRYPT: + *p_btm_sec_act = BTM_BLE_SEC_ENCRYPT; + break; + case GATT_SEC_ENCRYPT_NO_MITM: + *p_btm_sec_act = BTM_BLE_SEC_ENCRYPT_NO_MITM; + break; + case GATT_SEC_ENCRYPT_MITM: + *p_btm_sec_act = BTM_BLE_SEC_ENCRYPT_MITM; + break; + default: + status = FALSE; + break; + } + + return status; +} +/******************************************************************************* +** +** Function gatt_check_enc_req +** +** Description check link security. +** +** Returns TRUE if encrypted, otherwise FALSE. +** +*******************************************************************************/ +BOOLEAN gatt_security_check_start(tGATT_CLCB *p_clcb) +{ + tGATT_TCB *p_tcb = p_clcb->p_tcb; + tGATT_SEC_ACTION gatt_sec_act; + tBTM_BLE_SEC_ACT btm_ble_sec_act; + BOOLEAN status = TRUE; + tBTM_STATUS btm_status; + tGATT_SEC_ACTION sec_act_old = gatt_get_sec_act(p_tcb); + + gatt_sec_act = gatt_determine_sec_act(p_clcb); + + if (sec_act_old == GATT_SEC_NONE) + gatt_set_sec_act(p_tcb, gatt_sec_act); + + switch (gatt_sec_act ) + { + case GATT_SEC_SIGN_DATA: + GATT_TRACE_DEBUG("gatt_security_check_start: Do data signing"); + gatt_sign_data(p_clcb); + break; + case GATT_SEC_ENCRYPT: + case GATT_SEC_ENCRYPT_NO_MITM: + case GATT_SEC_ENCRYPT_MITM: + if (sec_act_old < GATT_SEC_ENCRYPT) + { + GATT_TRACE_DEBUG("gatt_security_check_start: Encrypt now or key upgreade first"); + gatt_convert_sec_action(gatt_sec_act, &btm_ble_sec_act); + btm_status = BTM_SetEncryption(p_tcb->peer_bda, p_tcb->transport , gatt_enc_cmpl_cback, &btm_ble_sec_act); + if ( (btm_status != BTM_SUCCESS) && (btm_status != BTM_CMD_STARTED)) + { + GATT_TRACE_ERROR("gatt_security_check_start BTM_SetEncryption failed btm_status=%d", btm_status); + status = FALSE; + } + } + if (status) + gatt_add_pending_enc_channel_clcb (p_tcb, p_clcb); + break; + case GATT_SEC_ENC_PENDING: + gatt_add_pending_enc_channel_clcb (p_tcb, p_clcb); + /* wait for link encrypotion to finish */ + break; + default: + gatt_sec_check_complete(TRUE, p_clcb, gatt_sec_act); + break; + } + + if (status == FALSE) + { + gatt_set_sec_act(p_tcb, GATT_SEC_NONE); + gatt_set_ch_state(p_tcb, GATT_CH_OPEN); + } + + return status; +} + + +#endif /* BLE_INCLUDED */ diff --git a/components/bt/bluedroid/stack/gatt/gatt_cl.c b/components/bt/bluedroid/stack/gatt/gatt_cl.c new file mode 100755 index 0000000000..5db6969f7e --- /dev/null +++ b/components/bt/bluedroid/stack/gatt/gatt_cl.c @@ -0,0 +1,1259 @@ +/****************************************************************************** + * + * Copyright (C) 1999-2012 Broadcom Corporation + * + * 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 main GATT client functions + * + ******************************************************************************/ + +#include "bt_target.h" + +#if BLE_INCLUDED == TRUE + +#include +//#include "bt_utils.h" +#include "gki.h" +#include "gatt_int.h" +#include "l2c_int.h" + +#define GATT_WRITE_LONG_HDR_SIZE 5 /* 1 opcode + 2 handle + 2 offset */ +#define GATT_READ_CHAR_VALUE_HDL (GATT_READ_CHAR_VALUE | 0x80) +#define GATT_READ_INC_SRV_UUID128 (GATT_DISC_INC_SRVC | 0x90) + +#define GATT_PREP_WRITE_RSP_MIN_LEN 4 +#define GATT_NOTIFICATION_MIN_LEN 2 +#define GATT_WRITE_RSP_MIN_LEN 2 +#define GATT_INFO_RSP_MIN_LEN 1 +#define GATT_MTU_RSP_MIN_LEN 2 +#define GATT_READ_BY_TYPE_RSP_MIN_LEN 1 + +/******************************************************************************** +** G L O B A L G A T T D A T A * +*********************************************************************************/ +void gatt_send_prepare_write(tGATT_TCB *p_tcb, tGATT_CLCB *p_clcb); + +UINT8 disc_type_to_att_opcode[GATT_DISC_MAX] = +{ + 0, + GATT_REQ_READ_BY_GRP_TYPE, /* GATT_DISC_SRVC_ALL = 1, */ + GATT_REQ_FIND_TYPE_VALUE, /* GATT_DISC_SRVC_BY_UUID, */ + GATT_REQ_READ_BY_TYPE, /* GATT_DISC_INC_SRVC, */ + GATT_REQ_READ_BY_TYPE, /* GATT_DISC_CHAR, */ + GATT_REQ_FIND_INFO /* GATT_DISC_CHAR_DSCPT, */ +}; + +UINT16 disc_type_to_uuid[GATT_DISC_MAX] = +{ + 0, /* reserved */ + GATT_UUID_PRI_SERVICE, /* DISC_SRVC_ALL */ + GATT_UUID_PRI_SERVICE, /* for DISC_SERVC_BY_UUID */ + GATT_UUID_INCLUDE_SERVICE, /* for DISC_INC_SRVC */ + GATT_UUID_CHAR_DECLARE, /* for DISC_CHAR */ + 0 /* no type filtering for DISC_CHAR_DSCPT */ +}; + + +/******************************************************************************* +** +** Function gatt_act_discovery +** +** Description GATT discovery operation. +** +** Returns void. +** +*******************************************************************************/ +void gatt_act_discovery(tGATT_CLCB *p_clcb) +{ + UINT8 op_code = disc_type_to_att_opcode[p_clcb->op_subtype]; + tGATT_CL_MSG cl_req; + tGATT_STATUS st; + + if (p_clcb->s_handle <= p_clcb->e_handle && p_clcb->s_handle != 0) + { + memset(&cl_req, 0, sizeof(tGATT_CL_MSG)); + + cl_req.browse.s_handle = p_clcb->s_handle; + cl_req.browse.e_handle = p_clcb->e_handle; + + if (disc_type_to_uuid[p_clcb->op_subtype] != 0) + { + cl_req.browse.uuid.len = 2; + cl_req.browse.uuid.uu.uuid16 = disc_type_to_uuid[p_clcb->op_subtype]; + } + + if (p_clcb->op_subtype == GATT_DISC_SRVC_BY_UUID) /* fill in the FindByTypeValue request info*/ + { + cl_req.find_type_value.uuid.len = 2; + cl_req.find_type_value.uuid.uu.uuid16 = disc_type_to_uuid[p_clcb->op_subtype]; + cl_req.find_type_value.s_handle = p_clcb->s_handle; + cl_req.find_type_value.e_handle = p_clcb->e_handle; + cl_req.find_type_value.value_len = p_clcb->uuid.len; + /* if service type is 32 bits UUID, convert it now */ + if (p_clcb->uuid.len == LEN_UUID_32) + { + cl_req.find_type_value.value_len = LEN_UUID_128; + gatt_convert_uuid32_to_uuid128(cl_req.find_type_value.value, p_clcb->uuid.uu.uuid32); + } + else + memcpy (cl_req.find_type_value.value, &p_clcb->uuid.uu, p_clcb->uuid.len); + } + + st = attp_send_cl_msg(p_clcb->p_tcb, p_clcb->clcb_idx, op_code, &cl_req); + + if (st != GATT_SUCCESS && st != GATT_CMD_STARTED) + { + gatt_end_operation(p_clcb, GATT_ERROR, NULL); + } + } + else /* end of handle range */ + gatt_end_operation(p_clcb, GATT_SUCCESS, NULL); +} + +/******************************************************************************* +** +** Function gatt_act_read +** +** Description GATT read operation. +** +** Returns void. +** +*******************************************************************************/ +void gatt_act_read (tGATT_CLCB *p_clcb, UINT16 offset) +{ + tGATT_TCB *p_tcb = p_clcb->p_tcb; + UINT8 rt = GATT_INTERNAL_ERROR; + tGATT_CL_MSG msg; + UINT8 op_code = 0; + + memset (&msg, 0, sizeof(tGATT_CL_MSG)); + + switch (p_clcb->op_subtype) + { + case GATT_READ_CHAR_VALUE: + case GATT_READ_BY_TYPE: + op_code = GATT_REQ_READ_BY_TYPE; + msg.browse.s_handle = p_clcb->s_handle; + msg.browse.e_handle = p_clcb->e_handle; + if (p_clcb->op_subtype == GATT_READ_BY_TYPE) + memcpy(&msg.browse.uuid, &p_clcb->uuid, sizeof(tBT_UUID)); + else + { + msg.browse.uuid.len = LEN_UUID_16; + msg.browse.uuid.uu.uuid16 = GATT_UUID_CHAR_DECLARE; + } + break; + + case GATT_READ_CHAR_VALUE_HDL: + case GATT_READ_BY_HANDLE: + if (!p_clcb->counter) + { + op_code = GATT_REQ_READ; + msg.handle = p_clcb->s_handle; + } + else + { + if (!p_clcb->first_read_blob_after_read) + p_clcb->first_read_blob_after_read = TRUE; + else + p_clcb->first_read_blob_after_read = FALSE; + + GATT_TRACE_DEBUG("gatt_act_read first_read_blob_after_read=%d", + p_clcb->first_read_blob_after_read); + op_code = GATT_REQ_READ_BLOB; + msg.read_blob.offset = offset; + msg.read_blob.handle = p_clcb->s_handle; + } + p_clcb->op_subtype &= ~ 0x80; + break; + + case GATT_READ_PARTIAL: + op_code = GATT_REQ_READ_BLOB; + msg.read_blob.handle = p_clcb->s_handle; + msg.read_blob.offset = offset; + break; + + case GATT_READ_MULTIPLE: + op_code = GATT_REQ_READ_MULTI; + memcpy (&msg.read_multi, p_clcb->p_attr_buf, sizeof(tGATT_READ_MULTI)); + break; + + case GATT_READ_INC_SRV_UUID128: + op_code = GATT_REQ_READ; + msg.handle = p_clcb->s_handle; + p_clcb->op_subtype &= ~ 0x90; + break; + + default: + GATT_TRACE_ERROR("Unknown read type: %d", p_clcb->op_subtype); + break; + } + + if (op_code != 0) + rt = attp_send_cl_msg(p_tcb, p_clcb->clcb_idx, op_code, &msg); + + if ( op_code == 0 || (rt != GATT_SUCCESS && rt != GATT_CMD_STARTED)) + { + gatt_end_operation(p_clcb, rt, NULL); + } +} + +/******************************************************************************* +** +** Function gatt_act_write +** +** Description GATT write operation. +** +** Returns void. +** +*******************************************************************************/ +void gatt_act_write (tGATT_CLCB *p_clcb, UINT8 sec_act) +{ + tGATT_TCB *p_tcb = p_clcb->p_tcb; + UINT8 rt = GATT_SUCCESS, op_code = 0; + tGATT_VALUE *p_attr = (tGATT_VALUE *)p_clcb->p_attr_buf; + + if (p_attr) + { + switch (p_clcb->op_subtype) + { + case GATT_WRITE_NO_RSP: + p_clcb->s_handle = p_attr->handle; + op_code = (sec_act == GATT_SEC_SIGN_DATA) ? GATT_SIGN_CMD_WRITE : GATT_CMD_WRITE; + rt = gatt_send_write_msg(p_tcb, + p_clcb->clcb_idx, + op_code, + p_attr->handle, + p_attr->len, + 0, + p_attr->value); + break; + + case GATT_WRITE: + if (p_attr->len <= (p_tcb->payload_size - GATT_HDR_SIZE)) + { + p_clcb->s_handle = p_attr->handle; + + rt = gatt_send_write_msg(p_tcb, + p_clcb->clcb_idx, + GATT_REQ_WRITE, + p_attr->handle, + p_attr->len, + 0, + p_attr->value); + } + else /* prepare write for long attribute */ + { + gatt_send_prepare_write(p_tcb, p_clcb); + } + break; + + case GATT_WRITE_PREPARE: + gatt_send_prepare_write(p_tcb, p_clcb); + break; + + default: + rt = GATT_INTERNAL_ERROR; + GATT_TRACE_ERROR("Unknown write type: %d", p_clcb->op_subtype); + break; + } + } + else + rt = GATT_INTERNAL_ERROR; + + if ((rt != GATT_SUCCESS && rt != GATT_CMD_STARTED && rt != GATT_CONGESTED) + || (rt != GATT_CMD_STARTED && p_clcb->op_subtype == GATT_WRITE_NO_RSP)) + { + if (rt != GATT_SUCCESS) + { + GATT_TRACE_ERROR("gatt_act_write() failed op_code=0x%x rt=%d", op_code, rt); + } + gatt_end_operation(p_clcb, rt, NULL); + } +} +/******************************************************************************* +** +** Function gatt_send_queue_write_cancel +** +** Description send queue write cancel +** +** Returns void. +** +*******************************************************************************/ +void gatt_send_queue_write_cancel (tGATT_TCB *p_tcb, tGATT_CLCB *p_clcb, tGATT_EXEC_FLAG flag) +{ + UINT8 rt ; + + GATT_TRACE_DEBUG("gatt_send_queue_write_cancel "); + + rt = attp_send_cl_msg(p_tcb, p_clcb->clcb_idx, GATT_REQ_EXEC_WRITE, (tGATT_CL_MSG *)&flag); + + if (rt != GATT_SUCCESS) + { + gatt_end_operation(p_clcb, rt, NULL); + } +} +/******************************************************************************* +** +** Function gatt_check_write_long_terminate +** +** Description To terminate write long or not. +** +** Returns TRUE: write long is terminated; FALSE keep sending. +** +*******************************************************************************/ +BOOLEAN gatt_check_write_long_terminate(tGATT_TCB *p_tcb, tGATT_CLCB *p_clcb, tGATT_VALUE *p_rsp_value) +{ + tGATT_VALUE *p_attr = (tGATT_VALUE *)p_clcb->p_attr_buf; + BOOLEAN exec = FALSE; + tGATT_EXEC_FLAG flag = GATT_PREP_WRITE_EXEC; + + GATT_TRACE_DEBUG("gatt_check_write_long_terminate "); + /* check the first write response status */ + if (p_rsp_value != NULL) + { + if (p_rsp_value->handle != p_attr->handle || + p_rsp_value->len != p_clcb->counter || + memcmp(p_rsp_value->value, p_attr->value + p_attr->offset, p_rsp_value->len)) + { + /* data does not match */ + p_clcb->status = GATT_ERROR; + flag = GATT_PREP_WRITE_CANCEL; + exec = TRUE; + } + else /* response checking is good */ + { + p_clcb->status = GATT_SUCCESS; + /* update write offset and check if end of attribute value */ + if ((p_attr->offset += p_rsp_value->len) >= p_attr->len) + exec = TRUE; + } + } + if (exec) + { + gatt_send_queue_write_cancel (p_tcb, p_clcb, flag); + return TRUE; + } + return FALSE; +} +/******************************************************************************* +** +** Function gatt_send_prepare_write +** +** Description Send prepare write. +** +** Returns void. +** +*******************************************************************************/ +void gatt_send_prepare_write(tGATT_TCB *p_tcb, tGATT_CLCB *p_clcb) +{ + tGATT_VALUE *p_attr = (tGATT_VALUE *)p_clcb->p_attr_buf; + UINT16 to_send, offset; + UINT8 rt = GATT_SUCCESS; + UINT8 type = p_clcb->op_subtype; + + GATT_TRACE_DEBUG("gatt_send_prepare_write type=0x%x", type ); + to_send = p_attr->len - p_attr->offset; + + if (to_send > (p_tcb->payload_size - GATT_WRITE_LONG_HDR_SIZE)) /* 2 = UINT16 offset bytes */ + to_send = p_tcb->payload_size - GATT_WRITE_LONG_HDR_SIZE; + + p_clcb->s_handle = p_attr->handle; + + offset = p_attr->offset; + if (type == GATT_WRITE_PREPARE) + { + offset += p_clcb->start_offset; + } + + GATT_TRACE_DEBUG("offset =0x%x len=%d", offset, to_send ); + + rt = gatt_send_write_msg(p_tcb, + p_clcb->clcb_idx, + GATT_REQ_PREPARE_WRITE, + p_attr->handle, + to_send, /* length */ + offset, /* used as offset */ + p_attr->value + p_attr->offset); /* data */ + + /* remember the write long attribute length */ + p_clcb->counter = to_send; + + if (rt != GATT_SUCCESS && rt != GATT_CMD_STARTED) + { + gatt_end_operation(p_clcb, rt, NULL); + } +} + + +/******************************************************************************* +** +** Function gatt_process_find_type_value_rsp +** +** Description This function is called to handle find by type value response. +** +** +** Returns void +** +*******************************************************************************/ +void gatt_process_find_type_value_rsp (tGATT_TCB *p_tcb, tGATT_CLCB *p_clcb, UINT16 len, UINT8 *p_data) +{ + tGATT_DISC_RES result; + UINT8 *p = p_data; + + UNUSED(p_tcb); + + GATT_TRACE_DEBUG("gatt_process_find_type_value_rsp "); + /* unexpected response */ + if (p_clcb->operation != GATTC_OPTYPE_DISCOVERY || p_clcb->op_subtype != GATT_DISC_SRVC_BY_UUID) + return; + + memset (&result, 0, sizeof(tGATT_DISC_RES)); + result.type.len = 2; + result.type.uu.uuid16 = GATT_UUID_PRI_SERVICE; + + /* returns a series of handle ranges */ + while (len >= 4) + { + STREAM_TO_UINT16 (result.handle, p); + STREAM_TO_UINT16 (result.value.group_value.e_handle, p); + memcpy (&result.value.group_value.service_type, &p_clcb->uuid, sizeof(tBT_UUID)); + + len -= 4; + + if (p_clcb->p_reg->app_cb.p_disc_res_cb) + (*p_clcb->p_reg->app_cb.p_disc_res_cb)(p_clcb->conn_id, p_clcb->op_subtype, &result); + } + + /* last handle + 1 */ + p_clcb->s_handle = (result.value.group_value.e_handle == 0) ? 0 : (result.value.group_value.e_handle + 1); + /* initiate another request */ + gatt_act_discovery(p_clcb) ; +} +/******************************************************************************* +** +** Function gatt_process_read_info_rsp +** +** Description This function is called to handle the read information +** response. +** +** +** Returns void +** +*******************************************************************************/ +void gatt_process_read_info_rsp(tGATT_TCB *p_tcb, tGATT_CLCB *p_clcb, UINT8 op_code, + UINT16 len, UINT8 *p_data) +{ + tGATT_DISC_RES result; + UINT8 *p = p_data, uuid_len = 0, type; + + UNUSED(p_tcb); + UNUSED(op_code); + + if (len < GATT_INFO_RSP_MIN_LEN) + { + GATT_TRACE_ERROR("invalid Info Response PDU received, discard."); + gatt_end_operation(p_clcb, GATT_INVALID_PDU, NULL); + return; + } + /* unexpected response */ + if (p_clcb->operation != GATTC_OPTYPE_DISCOVERY || p_clcb->op_subtype != GATT_DISC_CHAR_DSCPT) + return; + + STREAM_TO_UINT8(type, p); + len -= 1; + + if (type == GATT_INFO_TYPE_PAIR_16) + uuid_len = LEN_UUID_16; + else if (type == GATT_INFO_TYPE_PAIR_128) + uuid_len = LEN_UUID_128; + + while (len >= uuid_len + 2) + { + STREAM_TO_UINT16 (result.handle, p); + + if (uuid_len > 0) + { + if (!gatt_parse_uuid_from_cmd(&result.type, uuid_len, &p)) + break; + } + else + memcpy (&result.type, &p_clcb->uuid, sizeof(tBT_UUID)); + + len -= (uuid_len + 2); + + if (p_clcb->p_reg->app_cb.p_disc_res_cb) + (*p_clcb->p_reg->app_cb.p_disc_res_cb)(p_clcb->conn_id, p_clcb->op_subtype, &result); + } + + p_clcb->s_handle = (result.handle == 0) ? 0 :(result.handle + 1); + /* initiate another request */ + gatt_act_discovery(p_clcb) ; +} +/******************************************************************************* +** +** Function gatt_proc_disc_error_rsp +** +** Description This function process the read by type response and send another +** request if needed. +** +** Returns void. +** +*******************************************************************************/ +void gatt_proc_disc_error_rsp(tGATT_TCB *p_tcb, tGATT_CLCB *p_clcb, UINT8 opcode, + UINT16 handle, UINT8 reason) +{ + tGATT_STATUS status = (tGATT_STATUS) reason; + + UNUSED(p_tcb); + UNUSED(handle); + + GATT_TRACE_DEBUG("gatt_proc_disc_error_rsp reason: %02x cmd_code %04x", reason, opcode); + + switch (opcode) + { + case GATT_REQ_READ_BY_GRP_TYPE: + case GATT_REQ_FIND_TYPE_VALUE: + case GATT_REQ_READ_BY_TYPE: + case GATT_REQ_FIND_INFO: + if (reason == GATT_NOT_FOUND) + { + status = GATT_SUCCESS; + GATT_TRACE_DEBUG("Discovery completed"); + } + break; + default: + GATT_TRACE_ERROR("Incorrect discovery opcode %04x", opcode); + break; + } + + gatt_end_operation(p_clcb, status, NULL); +} + +/******************************************************************************* +** +** Function gatt_process_error_rsp +** +** Description This function is called to handle the error response +** +** +** Returns void +** +*******************************************************************************/ +void gatt_process_error_rsp(tGATT_TCB *p_tcb, tGATT_CLCB *p_clcb, UINT8 op_code, + UINT16 len, UINT8 *p_data) +{ + UINT8 opcode, reason, * p= p_data; + UINT16 handle; + tGATT_VALUE *p_attr = (tGATT_VALUE *)p_clcb->p_attr_buf; + + UNUSED(op_code); + UNUSED(len); + + GATT_TRACE_DEBUG("gatt_process_error_rsp "); + STREAM_TO_UINT8(opcode, p); + STREAM_TO_UINT16(handle, p); + STREAM_TO_UINT8(reason, p); + + if (p_clcb->operation == GATTC_OPTYPE_DISCOVERY) + { + gatt_proc_disc_error_rsp(p_tcb, p_clcb, opcode, handle, reason); + } + else + { + if ( (p_clcb->operation == GATTC_OPTYPE_WRITE) && + (p_clcb->op_subtype == GATT_WRITE) && + (opcode == GATT_REQ_PREPARE_WRITE) && + (p_attr) && + (handle == p_attr->handle) ) + { + p_clcb->status = reason; + gatt_send_queue_write_cancel(p_tcb, p_clcb, GATT_PREP_WRITE_CANCEL); + } + else if ((p_clcb->operation == GATTC_OPTYPE_READ) && + ((p_clcb->op_subtype == GATT_READ_CHAR_VALUE_HDL) || + (p_clcb->op_subtype == GATT_READ_BY_HANDLE)) && + (opcode == GATT_REQ_READ_BLOB) && + p_clcb->first_read_blob_after_read && + (reason == GATT_NOT_LONG)) + { + gatt_end_operation(p_clcb, GATT_SUCCESS, (void *)p_clcb->p_attr_buf); + } + else + gatt_end_operation(p_clcb, reason, NULL); + } +} +/******************************************************************************* +** +** Function gatt_process_prep_write_rsp +** +** Description This function is called to handle the read response +** +** +** Returns void +** +*******************************************************************************/ +void gatt_process_prep_write_rsp (tGATT_TCB *p_tcb, tGATT_CLCB *p_clcb, UINT8 op_code, + UINT16 len, UINT8 *p_data) +{ + tGATT_VALUE value = {0}; + UINT8 *p= p_data; + + GATT_TRACE_ERROR("value resp op_code = %s len = %d", gatt_dbg_op_name(op_code), len); + + if (len < GATT_PREP_WRITE_RSP_MIN_LEN) + { + GATT_TRACE_ERROR("illegal prepare write response length, discard"); + gatt_end_operation(p_clcb, GATT_INVALID_PDU, &value); + return; + } + + STREAM_TO_UINT16 (value.handle, p); + STREAM_TO_UINT16 (value.offset, p); + + value.len = len - 4; + + memcpy (value.value, p, value.len); + + if (p_clcb->op_subtype == GATT_WRITE_PREPARE) + { + p_clcb->status = GATT_SUCCESS; + /* application should verify handle offset + and value are matched or not */ + + gatt_end_operation(p_clcb, p_clcb->status, &value); + } + else if (p_clcb->op_subtype == GATT_WRITE ) + { + if (!gatt_check_write_long_terminate(p_tcb, p_clcb, &value)) + gatt_send_prepare_write(p_tcb, p_clcb); + } + +} +/******************************************************************************* +** +** Function gatt_process_notification +** +** Description This function is called to handle the handle value indication +** or handle value notification. +** +** +** Returns void +** +*******************************************************************************/ +void gatt_process_notification(tGATT_TCB *p_tcb, UINT8 op_code, + UINT16 len, UINT8 *p_data) +{ + tGATT_VALUE value = {0}; + tGATT_REG *p_reg; + UINT16 conn_id; + tGATT_STATUS encrypt_status; + UINT8 *p= p_data, i, + event = (op_code == GATT_HANDLE_VALUE_NOTIF) ? GATTC_OPTYPE_NOTIFICATION : GATTC_OPTYPE_INDICATION; + + GATT_TRACE_DEBUG("gatt_process_notification "); + + if (len < GATT_NOTIFICATION_MIN_LEN) + { + GATT_TRACE_ERROR("illegal notification PDU length, discard"); + return; + } + + STREAM_TO_UINT16 (value.handle, p); + value.len = len - 2; + memcpy (value.value, p, value.len); + + if (!GATT_HANDLE_IS_VALID(value.handle)) + { + /* illegal handle, send ack now */ + if (op_code == GATT_HANDLE_VALUE_IND) + attp_send_cl_msg(p_tcb, 0, GATT_HANDLE_VALUE_CONF, NULL); + return; + } + + if (event == GATTC_OPTYPE_INDICATION) + { + if (p_tcb->ind_count) + { + /* this is an error case that receiving an indication but we + still has an indication not being acked yet. + For now, just log the error reset the counter. + Later we need to disconnect the link unconditionally. + */ + GATT_TRACE_ERROR("gatt_process_notification rcv Ind. but ind_count=%d (will reset ind_count)", p_tcb->ind_count); + } + p_tcb->ind_count = 0; + } + + /* should notify all registered client with the handle value notificaion/indication + Note: need to do the indication count and start timer first then do callback + */ + + for (i = 0, p_reg = gatt_cb.cl_rcb; i < GATT_MAX_APPS; i++, p_reg++) + { + if (p_reg->in_use && p_reg->app_cb.p_cmpl_cb && (event == GATTC_OPTYPE_INDICATION)) + p_tcb->ind_count++; + } + + if (event == GATTC_OPTYPE_INDICATION) + { + /* start a timer for app confirmation */ + if (p_tcb->ind_count > 0) + gatt_start_ind_ack_timer(p_tcb); + else /* no app to indicate, or invalid handle */ + attp_send_cl_msg(p_tcb, 0, GATT_HANDLE_VALUE_CONF, NULL); + } + + encrypt_status = gatt_get_link_encrypt_status(p_tcb); + for (i = 0, p_reg = gatt_cb.cl_rcb; i < GATT_MAX_APPS; i++, p_reg++) + { + if (p_reg->in_use && p_reg->app_cb.p_cmpl_cb) + { + conn_id = GATT_CREATE_CONN_ID(p_tcb->tcb_idx, p_reg->gatt_if); + (*p_reg->app_cb.p_cmpl_cb) (conn_id, event, encrypt_status, (tGATT_CL_COMPLETE *)&value); + } + } + +} + +/******************************************************************************* +** +** Function gatt_process_read_by_type_rsp +** +** Description This function is called to handle the read by type response. +** read by type can be used for discovery, or read by type or +** read characteristic value. +** +** Returns void +** +*******************************************************************************/ +void gatt_process_read_by_type_rsp (tGATT_TCB *p_tcb, tGATT_CLCB *p_clcb, UINT8 op_code, + UINT16 len, UINT8 *p_data) +{ + tGATT_DISC_RES result; + tGATT_DISC_VALUE record_value; + UINT8 *p = p_data, value_len, handle_len = 2; + UINT16 handle = 0; + + /* discovery procedure and no callback function registered */ + if (((!p_clcb->p_reg) || (!p_clcb->p_reg->app_cb.p_disc_res_cb)) && (p_clcb->operation == GATTC_OPTYPE_DISCOVERY)) + return; + + if (len < GATT_READ_BY_TYPE_RSP_MIN_LEN) + { + GATT_TRACE_ERROR("Illegal ReadByType/ReadByGroupType Response length, discard"); + gatt_end_operation(p_clcb, GATT_INVALID_PDU, NULL); + return; + } + + STREAM_TO_UINT8(value_len, p); + + if ((value_len > (p_tcb->payload_size - 2)) || (value_len > (len-1)) ) + { + /* this is an error case that server's response containing a value length which is larger than MTU-2 + or value_len > message total length -1 */ + GATT_TRACE_ERROR("gatt_process_read_by_type_rsp: Discard response op_code=%d vale_len=%d > (MTU-2=%d or msg_len-1=%d)", + op_code, value_len, (p_tcb->payload_size - 2), (len-1)); + gatt_end_operation(p_clcb, GATT_ERROR, NULL); + return; + } + + if (op_code == GATT_RSP_READ_BY_GRP_TYPE) + handle_len = 4; + + value_len -= handle_len; /* substract the handle pairs bytes */ + len -= 1; + + while (len >= (handle_len + value_len)) + { + STREAM_TO_UINT16(handle, p); + + if (!GATT_HANDLE_IS_VALID(handle)) + { + gatt_end_operation(p_clcb, GATT_INVALID_HANDLE, NULL); + return; + } + + memset(&result, 0, sizeof(tGATT_DISC_RES)); + memset(&record_value, 0, sizeof(tGATT_DISC_VALUE)); + + result.handle = handle; + result.type.len = 2; + result.type.uu.uuid16 = disc_type_to_uuid[p_clcb->op_subtype]; + + /* discover all services */ + if (p_clcb->operation == GATTC_OPTYPE_DISCOVERY && + p_clcb->op_subtype == GATT_DISC_SRVC_ALL && + op_code == GATT_RSP_READ_BY_GRP_TYPE) + { + STREAM_TO_UINT16(handle, p); + + if (!GATT_HANDLE_IS_VALID(handle)) + { + gatt_end_operation(p_clcb, GATT_INVALID_HANDLE, NULL); + return; + } + else + { + record_value.group_value.e_handle = handle; + if (!gatt_parse_uuid_from_cmd(&record_value.group_value.service_type, value_len, &p)) + { + GATT_TRACE_ERROR("discover all service response parsing failure"); + break; + } + } + } + /* discover included service */ + else if (p_clcb->operation == GATTC_OPTYPE_DISCOVERY && p_clcb->op_subtype == GATT_DISC_INC_SRVC) + { + STREAM_TO_UINT16(record_value.incl_service.s_handle, p); + STREAM_TO_UINT16(record_value.incl_service.e_handle, p); + + if (!GATT_HANDLE_IS_VALID(record_value.incl_service.s_handle) || + !GATT_HANDLE_IS_VALID(record_value.incl_service.e_handle)) + { + gatt_end_operation(p_clcb, GATT_INVALID_HANDLE, NULL); + return; + } + + if(value_len == 6) + { + STREAM_TO_UINT16(record_value.incl_service.service_type.uu.uuid16, p); + record_value.incl_service.service_type.len = LEN_UUID_16; + } + else if (value_len == 4) + { + p_clcb->s_handle = record_value.incl_service.s_handle; + p_clcb->read_uuid128.wait_for_read_rsp = TRUE; + p_clcb->read_uuid128.next_disc_start_hdl = handle + 1; + memcpy(&p_clcb->read_uuid128.result, &result, sizeof(result)); + memcpy(&p_clcb->read_uuid128.result.value, &record_value, sizeof (result.value)); + p_clcb->op_subtype |= 0x90; + gatt_act_read(p_clcb, 0); + return; + } + else + { + GATT_TRACE_ERROR("gatt_process_read_by_type_rsp INCL_SRVC failed with invalid data value_len=%d", value_len); + gatt_end_operation(p_clcb, GATT_INVALID_PDU, (void *)p); + return; + } + } + /* read by type */ + else if (p_clcb->operation == GATTC_OPTYPE_READ && p_clcb->op_subtype == GATT_READ_BY_TYPE) + { + p_clcb->counter = len - 2; + p_clcb->s_handle = handle; + if ( p_clcb->counter == (p_clcb->p_tcb->payload_size -4)) + { + p_clcb->op_subtype = GATT_READ_BY_HANDLE; + if (!p_clcb->p_attr_buf) + p_clcb->p_attr_buf = (UINT8 *)GKI_getbuf(GATT_MAX_ATTR_LEN); + if (p_clcb->p_attr_buf && p_clcb->counter <= GATT_MAX_ATTR_LEN) + { + memcpy(p_clcb->p_attr_buf, p, p_clcb->counter); + gatt_act_read(p_clcb, p_clcb->counter); + } + else + gatt_end_operation(p_clcb, GATT_INTERNAL_ERROR, (void *)p); + } + else + { + gatt_end_operation(p_clcb, GATT_SUCCESS, (void *)p); + } + return; + } + else /* discover characterisitic */ + { + STREAM_TO_UINT8 (record_value.dclr_value.char_prop, p); + STREAM_TO_UINT16(record_value.dclr_value.val_handle, p); + if (!GATT_HANDLE_IS_VALID(record_value.dclr_value.val_handle)) + { + gatt_end_operation(p_clcb, GATT_INVALID_HANDLE, NULL); + return; + } + if (!gatt_parse_uuid_from_cmd(&record_value.dclr_value.char_uuid, (UINT16)(value_len - 3), &p)) + { + gatt_end_operation(p_clcb, GATT_SUCCESS, NULL); + /* invalid format, and skip the result */ + return; + } + + /* UUID not matching */ + if (!gatt_uuid_compare(record_value.dclr_value.char_uuid, p_clcb->uuid)) + { + len -= (value_len + 2); + continue; /* skip the result, and look for next one */ + } + else if (p_clcb->operation == GATTC_OPTYPE_READ) + /* UUID match for read characteristic value */ + { + /* only read the first matching UUID characteristic value, and + discard the rest results */ + p_clcb->s_handle = record_value.dclr_value.val_handle; + p_clcb->op_subtype |= 0x80; + gatt_act_read(p_clcb, 0); + return; + } + } + len -= (value_len + handle_len); + + /* result is (handle, 16bits UUID) pairs */ + memcpy (&result.value, &record_value, sizeof (result.value)); + + /* send callback if is discover procedure */ + if (p_clcb->operation == GATTC_OPTYPE_DISCOVERY && p_clcb->p_reg->app_cb.p_disc_res_cb) + (*p_clcb->p_reg->app_cb.p_disc_res_cb)(p_clcb->conn_id, p_clcb->op_subtype, &result); + } + + p_clcb->s_handle = (handle == 0) ? 0 : (handle + 1); + + if (p_clcb->operation == GATTC_OPTYPE_DISCOVERY) + { + /* initiate another request */ + gatt_act_discovery(p_clcb) ; + } + else /* read characteristic value */ + { + gatt_act_read(p_clcb, 0); + } +} + +/******************************************************************************* +** +** Function gatt_process_read_rsp +** +** Description This function is called to handle the read BLOB response +** +** +** Returns void +** +*******************************************************************************/ +void gatt_process_read_rsp(tGATT_TCB *p_tcb, tGATT_CLCB *p_clcb, UINT8 op_code, + UINT16 len, UINT8 *p_data) +{ + UINT16 offset = p_clcb->counter; + UINT8 * p= p_data; + + UNUSED(op_code); + + if (p_clcb->operation == GATTC_OPTYPE_READ) + { + if (p_clcb->op_subtype != GATT_READ_BY_HANDLE) + { + p_clcb->counter = len; + gatt_end_operation(p_clcb, GATT_SUCCESS, (void *)p); + } + else + { + + /* allocate GKI buffer holding up long attribute value */ + if (!p_clcb->p_attr_buf) + p_clcb->p_attr_buf = (UINT8 *)GKI_getbuf(GATT_MAX_ATTR_LEN); + + /* copy attrobute value into cb buffer */ + if (p_clcb->p_attr_buf && offset < GATT_MAX_ATTR_LEN) + { + if ((len + offset) > GATT_MAX_ATTR_LEN) + len = GATT_MAX_ATTR_LEN - offset; + + p_clcb->counter += len; + + memcpy(p_clcb->p_attr_buf + offset, p, len); + + /* send next request if needed */ + + if (len == (p_tcb->payload_size - 1) && /* full packet for read or read blob rsp */ + len + offset < GATT_MAX_ATTR_LEN) + { + GATT_TRACE_DEBUG("full pkt issue read blob for remianing bytes old offset=%d len=%d new offset=%d", + offset, len, p_clcb->counter); + gatt_act_read(p_clcb, p_clcb->counter); + } + else /* end of request, send callback */ + { + gatt_end_operation(p_clcb, GATT_SUCCESS, (void *)p_clcb->p_attr_buf); + } + } + else /* exception, should not happen */ + { + GATT_TRACE_ERROR("attr offset = %d p_attr_buf = %d ", offset, p_clcb->p_attr_buf); + gatt_end_operation(p_clcb, GATT_NO_RESOURCES, (void *)p_clcb->p_attr_buf); + } + } + } + else + { + if (p_clcb->operation == GATTC_OPTYPE_DISCOVERY && + p_clcb->op_subtype == GATT_DISC_INC_SRVC && + p_clcb->read_uuid128.wait_for_read_rsp ) + { + p_clcb->s_handle = p_clcb->read_uuid128.next_disc_start_hdl; + p_clcb->read_uuid128.wait_for_read_rsp = FALSE; + if (len == LEN_UUID_128) + { + + memcpy(p_clcb->read_uuid128.result.value.incl_service.service_type.uu.uuid128, p, len); + p_clcb->read_uuid128.result.value.incl_service.service_type.len = LEN_UUID_128; + if ( p_clcb->p_reg->app_cb.p_disc_res_cb) + (*p_clcb->p_reg->app_cb.p_disc_res_cb)(p_clcb->conn_id, p_clcb->op_subtype, &p_clcb->read_uuid128.result); + gatt_act_discovery(p_clcb) ; + } + else + { + gatt_end_operation(p_clcb, GATT_INVALID_PDU, (void *)p); + } + } + } + +} + + +/******************************************************************************* +** +** Function gatt_process_handle_rsp +** +** Description This function is called to handle the write response +** +** +** Returns void +** +*******************************************************************************/ +void gatt_process_handle_rsp(tGATT_CLCB *p_clcb) +{ + gatt_end_operation(p_clcb, GATT_SUCCESS, NULL); +} +/******************************************************************************* +** +** Function gatt_process_mtu_rsp +** +** Description This function is called to process the configure MTU response. +** +** +** Returns void +** +*******************************************************************************/ +void gatt_process_mtu_rsp(tGATT_TCB *p_tcb, tGATT_CLCB *p_clcb, UINT16 len, UINT8 *p_data) +{ + UINT16 mtu; + tGATT_STATUS status = GATT_SUCCESS; + + if (len < GATT_MTU_RSP_MIN_LEN) + { + GATT_TRACE_ERROR("invalid MTU response PDU received, discard."); + status = GATT_INVALID_PDU; + } + else + { + STREAM_TO_UINT16(mtu, p_data); + + if (mtu < p_tcb->payload_size && mtu >= GATT_DEF_BLE_MTU_SIZE) + p_tcb->payload_size = mtu; + } + + l2cble_set_fixed_channel_tx_data_length(p_tcb->peer_bda, L2CAP_ATT_CID, p_tcb->payload_size); + gatt_end_operation(p_clcb, status, NULL); +} +/******************************************************************************* +** +** Function gatt_cmd_to_rsp_code +** +** Description The function convert a ATT command op code into the corresponding +** response code assume no error occurs. +** +** Returns response code. +** +*******************************************************************************/ +UINT8 gatt_cmd_to_rsp_code (UINT8 cmd_code) +{ + UINT8 rsp_code = 0; + + if (cmd_code > 1 && cmd_code != GATT_CMD_WRITE) + { + rsp_code = cmd_code + 1; + } + return rsp_code; +} +/******************************************************************************* +** +** Function gatt_cl_send_next_cmd_inq +** +** Description Find next command in queue and sent to server +** +** Returns TRUE if command sent, otherwise FALSE. +** +*******************************************************************************/ +BOOLEAN gatt_cl_send_next_cmd_inq(tGATT_TCB *p_tcb) +{ + tGATT_CMD_Q *p_cmd = &p_tcb->cl_cmd_q[p_tcb->pending_cl_req]; + BOOLEAN sent = FALSE; + UINT8 rsp_code; + tGATT_CLCB *p_clcb = NULL; + tGATT_STATUS att_ret = GATT_SUCCESS; + + while (!sent && + p_tcb->pending_cl_req != p_tcb->next_slot_inq && + p_cmd->to_send && p_cmd->p_cmd != NULL) + { + att_ret = attp_send_msg_to_l2cap(p_tcb, p_cmd->p_cmd); + + if (att_ret == GATT_SUCCESS || att_ret == GATT_CONGESTED) + { + sent = TRUE; + p_cmd->to_send = FALSE; + p_cmd->p_cmd = NULL; + + /* dequeue the request if is write command or sign write */ + if (p_cmd->op_code != GATT_CMD_WRITE && p_cmd->op_code != GATT_SIGN_CMD_WRITE) + { + gatt_start_rsp_timer (p_cmd->clcb_idx); + } + else + { + p_clcb = gatt_cmd_dequeue(p_tcb, &rsp_code); + + /* if no ack needed, keep sending */ + if (att_ret == GATT_SUCCESS) + sent = FALSE; + + p_cmd = &p_tcb->cl_cmd_q[p_tcb->pending_cl_req]; + /* send command complete callback here */ + gatt_end_operation(p_clcb, att_ret, NULL); + } + } + else + { + GATT_TRACE_ERROR("gatt_cl_send_next_cmd_inq: L2CAP sent error"); + + memset(p_cmd, 0, sizeof(tGATT_CMD_Q)); + p_tcb->pending_cl_req ++; + p_cmd = &p_tcb->cl_cmd_q[p_tcb->pending_cl_req]; + } + + } + return sent; +} + +/******************************************************************************* +** +** Function gatt_client_handle_server_rsp +** +** Description This function is called to handle the server response to +** client. +** +** +** Returns void +** +*******************************************************************************/ +void gatt_client_handle_server_rsp (tGATT_TCB *p_tcb, UINT8 op_code, + UINT16 len, UINT8 *p_data) +{ + tGATT_CLCB *p_clcb = NULL; + UINT8 rsp_code; + + if (op_code != GATT_HANDLE_VALUE_IND && op_code != GATT_HANDLE_VALUE_NOTIF) + { + p_clcb = gatt_cmd_dequeue(p_tcb, &rsp_code); + + rsp_code = gatt_cmd_to_rsp_code(rsp_code); + + if (p_clcb == NULL || (rsp_code != op_code && op_code != GATT_RSP_ERROR)) + { + GATT_TRACE_WARNING ("ATT - Ignore wrong response. Receives (%02x) \ + Request(%02x) Ignored", op_code, rsp_code); + + return; + } + else + { + btu_stop_timer (&p_clcb->rsp_timer_ent); + p_clcb->retry_count = 0; + } + } + /* the size of the message may not be bigger than the local max PDU size*/ + /* The message has to be smaller than the agreed MTU, len does not count op_code */ + if (len >= p_tcb->payload_size) + { + GATT_TRACE_ERROR("invalid response/indicate pkt size: %d, PDU size: %d", len + 1, p_tcb->payload_size); + if (op_code != GATT_HANDLE_VALUE_NOTIF && + op_code != GATT_HANDLE_VALUE_IND) + gatt_end_operation(p_clcb, GATT_ERROR, NULL); + } + else + { + switch (op_code) + { + case GATT_RSP_ERROR: + gatt_process_error_rsp(p_tcb, p_clcb, op_code, len, p_data); + break; + + case GATT_RSP_MTU: /* 2 bytes mtu */ + gatt_process_mtu_rsp(p_tcb, p_clcb, len ,p_data); + break; + + case GATT_RSP_FIND_INFO: + gatt_process_read_info_rsp(p_tcb, p_clcb, op_code, len, p_data); + break; + + case GATT_RSP_READ_BY_TYPE: + case GATT_RSP_READ_BY_GRP_TYPE: + gatt_process_read_by_type_rsp(p_tcb, p_clcb, op_code, len, p_data); + break; + + case GATT_RSP_READ: + case GATT_RSP_READ_BLOB: + case GATT_RSP_READ_MULTI: + gatt_process_read_rsp(p_tcb, p_clcb, op_code, len, p_data); + break; + + case GATT_RSP_FIND_TYPE_VALUE: /* disc service with UUID */ + gatt_process_find_type_value_rsp(p_tcb, p_clcb, len, p_data); + break; + + case GATT_RSP_WRITE: + gatt_process_handle_rsp(p_clcb); + break; + + case GATT_RSP_PREPARE_WRITE: + gatt_process_prep_write_rsp(p_tcb, p_clcb, op_code, len, p_data); + break; + + case GATT_RSP_EXEC_WRITE: + gatt_end_operation(p_clcb, p_clcb->status, NULL); + break; + + case GATT_HANDLE_VALUE_NOTIF: + case GATT_HANDLE_VALUE_IND: + gatt_process_notification(p_tcb, op_code, len, p_data); + break; + + default: + GATT_TRACE_ERROR("Unknown opcode = %d", op_code); + break; + } + } + + if (op_code != GATT_HANDLE_VALUE_IND && op_code != GATT_HANDLE_VALUE_NOTIF) + { + gatt_cl_send_next_cmd_inq(p_tcb); + } + + return; +} + +#endif /* BLE_INCLUDED */ diff --git a/components/bt/bluedroid/stack/gatt/gatt_db.c b/components/bt/bluedroid/stack/gatt/gatt_db.c new file mode 100755 index 0000000000..0efee48985 --- /dev/null +++ b/components/bt/bluedroid/stack/gatt/gatt_db.c @@ -0,0 +1,1222 @@ +/****************************************************************************** + * + * Copyright (C) 2009-2012 Broadcom Corporation + * + * 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 GATT database building and query functions + * + ******************************************************************************/ + +#include "bt_target.h" + +#if BLE_INCLUDED == TRUE + +#include "bt_trace.h" +//#include "bt_utils.h" + +//#include +#include +#include "gatt_int.h" +#include "l2c_api.h" +#include "btm_int.h" + +/******************************************************************************** +** L O C A L F U N C T I O N P R O T O T Y P E S * +*********************************************************************************/ +static BOOLEAN allocate_svc_db_buf(tGATT_SVC_DB *p_db); +static void *allocate_attr_in_db(tGATT_SVC_DB *p_db, tBT_UUID *p_uuid, tGATT_PERM perm); +static BOOLEAN deallocate_attr_in_db(tGATT_SVC_DB *p_db, void *p_attr); +static BOOLEAN copy_extra_byte_in_db(tGATT_SVC_DB *p_db, void **p_dst, UINT16 len); + +static BOOLEAN gatts_db_add_service_declaration(tGATT_SVC_DB *p_db, tBT_UUID *p_service, BOOLEAN is_pri); +static tGATT_STATUS gatts_send_app_read_request(tGATT_TCB *p_tcb, UINT8 op_code, + UINT16 handle, UINT16 offset, UINT32 trans_id); + +/******************************************************************************* +** +** Function gatts_init_service_db +** +** Description This function initialize a memory space to be a service database. +** +** Parameter p_db: database pointer. +** len: size of the memory space. +** +** Returns Status of te operation. +** +*******************************************************************************/ +BOOLEAN gatts_init_service_db (tGATT_SVC_DB *p_db, tBT_UUID *p_service, BOOLEAN is_pri, + UINT16 s_hdl, UINT16 num_handle) +{ + GKI_init_q(&p_db->svc_buffer); + + if (!allocate_svc_db_buf(p_db)) + { + GATT_TRACE_ERROR("gatts_init_service_db failed, no resources"); + return FALSE; + } + + GATT_TRACE_DEBUG("gatts_init_service_db"); + GATT_TRACE_DEBUG("s_hdl = %d num_handle = %d", s_hdl, num_handle ); + + /* update service database information */ + p_db->next_handle = s_hdl; + p_db->end_handle = s_hdl + num_handle; + + return gatts_db_add_service_declaration(p_db, p_service, is_pri); +} + +/******************************************************************************* +** +** Function gatts_init_service_db +** +** Description This function initialize a memory space to be a service database. +** +** Parameter p_db: database pointer. +** len: size of the memory space. +** +** Returns Status of te operation. +** +*******************************************************************************/ +tBT_UUID * gatts_get_service_uuid (tGATT_SVC_DB *p_db) +{ + if (!p_db || !p_db->p_attr_list) + { + GATT_TRACE_ERROR("service DB empty"); + + return NULL; + } + else + { + return &((tGATT_ATTR16 *)p_db->p_attr_list)->p_value->uuid; + } +} + +/******************************************************************************* +** +** Function gatts_check_attr_readability +** +** Description check attribute readability +** +** Returns status of operation. +** +*******************************************************************************/ +static tGATT_STATUS gatts_check_attr_readability(tGATT_ATTR16 *p_attr, + UINT16 offset, + BOOLEAN read_long, + tGATT_SEC_FLAG sec_flag, + UINT8 key_size) +{ + UINT16 min_key_size; + tGATT_PERM perm = p_attr->permission; + + UNUSED(offset); + min_key_size = (((perm & GATT_ENCRYPT_KEY_SIZE_MASK) >> 12)); + if (min_key_size != 0 ) + { + min_key_size +=6; + } + + if (!(perm & GATT_READ_ALLOWED)) + { + GATT_TRACE_ERROR( "GATT_READ_NOT_PERMIT"); + return GATT_READ_NOT_PERMIT; + } + + if ((perm & GATT_READ_AUTH_REQUIRED ) && !(sec_flag & GATT_SEC_FLAG_LKEY_UNAUTHED) && + !(sec_flag & BTM_SEC_FLAG_ENCRYPTED)) + { + GATT_TRACE_ERROR( "GATT_INSUF_AUTHENTICATION"); + return GATT_INSUF_AUTHENTICATION; + } + + if ((perm & GATT_READ_MITM_REQUIRED ) && !(sec_flag & GATT_SEC_FLAG_LKEY_AUTHED)) + { + GATT_TRACE_ERROR( "GATT_INSUF_AUTHENTICATION: MITM Required"); + return GATT_INSUF_AUTHENTICATION; + } + + if ((perm & GATT_READ_ENCRYPTED_REQUIRED ) && !(sec_flag & GATT_SEC_FLAG_ENCRYPTED)) + { + GATT_TRACE_ERROR( "GATT_INSUF_ENCRYPTION"); + return GATT_INSUF_ENCRYPTION; + } + + if ( (perm & GATT_READ_ENCRYPTED_REQUIRED) && (sec_flag & GATT_SEC_FLAG_ENCRYPTED) && (key_size < min_key_size)) + { + GATT_TRACE_ERROR( "GATT_INSUF_KEY_SIZE"); + return GATT_INSUF_KEY_SIZE; + } + + + if (read_long) + { + switch (p_attr->uuid) + { + case GATT_UUID_PRI_SERVICE: + case GATT_UUID_SEC_SERVICE: + case GATT_UUID_CHAR_DECLARE: + case GATT_UUID_INCLUDE_SERVICE: + case GATT_UUID_CHAR_EXT_PROP: + case GATT_UUID_CHAR_CLIENT_CONFIG: + case GATT_UUID_CHAR_SRVR_CONFIG: + case GATT_UUID_CHAR_PRESENT_FORMAT: + GATT_TRACE_ERROR("GATT_NOT_LONG"); + return GATT_NOT_LONG; + + default: + break; + } + } + + return GATT_SUCCESS; +} + +/******************************************************************************* +** +** Function read_attr_value +** +** Description Utility function to read an attribute value. +** +** Parameter p_attr: pointer to the attribute to read. +** offset: read offset. +** p_value: output parameter to carry out the attribute value. +** p_len: output parameter to carry out the attribute length. +** read_long: this is a read blob request. +** mtu: MTU +** sec_flag: current link security status. +** key_size: encryption key size. +** +** Returns status of operation. +** +*******************************************************************************/ +static tGATT_STATUS read_attr_value (void *p_attr, + UINT16 offset, + UINT8 **p_data, + BOOLEAN read_long, + UINT16 mtu, + UINT16 *p_len, + tGATT_SEC_FLAG sec_flag, + UINT8 key_size) +{ + UINT16 len = 0, uuid16 = 0; + UINT8 *p = *p_data; + tGATT_STATUS status; + tGATT_ATTR16 *p_attr16 = (tGATT_ATTR16 *)p_attr; + + GATT_TRACE_DEBUG("read_attr_value uuid=0x%04x perm=0x%0x sec_flag=0x%x offset=%d read_long=%d", + p_attr16->uuid, + p_attr16->permission, + sec_flag, + offset, + read_long); + + status = gatts_check_attr_readability((tGATT_ATTR16 *)p_attr, offset, read_long, sec_flag, key_size); + + if (status != GATT_SUCCESS) + return status; + + if (p_attr16->uuid_type == GATT_ATTR_UUID_TYPE_16) + uuid16 = p_attr16->uuid; + + status = GATT_NO_RESOURCES; + + if (uuid16 == GATT_UUID_PRI_SERVICE || uuid16 == GATT_UUID_SEC_SERVICE) + { + len = p_attr16->p_value->uuid.len; + if (mtu >= p_attr16->p_value->uuid.len) + { + gatt_build_uuid_to_stream(&p, p_attr16->p_value->uuid); + status = GATT_SUCCESS; + } + } + else if (uuid16 == GATT_UUID_CHAR_DECLARE) + { + len = (((tGATT_ATTR16 *)(p_attr16->p_next))->uuid_type == GATT_ATTR_UUID_TYPE_16) ? 5 :19; + + if (mtu >= len) + { + UINT8_TO_STREAM(p, p_attr16->p_value->char_decl.property); + UINT16_TO_STREAM(p, p_attr16->p_value->char_decl.char_val_handle); + + if (((tGATT_ATTR16 *)(p_attr16->p_next))->uuid_type == GATT_ATTR_UUID_TYPE_16) + { + UINT16_TO_STREAM(p, ((tGATT_ATTR16 *)(p_attr16->p_next))->uuid); + } + /* convert a 32bits UUID to 128 bits */ + else if (((tGATT_ATTR32 *)(p_attr16->p_next))->uuid_type == GATT_ATTR_UUID_TYPE_32) + { + gatt_convert_uuid32_to_uuid128 (p, ((tGATT_ATTR32 *)(p_attr16->p_next))->uuid); + p += LEN_UUID_128; + } + else + { + ARRAY_TO_STREAM (p, ((tGATT_ATTR128 *)(p_attr16->p_next))->uuid, LEN_UUID_128); + } + status = GATT_SUCCESS; + } + + } + else if (uuid16 == GATT_UUID_INCLUDE_SERVICE) + { + if (p_attr16->p_value->incl_handle.service_type.len == LEN_UUID_16) + len = 6; + else + len = 4; + + if (mtu >= len) + { + UINT16_TO_STREAM(p, p_attr16->p_value->incl_handle.s_handle); + UINT16_TO_STREAM(p, p_attr16->p_value->incl_handle.e_handle); + + if (p_attr16->p_value->incl_handle.service_type.len == LEN_UUID_16) + { + UINT16_TO_STREAM(p, p_attr16->p_value->incl_handle.service_type.uu.uuid16); + } + status = GATT_SUCCESS; + } + } + else /* characteristic description or characteristic value */ + { + status = GATT_PENDING; + } + + *p_len = len; + *p_data = p; + return status; +} + +/******************************************************************************* +** +** Function gatts_db_read_attr_value_by_type +** +** Description Query attribute value by attribute type. +** +** Parameter p_db: pointer to the attribute database. +** p_rsp: Read By type response data. +** s_handle: starting handle of the range we are looking for. +** e_handle: ending handle of the range we are looking for. +** type: Attribute type. +** mtu: MTU. +** sec_flag: current link security status. +** key_size: encryption key size. +** +** Returns Status of the operation. +** +*******************************************************************************/ +tGATT_STATUS gatts_db_read_attr_value_by_type (tGATT_TCB *p_tcb, + tGATT_SVC_DB *p_db, + UINT8 op_code, + BT_HDR *p_rsp, + UINT16 s_handle, + UINT16 e_handle, + tBT_UUID type, + UINT16 *p_len, + tGATT_SEC_FLAG sec_flag, + UINT8 key_size, + UINT32 trans_id, + UINT16 *p_cur_handle) +{ + tGATT_STATUS status = GATT_NOT_FOUND; + tGATT_ATTR16 *p_attr; + UINT16 len = 0; + UINT8 *p = (UINT8 *)(p_rsp + 1) + p_rsp->len + L2CAP_MIN_OFFSET; + tBT_UUID attr_uuid; +#if (defined(BLE_DELAY_REQUEST_ENC) && (BLE_DELAY_REQUEST_ENC == TRUE)) + UINT8 flag; +#endif + + if (p_db && p_db->p_attr_list) + { + p_attr = (tGATT_ATTR16 *)p_db->p_attr_list; + + while (p_attr && p_attr->handle <= e_handle) + { + if (p_attr->uuid_type == GATT_ATTR_UUID_TYPE_16) + { + attr_uuid.len = LEN_UUID_16; + attr_uuid.uu.uuid16 = p_attr->uuid; + } + else if (p_attr->uuid_type == GATT_ATTR_UUID_TYPE_32) + { + attr_uuid.len = LEN_UUID_32; + attr_uuid.uu.uuid32 = ((tGATT_ATTR32 *)p_attr)->uuid; + } + else + { + attr_uuid.len = LEN_UUID_128; + memcpy(attr_uuid.uu.uuid128, ((tGATT_ATTR128 *)p_attr)->uuid, LEN_UUID_128); + } + + if (p_attr->handle >= s_handle && gatt_uuid_compare(type, attr_uuid)) + { + if (*p_len <= 2) + { + status = GATT_NO_RESOURCES; + break; + } + + UINT16_TO_STREAM (p, p_attr->handle); + + status = read_attr_value ((void *)p_attr, 0, &p, FALSE, (UINT16)(*p_len -2), &len, sec_flag, key_size); + + if (status == GATT_PENDING) + { + status = gatts_send_app_read_request(p_tcb, op_code, p_attr->handle, 0, trans_id); + + /* one callback at a time */ + break; + } + else if (status == GATT_SUCCESS) + { + if (p_rsp->offset == 0) + p_rsp->offset = len + 2; + + if (p_rsp->offset == len + 2) + { + p_rsp->len += (len + 2); + *p_len -= (len + 2); + } + else + { + GATT_TRACE_ERROR("format mismatch"); + status = GATT_NO_RESOURCES; + break; + } + } + else + { + *p_cur_handle = p_attr->handle; + break; + } + } + p_attr = (tGATT_ATTR16 *)p_attr->p_next; + } + } + +#if (defined(BLE_DELAY_REQUEST_ENC) && (BLE_DELAY_REQUEST_ENC == TRUE)) + if (BTM_GetSecurityFlags(p_tcb->peer_bda, &flag)) + { + if ((p_tcb->att_lcid == L2CAP_ATT_CID) && (status == GATT_PENDING) && + (type.uu.uuid16 == GATT_UUID_GAP_DEVICE_NAME)) + { + if ((flag & (BTM_SEC_LINK_KEY_KNOWN | BTM_SEC_FLAG_ENCRYPTED)) == + BTM_SEC_LINK_KEY_KNOWN) + { + tACL_CONN *p; + p = btm_bda_to_acl(p_tcb->peer_bda, BT_TRANSPORT_LE); + if ((p != NULL) && (p->link_role == BTM_ROLE_MASTER)) + { + tBTM_BLE_SEC_ACT sec_act = BTM_BLE_SEC_ENCRYPT; + btm_ble_set_encryption(p_tcb->peer_bda, &sec_act, p->link_role); + } + } + } + } +#endif + return status; +} + +/******************************************************************************* +** +** Function gatts_add_included_service +** +** Description This function adds an included service into a database. +** +** Parameter p_db: database pointer. +** inc_srvc_type: included service type. +** +** Returns Status of the operation. +** +*******************************************************************************/ +UINT16 gatts_add_included_service (tGATT_SVC_DB *p_db, UINT16 s_handle, UINT16 e_handle, + tBT_UUID service) +{ + tGATT_ATTR16 *p_attr; + tBT_UUID uuid = {LEN_UUID_16, {GATT_UUID_INCLUDE_SERVICE}}; + + GATT_TRACE_DEBUG("gatts_add_included_service: s_hdl = 0x%04x e_hdl = 0x%04x uuid = 0x%04x", + s_handle, e_handle, service.uu.uuid16); + + if (service.len == 0 || s_handle == 0 || e_handle == 0) + { + GATT_TRACE_ERROR("gatts_add_included_service Illegal Params."); + return 0; + } + + if ((p_attr = (tGATT_ATTR16 *) allocate_attr_in_db(p_db, &uuid, GATT_PERM_READ)) != NULL) + { + if (copy_extra_byte_in_db(p_db, (void **)&p_attr->p_value, sizeof(tGATT_INCL_SRVC))) + { + p_attr->p_value->incl_handle.s_handle = s_handle; + p_attr->p_value->incl_handle.e_handle = e_handle; + memcpy(&p_attr->p_value->incl_handle.service_type, &service, sizeof(tBT_UUID)); + + return p_attr->handle; + } + else + { + deallocate_attr_in_db(p_db, p_attr); + } + } + + return 0; +} + +/******************************************************************************* +** +** Function gatts_add_characteristic +** +** Description This function add a characteristics and its descriptor into +** a servce identified by the service database pointer. +** +** Parameter p_db: database pointer. +** perm: permission (authentication and key size requirements) +** property: property of the characteristic. +** p_char: characteristic value information. +** +** Returns Status of te operation. +** +*******************************************************************************/ +UINT16 gatts_add_characteristic (tGATT_SVC_DB *p_db, tGATT_PERM perm, + tGATT_CHAR_PROP property, + tBT_UUID * p_char_uuid) +{ + tGATT_ATTR16 *p_char_decl, *p_char_val; + tBT_UUID uuid = {LEN_UUID_16, {GATT_UUID_CHAR_DECLARE}}; + + GATT_TRACE_DEBUG("gatts_add_characteristic perm=0x%0x property=0x%0x", perm, property); + + if ((p_char_decl = (tGATT_ATTR16 *)allocate_attr_in_db(p_db, &uuid, GATT_PERM_READ)) != NULL) + { + if (!copy_extra_byte_in_db(p_db, (void **)&p_char_decl->p_value, sizeof(tGATT_CHAR_DECL))) + { + deallocate_attr_in_db(p_db, p_char_decl); + return 0; + } + + p_char_val = (tGATT_ATTR16 *)allocate_attr_in_db(p_db, p_char_uuid, perm); + + if (p_char_val == NULL) + { + deallocate_attr_in_db(p_db, p_char_decl); + return 0; + } + + p_char_decl->p_value->char_decl.property = property; + p_char_decl->p_value->char_decl.char_val_handle = p_char_val->handle; + + p_char_val->p_value = NULL; + + return p_char_val->handle; + } + + return 0; +} + +/******************************************************************************* +** +** Function gatt_convertchar_descr_type +** +** Description This function convert a char descript UUID into descriptor type. +** +** Returns descriptor type. +** +*******************************************************************************/ +UINT8 gatt_convertchar_descr_type(tBT_UUID *p_descr_uuid) +{ + tBT_UUID std_descr = {LEN_UUID_16, {GATT_UUID_CHAR_EXT_PROP}}; + + if (gatt_uuid_compare(std_descr, * p_descr_uuid)) + return GATT_DESCR_EXT_DSCPTOR; + + std_descr.uu.uuid16 ++; + if (gatt_uuid_compare(std_descr, * p_descr_uuid)) + return GATT_DESCR_USER_DSCPTOR; + + std_descr.uu.uuid16 ++; + if (gatt_uuid_compare(std_descr, * p_descr_uuid)) + return GATT_DESCR_CLT_CONFIG; + + std_descr.uu.uuid16 ++; + if (gatt_uuid_compare(std_descr, * p_descr_uuid)) + return GATT_DESCR_SVR_CONFIG; + + std_descr.uu.uuid16 ++; + if (gatt_uuid_compare(std_descr, * p_descr_uuid)) + return GATT_DESCR_PRES_FORMAT; + + std_descr.uu.uuid16 ++; + if (gatt_uuid_compare(std_descr, * p_descr_uuid)) + return GATT_DESCR_AGGR_FORMAT; + + std_descr.uu.uuid16 ++; + if (gatt_uuid_compare(std_descr, * p_descr_uuid)) + return GATT_DESCR_VALID_RANGE; + + + return GATT_DESCR_UNKNOWN; +} + +/******************************************************************************* +** +** Function gatts_add_char_descr +** +** Description This function add a characteristics descriptor. +** +** Parameter p_db: database pointer. +** perm: characteristic descriptor permission type. +** char_dscp_tpye: the characteristic descriptor masks. +** p_dscp_params: characteristic descriptors values. +** +** Returns Status of the operation. +** +*******************************************************************************/ +UINT16 gatts_add_char_descr (tGATT_SVC_DB *p_db, tGATT_PERM perm, + tBT_UUID * p_descr_uuid) +{ + tGATT_ATTR16 *p_char_dscptr; + + GATT_TRACE_DEBUG("gatts_add_char_descr uuid=0x%04x", p_descr_uuid->uu.uuid16); + + /* Add characteristic descriptors */ + if ((p_char_dscptr = (tGATT_ATTR16 *)allocate_attr_in_db(p_db, + p_descr_uuid, + perm)) + == NULL) + { + GATT_TRACE_DEBUG("gatts_add_char_descr Fail for adding char descriptors."); + return 0; + } + else + { + return p_char_dscptr->handle; + } +} + +/*******************************************************************************/ +/* Service Attribute Database Query Utility Functions */ +/*******************************************************************************/ +/******************************************************************************* +** +** Function gatts_read_attr_value_by_handle +** +** Description Query attribute value by attribute handle. +** +** Parameter p_db: pointer to the attribute database. +** handle: Attribute handle to read. +** offset: Read offset. +** p_value: output parameter to carry out the attribute value. +** p_len: output parameter as attribute length read. +** read_long: this is a read blob request. +** mtu: MTU. +** sec_flag: current link security status. +** key_size: encryption key size +** +** Returns Status of operation. +** +*******************************************************************************/ +tGATT_STATUS gatts_read_attr_value_by_handle(tGATT_TCB *p_tcb, + tGATT_SVC_DB *p_db, + UINT8 op_code, + UINT16 handle, UINT16 offset, + UINT8 *p_value, UINT16 *p_len, + UINT16 mtu, + tGATT_SEC_FLAG sec_flag, + UINT8 key_size, + UINT32 trans_id) +{ + tGATT_STATUS status = GATT_NOT_FOUND; + tGATT_ATTR16 *p_attr; + UINT8 *pp = p_value; + + if (p_db && p_db->p_attr_list) + { + p_attr = (tGATT_ATTR16 *)p_db->p_attr_list; + + while (p_attr && handle >= p_attr->handle) + { + if (p_attr->handle == handle) + { + status = read_attr_value (p_attr, offset, &pp, + (BOOLEAN)(op_code == GATT_REQ_READ_BLOB), + mtu, p_len, sec_flag, key_size); + + if (status == GATT_PENDING) + { + status = gatts_send_app_read_request(p_tcb, op_code, p_attr->handle, offset, trans_id); + } + break; + } + p_attr = (tGATT_ATTR16 *)p_attr->p_next; + } + } + + return status; +} + +/******************************************************************************* +** +** Function gatts_read_attr_perm_check +** +** Description Check attribute readability. +** +** Parameter p_db: pointer to the attribute database. +** handle: Attribute handle to read. +** offset: Read offset. +** p_value: output parameter to carry out the attribute value. +** p_len: output parameter as attribute length read. +** read_long: this is a read blob request. +** mtu: MTU. +** sec_flag: current link security status. +** key_size: encryption key size +** +** Returns Status of operation. +** +*******************************************************************************/ +tGATT_STATUS gatts_read_attr_perm_check(tGATT_SVC_DB *p_db, + BOOLEAN is_long, + UINT16 handle, + tGATT_SEC_FLAG sec_flag, + UINT8 key_size) +{ + tGATT_STATUS status = GATT_NOT_FOUND; + tGATT_ATTR16 *p_attr; + + if (p_db && p_db->p_attr_list) + { + p_attr = (tGATT_ATTR16 *)p_db->p_attr_list; + + while (p_attr && handle >= p_attr->handle) + { + if (p_attr->handle == handle) + { + status = gatts_check_attr_readability (p_attr, 0, + is_long, + sec_flag, key_size); + break; + } + p_attr = (tGATT_ATTR16 *) p_attr->p_next; + } + } + + return status; +} +/******************************************************************************* +** +** Function gatts_write_attr_perm_check +** +** Description Write attribute value into database. +** +** Parameter p_db: pointer to the attribute database. +** op_code:op code of this write. +** handle: handle of the attribute to write. +** offset: Write offset if write op code is write blob. +** p_data: Attribute value to write. +** len: attribute data length. +** sec_flag: current link security status. +** key_size: encryption key size +** +** Returns Status of the operation. +** +*******************************************************************************/ +tGATT_STATUS gatts_write_attr_perm_check (tGATT_SVC_DB *p_db, UINT8 op_code, + UINT16 handle, UINT16 offset, UINT8 *p_data, + UINT16 len, tGATT_SEC_FLAG sec_flag, UINT8 key_size) +{ + tGATT_STATUS status = GATT_NOT_FOUND; + tGATT_ATTR16 *p_attr; + UINT16 max_size = 0; + tGATT_PERM perm; + UINT16 min_key_size; + + GATT_TRACE_DEBUG( "gatts_write_attr_perm_check op_code=0x%0x handle=0x%04x offset=%d len=%d sec_flag=0x%0x key_size=%d", + op_code, handle, offset, len, sec_flag, key_size); + + if (p_db != NULL) + { + p_attr = (tGATT_ATTR16 *) p_db->p_attr_list; + + while (p_attr != NULL) + { + if (p_attr->handle == handle) + { + perm = p_attr->permission; + min_key_size = (((perm & GATT_ENCRYPT_KEY_SIZE_MASK) >> 12)); + if (min_key_size != 0 ) + { + min_key_size +=6; + } + GATT_TRACE_DEBUG( "gatts_write_attr_perm_check p_attr->permission =0x%04x min_key_size==0x%04x", + p_attr->permission, + min_key_size); + + if ((op_code == GATT_CMD_WRITE || op_code == GATT_REQ_WRITE) + && (perm & GATT_WRITE_SIGNED_PERM)) + { + /* use the rules for the mixed security see section 10.2.3*/ + /* use security mode 1 level 2 when the following condition follows */ + /* LE security mode 2 level 1 and LE security mode 1 level 2 */ + if ((perm & GATT_PERM_WRITE_SIGNED) && (perm & GATT_PERM_WRITE_ENCRYPTED)) + { + perm = GATT_PERM_WRITE_ENCRYPTED; + } + /* use security mode 1 level 3 when the following condition follows */ + /* LE security mode 2 level 2 and security mode 1 and LE */ + else if (((perm & GATT_PERM_WRITE_SIGNED_MITM) && (perm & GATT_PERM_WRITE_ENCRYPTED)) || + /* LE security mode 2 and security mode 1 level 3 */ + ((perm & GATT_WRITE_SIGNED_PERM) && (perm & GATT_PERM_WRITE_ENC_MITM))) + { + perm = GATT_PERM_WRITE_ENC_MITM; + } + } + + if ((op_code == GATT_SIGN_CMD_WRITE) && !(perm & GATT_WRITE_SIGNED_PERM)) + { + status = GATT_WRITE_NOT_PERMIT; + GATT_TRACE_DEBUG( "gatts_write_attr_perm_check - sign cmd write not allowed"); + } + if ((op_code == GATT_SIGN_CMD_WRITE) && (sec_flag & GATT_SEC_FLAG_ENCRYPTED)) + { + status = GATT_INVALID_PDU; + GATT_TRACE_ERROR( "gatts_write_attr_perm_check - Error!! sign cmd write sent on a encypted link"); + } + else if (!(perm & GATT_WRITE_ALLOWED)) + { + status = GATT_WRITE_NOT_PERMIT; + GATT_TRACE_ERROR( "gatts_write_attr_perm_check - GATT_WRITE_NOT_PERMIT"); + } + /* require authentication, but not been authenticated */ + else if ((perm & GATT_WRITE_AUTH_REQUIRED ) && !(sec_flag & GATT_SEC_FLAG_LKEY_UNAUTHED)) + { + status = GATT_INSUF_AUTHENTICATION; + GATT_TRACE_ERROR( "gatts_write_attr_perm_check - GATT_INSUF_AUTHENTICATION"); + } + else if ((perm & GATT_WRITE_MITM_REQUIRED ) && !(sec_flag & GATT_SEC_FLAG_LKEY_AUTHED)) + { + status = GATT_INSUF_AUTHENTICATION; + GATT_TRACE_ERROR( "gatts_write_attr_perm_check - GATT_INSUF_AUTHENTICATION: MITM required"); + } + else if ((perm & GATT_WRITE_ENCRYPTED_PERM ) && !(sec_flag & GATT_SEC_FLAG_ENCRYPTED)) + { + status = GATT_INSUF_ENCRYPTION; + GATT_TRACE_ERROR( "gatts_write_attr_perm_check - GATT_INSUF_ENCRYPTION"); + } + else if ((perm & GATT_WRITE_ENCRYPTED_PERM ) && (sec_flag & GATT_SEC_FLAG_ENCRYPTED) && (key_size < min_key_size)) + { + status = GATT_INSUF_KEY_SIZE; + GATT_TRACE_ERROR( "gatts_write_attr_perm_check - GATT_INSUF_KEY_SIZE"); + } + /* LE security mode 2 attribute */ + else if (perm & GATT_WRITE_SIGNED_PERM && op_code != GATT_SIGN_CMD_WRITE && !(sec_flag & GATT_SEC_FLAG_ENCRYPTED) + && (perm & GATT_WRITE_ALLOWED) == 0) + { + status = GATT_INSUF_AUTHENTICATION; + GATT_TRACE_ERROR( "gatts_write_attr_perm_check - GATT_INSUF_AUTHENTICATION: LE security mode 2 required"); + } + else /* writable: must be char value declaration or char descritpors */ + { + if(p_attr->uuid_type == GATT_ATTR_UUID_TYPE_16) + { + switch (p_attr->uuid) + { + case GATT_UUID_CHAR_PRESENT_FORMAT:/* should be readable only */ + case GATT_UUID_CHAR_EXT_PROP:/* should be readable only */ + case GATT_UUID_CHAR_AGG_FORMAT: /* should be readable only */ + case GATT_UUID_CHAR_VALID_RANGE: + status = GATT_WRITE_NOT_PERMIT; + break; + + case GATT_UUID_CHAR_CLIENT_CONFIG: +/* coverity[MISSING_BREAK] */ +/* intnended fall through, ignored */ + /* fall through */ + case GATT_UUID_CHAR_SRVR_CONFIG: + max_size = 2; + case GATT_UUID_CHAR_DESCRIPTION: + default: /* any other must be character value declaration */ + status = GATT_SUCCESS; + break; + } + } + else if (p_attr->uuid_type == GATT_ATTR_UUID_TYPE_128 || + p_attr->uuid_type == GATT_ATTR_UUID_TYPE_32) + { + status = GATT_SUCCESS; + } + else + { + status = GATT_INVALID_PDU; + } + + if (p_data == NULL && len > 0) + { + status = GATT_INVALID_PDU; + } + /* these attribute does not allow write blob */ +// btla-specific ++ + else if ( (p_attr->uuid_type == GATT_ATTR_UUID_TYPE_16) && + (p_attr->uuid == GATT_UUID_CHAR_CLIENT_CONFIG || + p_attr->uuid == GATT_UUID_CHAR_SRVR_CONFIG) ) +// btla-specific -- + { + if (op_code == GATT_REQ_PREPARE_WRITE && offset != 0) /* does not allow write blob */ + { + status = GATT_NOT_LONG; + GATT_TRACE_ERROR( "gatts_write_attr_perm_check - GATT_NOT_LONG"); + } + else if (len != max_size) /* data does not match the required format */ + { + status = GATT_INVALID_ATTR_LEN; + GATT_TRACE_ERROR( "gatts_write_attr_perm_check - GATT_INVALID_PDU"); + } + else + { + status = GATT_SUCCESS; + } + } + } + break; + } + else + p_attr = (tGATT_ATTR16 *)p_attr->p_next; + } + } + + return status; +} + +/******************************************************************************* +** +** Function allocate_attr_in_db +** +** Description Allocate a memory space for a new attribute, and link this +** attribute into the database attribute list. +** +** +** Parameter p_db : database pointer. +** p_uuid: pointer to attribute UUID +** service : type of attribute to be added. +** +** Returns pointer to the newly allocated attribute. +** +*******************************************************************************/ +static void *allocate_attr_in_db(tGATT_SVC_DB *p_db, tBT_UUID *p_uuid, tGATT_PERM perm) +{ + tGATT_ATTR16 *p_attr16 = NULL, *p_last; + tGATT_ATTR32 *p_attr32 = NULL; + tGATT_ATTR128 *p_attr128 = NULL; + UINT16 len = sizeof(tGATT_ATTR128); + + if (p_uuid == NULL) + { + GATT_TRACE_ERROR("illegal UUID"); + return NULL; + } + + if (p_uuid->len == LEN_UUID_16) + len = sizeof(tGATT_ATTR16); + else if (p_uuid->len == LEN_UUID_32) + len = sizeof(tGATT_ATTR32); + + GATT_TRACE_DEBUG("allocate attr %d bytes ",len); + + if (p_db->end_handle <= p_db->next_handle) + { + GATT_TRACE_DEBUG("handle space full. handle_max = %d next_handle = %d", + p_db->end_handle, p_db->next_handle); + return NULL; + } + + if (p_db->mem_free < len) + { + if (!allocate_svc_db_buf(p_db)) + { + GATT_TRACE_ERROR("allocate_attr_in_db failed, no resources"); + return NULL; + } + } + memset(p_db->p_free_mem, 0, len); + p_attr16 = (tGATT_ATTR16 *) p_db->p_free_mem; + + if (p_uuid->len == LEN_UUID_16 && p_uuid->uu.uuid16 != GATT_ILLEGAL_UUID) + { + p_attr16->uuid_type = GATT_ATTR_UUID_TYPE_16; + p_attr16->uuid = p_uuid->uu.uuid16; + } + else if (p_uuid->len == LEN_UUID_32) + { + p_attr32 = (tGATT_ATTR32 *) p_db->p_free_mem; + p_attr32->uuid_type = GATT_ATTR_UUID_TYPE_32; + p_attr32->uuid = p_uuid->uu.uuid32; + } + else if (p_uuid->len == LEN_UUID_128) + { + p_attr128 = (tGATT_ATTR128 *) p_db->p_free_mem; + p_attr128->uuid_type = GATT_ATTR_UUID_TYPE_128; + memcpy(p_attr128->uuid, p_uuid->uu.uuid128, LEN_UUID_128); + } + + p_db->p_free_mem += len; + p_db->mem_free -= len; + + p_attr16->handle = p_db->next_handle++; + p_attr16->permission = perm; + p_attr16->p_next = NULL; + + /* link the attribute record into the end of DB */ + if (p_db->p_attr_list == NULL) + p_db->p_attr_list = p_attr16; + else + { + p_last = (tGATT_ATTR16 *)p_db->p_attr_list; + + while (p_last != NULL && p_last->p_next != NULL) + p_last = (tGATT_ATTR16 *)p_last->p_next; + + p_last->p_next = p_attr16; + } + + if (p_attr16->uuid_type == GATT_ATTR_UUID_TYPE_16) + { + GATT_TRACE_DEBUG("=====> handle = [0x%04x] uuid16 = [0x%04x] perm=0x%02x ", + p_attr16->handle, p_attr16->uuid, p_attr16->permission); + } + else if (p_attr16->uuid_type == GATT_ATTR_UUID_TYPE_32) + { + GATT_TRACE_DEBUG("=====> handle = [0x%04x] uuid32 = [0x%08x] perm=0x%02x ", + p_attr32->handle, p_attr32->uuid, p_attr32->permission); + } + else + { + GATT_TRACE_DEBUG("=====> handle = [0x%04x] uuid128 = [0x%02x:0x%02x] perm=0x%02x ", + p_attr128->handle, p_attr128->uuid[0],p_attr128->uuid[1], + p_attr128->permission); + } + return(void *)p_attr16; +} + +/******************************************************************************* +** +** Function deallocate_attr_in_db +** +** Description Free an attribute within the database. +** +** Parameter p_db: database pointer. +** p_attr: pointer to the attribute record to be freed. +** +** Returns BOOLEAN: success +** +*******************************************************************************/ +static BOOLEAN deallocate_attr_in_db(tGATT_SVC_DB *p_db, void *p_attr) +{ + tGATT_ATTR16 *p_cur, *p_next; + BOOLEAN found = FALSE; + + if (p_db->p_attr_list == NULL) + return found; + + p_cur = (tGATT_ATTR16 *) p_db->p_attr_list; + p_next = (tGATT_ATTR16 *) p_cur->p_next; + + for (; p_cur != NULL && p_next != NULL; + p_cur = p_next, p_next = (tGATT_ATTR16 *)p_next->p_next) + { + if (p_next == p_attr) + { + p_cur->p_next = p_next->p_next; + found = TRUE; + } + } + if (p_cur == p_attr && p_cur == p_db->p_attr_list) + { + p_db->p_attr_list = p_cur->p_next; + found = TRUE; + } + /* else attr not found */ + if ( found) + p_db->next_handle --; + + return found; +} + +/******************************************************************************* +** +** Function copy_extra_byte_in_db +** +** Description Utility function to allocate extra bytes memory in DB and copy +** the value from a source place. +** +** +** Parameter p_db: database pointer. +** p_dst: destination data pointer. +** p_src: source data pointer. +** len: data length to be copied. +** +** Returns None. +** +*******************************************************************************/ +static BOOLEAN copy_extra_byte_in_db(tGATT_SVC_DB *p_db, void **p_dst, UINT16 len) +{ + UINT8 *p = (UINT8 *)*p_dst; + + if (p_db->mem_free < len) + { + if (!allocate_svc_db_buf(p_db)) + { + GATT_TRACE_ERROR("copy_extra_byte_in_db failed, no resources"); + return FALSE; + } + } + + p = p_db->p_free_mem; + p_db->p_free_mem += len; + p_db->mem_free -= len; + memset((void *)p, 0, len); + *p_dst = (void *)p; + + return TRUE; +} + +/******************************************************************************* +** +** Function allocate_svc_db_buf +** +** Description Utility function to allocate extra buffer for service database. +** +** Returns TRUE if allocation succeed, otherwise FALSE. +** +*******************************************************************************/ +static BOOLEAN allocate_svc_db_buf(tGATT_SVC_DB *p_db) +{ + BT_HDR *p_buf; + + GATT_TRACE_DEBUG("allocate_svc_db_buf allocating extra buffer"); + + if ((p_buf = (BT_HDR *)GKI_getpoolbuf(GATT_DB_POOL_ID)) == NULL) + { + GATT_TRACE_ERROR("allocate_svc_db_buf failed, no resources"); + return FALSE; + } + + memset(p_buf, 0, GKI_get_buf_size(p_buf)); + p_db->p_free_mem = (UINT8 *) p_buf; + p_db->mem_free = GKI_get_buf_size(p_buf); + + GKI_enqueue(&p_db->svc_buffer, p_buf); + + return TRUE; + +} + +/******************************************************************************* +** +** Function gatts_send_app_read_request +** +** Description Send application read request callback +** +** Returns status of operation. +** +*******************************************************************************/ +static tGATT_STATUS gatts_send_app_read_request(tGATT_TCB *p_tcb, UINT8 op_code, + UINT16 handle, UINT16 offset, UINT32 trans_id) +{ + tGATTS_DATA sr_data; + UINT8 i_rcb; + tGATT_SR_REG *p_sreg; + UINT16 conn_id; + + i_rcb = gatt_sr_find_i_rcb_by_handle(handle); + p_sreg = &gatt_cb.sr_reg[i_rcb]; + conn_id = GATT_CREATE_CONN_ID(p_tcb->tcb_idx, p_sreg->gatt_if); + + if (trans_id == 0) + { + trans_id = gatt_sr_enqueue_cmd(p_tcb, op_code, handle); + gatt_sr_update_cback_cnt(p_tcb, p_sreg->gatt_if, TRUE, TRUE); + } + + if (trans_id != 0 ) + { + memset(&sr_data, 0, sizeof(tGATTS_DATA)); + + sr_data.read_req.handle = handle; + sr_data.read_req.is_long = (BOOLEAN)(op_code == GATT_REQ_READ_BLOB); + sr_data.read_req.offset = offset; + + gatt_sr_send_req_callback(conn_id, + trans_id, GATTS_REQ_TYPE_READ, &sr_data); + return(tGATT_STATUS) GATT_PENDING; + } + else + return(tGATT_STATUS) GATT_BUSY; /* max pending command, application error */ + +} + +/******************************************************************************* +** +** Function gatts_db_add_service_declaration +** +** Description Update a service database service declaration record. +** +** Parameter p_db: database pointer. +** service: UUID of the service. +** +** Returns void +** +*******************************************************************************/ +static BOOLEAN gatts_db_add_service_declaration(tGATT_SVC_DB *p_db, tBT_UUID *p_service, BOOLEAN is_pri) +{ + tGATT_ATTR16 *p_attr; + tBT_UUID uuid = {LEN_UUID_16, {0}}; + BOOLEAN rt = FALSE; + + GATT_TRACE_DEBUG( "add_service_declaration"); + + if (is_pri) + uuid.uu.uuid16 = GATT_UUID_PRI_SERVICE; + else + uuid.uu.uuid16 = GATT_UUID_SEC_SERVICE; + + /* add service declration record */ + if ((p_attr = (tGATT_ATTR16 *)(allocate_attr_in_db(p_db, &uuid, GATT_PERM_READ))) != NULL) + { + if (copy_extra_byte_in_db (p_db, (void **)&p_attr->p_value, sizeof(tBT_UUID))) + { + if (p_service->len == LEN_UUID_16) + { + p_attr->p_value->uuid.len = LEN_UUID_16; + p_attr->p_value->uuid.uu.uuid16 = p_service->uu.uuid16; + } + else if (p_service->len == LEN_UUID_32) + { + p_attr->p_value->uuid.len = LEN_UUID_128; + gatt_convert_uuid32_to_uuid128(p_attr->p_value->uuid.uu.uuid128, p_service->uu.uuid32); + } + else + { + p_attr->p_value->uuid.len = LEN_UUID_128; + memcpy(p_attr->p_value->uuid.uu.uuid128, p_service->uu.uuid128, LEN_UUID_128); + } + rt = TRUE; + } + + } + return rt; +} + +#endif /* BLE_INCLUDED */ diff --git a/components/bt/bluedroid/stack/gatt/gatt_main.c b/components/bt/bluedroid/stack/gatt/gatt_main.c new file mode 100755 index 0000000000..953b95037a --- /dev/null +++ b/components/bt/bluedroid/stack/gatt/gatt_main.c @@ -0,0 +1,1222 @@ +/****************************************************************************** + * + * Copyright (C) 2008-2012 Broadcom Corporation + * + * 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 main ATT functions + * + ******************************************************************************/ + +#include "bt_target.h" + +#if BLE_INCLUDED == TRUE + +#include "gki.h" +#include "gatt_int.h" +#include "l2c_api.h" +#include "btm_int.h" +#include "btm_ble_int.h" +//#include "bt_utils.h" + +/* Configuration flags. */ +#define GATT_L2C_CFG_IND_DONE (1<<0) +#define GATT_L2C_CFG_CFM_DONE (1<<1) + +/* minimum GATT MTU size over BR/EDR link +*/ +#define GATT_MIN_BR_MTU_SIZE 48 + +/********************************************************************************/ +/* L O C A L F U N C T I O N P R O T O T Y P E S */ +/********************************************************************************/ +static void gatt_le_connect_cback (UINT16 chan, BD_ADDR bd_addr, BOOLEAN connected, + UINT16 reason, tBT_TRANSPORT transport); +static void gatt_le_data_ind (UINT16 chan, BD_ADDR bd_addr, BT_HDR *p_buf); +static void gatt_le_cong_cback(BD_ADDR remote_bda, BOOLEAN congest); + +static void gatt_l2cif_connect_ind_cback (BD_ADDR bd_addr, UINT16 l2cap_cid, + UINT16 psm, UINT8 l2cap_id); +static void gatt_l2cif_connect_cfm_cback (UINT16 l2cap_cid, UINT16 result); +static void gatt_l2cif_config_ind_cback (UINT16 l2cap_cid, tL2CAP_CFG_INFO *p_cfg); +static void gatt_l2cif_config_cfm_cback (UINT16 l2cap_cid, tL2CAP_CFG_INFO *p_cfg); +static void gatt_l2cif_disconnect_ind_cback (UINT16 l2cap_cid, BOOLEAN ack_needed); +static void gatt_l2cif_disconnect_cfm_cback (UINT16 l2cap_cid, UINT16 result); +static void gatt_l2cif_data_ind_cback (UINT16 l2cap_cid, BT_HDR *p_msg); +static void gatt_send_conn_cback (tGATT_TCB *p_tcb); +static void gatt_l2cif_congest_cback (UINT16 cid, BOOLEAN congested); + +static const tL2CAP_APPL_INFO dyn_info = +{ + gatt_l2cif_connect_ind_cback, + gatt_l2cif_connect_cfm_cback, + NULL, + gatt_l2cif_config_ind_cback, + gatt_l2cif_config_cfm_cback, + gatt_l2cif_disconnect_ind_cback, + gatt_l2cif_disconnect_cfm_cback, + NULL, + gatt_l2cif_data_ind_cback, + gatt_l2cif_congest_cback, + NULL +} ; + +#if GATT_DYNAMIC_MEMORY == FALSE +tGATT_CB gatt_cb; +#endif + +/******************************************************************************* +** +** Function gatt_init +** +** Description This function is enable the GATT profile on the device. +** It clears out the control blocks, and registers with L2CAP. +** +** Returns void +** +*******************************************************************************/ +void gatt_init (void) +{ + tL2CAP_FIXED_CHNL_REG fixed_reg; + + GATT_TRACE_DEBUG("gatt_init()"); + + memset (&gatt_cb, 0, sizeof(tGATT_CB)); + memset (&fixed_reg, 0, sizeof(tL2CAP_FIXED_CHNL_REG)); + +#if defined(GATT_INITIAL_TRACE_LEVEL) + gatt_cb.trace_level = GATT_INITIAL_TRACE_LEVEL; +#else + gatt_cb.trace_level = BT_TRACE_LEVEL_NONE; /* No traces */ +#endif + gatt_cb.def_mtu_size = GATT_DEF_BLE_MTU_SIZE; + GKI_init_q (&gatt_cb.sign_op_queue); + GKI_init_q (&gatt_cb.srv_chg_clt_q); + GKI_init_q (&gatt_cb.pending_new_srv_start_q); + /* First, register fixed L2CAP channel for ATT over BLE */ + fixed_reg.fixed_chnl_opts.mode = L2CAP_FCR_BASIC_MODE; + fixed_reg.fixed_chnl_opts.max_transmit = 0xFF; + fixed_reg.fixed_chnl_opts.rtrans_tout = 2000; + fixed_reg.fixed_chnl_opts.mon_tout = 12000; + fixed_reg.fixed_chnl_opts.mps = 670; + fixed_reg.fixed_chnl_opts.tx_win_sz = 1; + + fixed_reg.pL2CA_FixedConn_Cb = gatt_le_connect_cback; + fixed_reg.pL2CA_FixedData_Cb = gatt_le_data_ind; + fixed_reg.pL2CA_FixedCong_Cb = gatt_le_cong_cback; /* congestion callback */ + fixed_reg.default_idle_tout = 0xffff; /* 0xffff default idle timeout */ + + L2CA_RegisterFixedChannel (L2CAP_ATT_CID, &fixed_reg); + + /* Now, register with L2CAP for ATT PSM over BR/EDR */ + if (!L2CA_Register (BT_PSM_ATT, (tL2CAP_APPL_INFO *) &dyn_info)) + { + GATT_TRACE_ERROR ("ATT Dynamic Registration failed"); + } + + BTM_SetSecurityLevel(TRUE, "", BTM_SEC_SERVICE_ATT, BTM_SEC_NONE, BT_PSM_ATT, 0, 0); + BTM_SetSecurityLevel(FALSE, "", BTM_SEC_SERVICE_ATT, BTM_SEC_NONE, BT_PSM_ATT, 0, 0); + + gatt_cb.hdl_cfg.gatt_start_hdl = GATT_GATT_START_HANDLE; + gatt_cb.hdl_cfg.gap_start_hdl = GATT_GAP_START_HANDLE; + gatt_cb.hdl_cfg.app_start_hdl = GATT_APP_START_HANDLE; + gatt_profile_db_init(); + +} + + +/******************************************************************************* +** +** Function gatt_free +** +** Description This function frees resources used by the GATT profile. +** +** Returns void +** +*******************************************************************************/ +void gatt_free(void) +{ + int i; + GATT_TRACE_DEBUG("gatt_free()"); + for (i = 0; i < GATT_MAX_SR_PROFILES; i++) + { + gatt_free_hdl_buffer(&gatt_cb.hdl_list[i]); + } +} + +/******************************************************************************* +** +** Function gatt_connect +** +** Description This function is called to initiate a connection to a peer device. +** +** Parameter rem_bda: remote device address to connect to. +** +** Returns TRUE if connection is started, otherwise return FALSE. +** +*******************************************************************************/ +BOOLEAN gatt_connect (BD_ADDR rem_bda, tGATT_TCB *p_tcb, tBT_TRANSPORT transport) +{ + BOOLEAN gatt_ret = FALSE; + + if (gatt_get_ch_state(p_tcb) != GATT_CH_OPEN) + gatt_set_ch_state(p_tcb, GATT_CH_CONN); + + if (transport == BT_TRANSPORT_LE) + { + p_tcb->att_lcid = L2CAP_ATT_CID; + gatt_ret = L2CA_ConnectFixedChnl (L2CAP_ATT_CID, rem_bda); + } + else + { + if ((p_tcb->att_lcid = L2CA_ConnectReq(BT_PSM_ATT, rem_bda)) != 0) + gatt_ret = TRUE; + } + + return gatt_ret; +} + +/******************************************************************************* +** +** Function gatt_disconnect +** +** Description This function is called to disconnect to an ATT device. +** +** Parameter p_tcb: pointer to the TCB to disconnect. +** +** Returns TRUE: if connection found and to be disconnected; otherwise +** return FALSE. +** +*******************************************************************************/ +BOOLEAN gatt_disconnect (tGATT_TCB *p_tcb) +{ + BOOLEAN ret = FALSE; + tGATT_CH_STATE ch_state; + GATT_TRACE_DEBUG ("gatt_disconnect "); + + if (p_tcb != NULL) + { + ret = TRUE; + if ( (ch_state = gatt_get_ch_state(p_tcb)) != GATT_CH_CLOSING ) + { + if (p_tcb->att_lcid == L2CAP_ATT_CID) + { + if (ch_state == GATT_CH_OPEN) + { + /* only LCB exist between remote device and local */ + ret = L2CA_RemoveFixedChnl (L2CAP_ATT_CID, p_tcb->peer_bda); + } + else + { + gatt_set_ch_state(p_tcb, GATT_CH_CLOSING); + ret = L2CA_CancelBleConnectReq (p_tcb->peer_bda); + } + } + else + { + ret = L2CA_DisconnectReq(p_tcb->att_lcid); + } + } + else + { + GATT_TRACE_DEBUG ("gatt_disconnect already in closing state"); + } + } + + return ret; +} + +/******************************************************************************* +** +** Function gatt_update_app_hold_link_status +** +** Description Update the application use link status +** +** Returns void. +** +*******************************************************************************/ +void gatt_update_app_hold_link_status (tGATT_IF gatt_if, tGATT_TCB *p_tcb, BOOLEAN is_add) +{ + UINT8 i; + BOOLEAN found=FALSE; + + if (p_tcb == NULL) + { + GATT_TRACE_ERROR("gatt_update_app_hold_link_status p_tcb=NULL"); + return; + } + + + for (i=0; iapp_hold_link[i] == gatt_if) + { + found = TRUE; + if (!is_add) + { + p_tcb->app_hold_link[i] = 0; + break; + } + } + } + + if (!found && is_add) + { + for (i=0; iapp_hold_link[i] == 0) + { + p_tcb->app_hold_link[i] = gatt_if; + found = TRUE; + break; + } + } + } + + GATT_TRACE_DEBUG("gatt_update_app_hold_link_status found=%d[1-found] idx=%d gatt_if=%d is_add=%d", found, i, gatt_if, is_add); + +} + +/******************************************************************************* +** +** Function gatt_update_app_use_link_flag +** +** Description Update the application use link flag and optional to check the acl link +** if the link is up then set the idle time out accordingly +** +** Returns void. +** +*******************************************************************************/ +void gatt_update_app_use_link_flag (tGATT_IF gatt_if, tGATT_TCB *p_tcb, BOOLEAN is_add, BOOLEAN check_acl_link) +{ + GATT_TRACE_DEBUG("gatt_update_app_use_link_flag is_add=%d chk_link=%d", + is_add, check_acl_link); + + gatt_update_app_hold_link_status(gatt_if, p_tcb, is_add); + + if (check_acl_link && + p_tcb && + p_tcb->att_lcid == L2CAP_ATT_CID && /* only update link idle timer for fixed channel */ + (BTM_GetHCIConnHandle(p_tcb->peer_bda, p_tcb->transport) != GATT_INVALID_ACL_HANDLE)) + { + if (is_add) + { + GATT_TRACE_DEBUG("GATT disables link idle timer"); + /* acl link is connected disable the idle timeout */ + GATT_SetIdleTimeout(p_tcb->peer_bda, GATT_LINK_NO_IDLE_TIMEOUT, p_tcb->transport); + } + else + { + if (!gatt_num_apps_hold_link(p_tcb)) + { + /* acl link is connected but no application needs to use the link + so set the timeout value to GATT_LINK_IDLE_TIMEOUT_WHEN_NO_APP seconds */ + GATT_TRACE_DEBUG("GATT starts link idle timer =%d sec", GATT_LINK_IDLE_TIMEOUT_WHEN_NO_APP); + GATT_SetIdleTimeout(p_tcb->peer_bda, GATT_LINK_IDLE_TIMEOUT_WHEN_NO_APP, p_tcb->transport); + } + + } + } +} + +/******************************************************************************* +** +** Function gatt_act_connect +** +** Description GATT connection initiation. +** +** Returns void. +** +*******************************************************************************/ +BOOLEAN gatt_act_connect (tGATT_REG *p_reg, BD_ADDR bd_addr, tBT_TRANSPORT transport) +{ + BOOLEAN ret = FALSE; + tGATT_TCB *p_tcb; + UINT8 st; + + if ((p_tcb = gatt_find_tcb_by_addr(bd_addr, transport)) != NULL) + { + ret = TRUE; + st = gatt_get_ch_state(p_tcb); + + /* before link down, another app try to open a GATT connection */ + if(st == GATT_CH_OPEN && gatt_num_apps_hold_link(p_tcb) == 0 && + transport == BT_TRANSPORT_LE ) + { + if (!gatt_connect(bd_addr, p_tcb, transport)) + ret = FALSE; + } + else if(st == GATT_CH_CLOSING) + { + /* need to complete the closing first */ + ret = FALSE; + } + } + else + { + if ((p_tcb = gatt_allocate_tcb_by_bdaddr(bd_addr, transport)) != NULL) + { + if (!gatt_connect(bd_addr, p_tcb, transport)) + { + GATT_TRACE_ERROR("gatt_connect failed"); + memset(p_tcb, 0, sizeof(tGATT_TCB)); + } + else + ret = TRUE; + } + else + { + ret = 0; + GATT_TRACE_ERROR("Max TCB for gatt_if [%d] reached.", p_reg->gatt_if); + } + } + + if (ret) + { + gatt_update_app_use_link_flag(p_reg->gatt_if, p_tcb, TRUE, FALSE); + } + + return ret; +} + +/******************************************************************************* +** +** Function gatt_le_connect_cback +** +** Description This callback function is called by L2CAP to indicate that +** the ATT fixed channel for LE is +** connected (conn = TRUE)/disconnected (conn = FALSE). +** +*******************************************************************************/ +static void gatt_le_connect_cback (UINT16 chan, BD_ADDR bd_addr, BOOLEAN connected, + UINT16 reason, tBT_TRANSPORT transport) +{ + + tGATT_TCB *p_tcb = gatt_find_tcb_by_addr(bd_addr, transport); + BOOLEAN check_srv_chg = FALSE; + tGATTS_SRV_CHG *p_srv_chg_clt=NULL; + + /* ignore all fixed channel connect/disconnect on BR/EDR link for GATT */ + if (transport == BT_TRANSPORT_BR_EDR) + return; + + GATT_TRACE_DEBUG ("GATT ATT protocol channel with BDA: %08x%04x is %s", + (bd_addr[0]<<24)+(bd_addr[1]<<16)+(bd_addr[2]<<8)+bd_addr[3], + (bd_addr[4]<<8)+bd_addr[5], (connected) ? "connected" : "disconnected"); + + if ((p_srv_chg_clt = gatt_is_bda_in_the_srv_chg_clt_list(bd_addr)) != NULL) + { + check_srv_chg = TRUE; + } + else + { + if (btm_sec_is_a_bonded_dev(bd_addr)) + gatt_add_a_bonded_dev_for_srv_chg(bd_addr); + } + + if (connected) + { + /* do we have a channel initiating a connection? */ + if (p_tcb) + { + /* we are initiating connection */ + if ( gatt_get_ch_state(p_tcb) == GATT_CH_CONN) + { + /* send callback */ + gatt_set_ch_state(p_tcb, GATT_CH_OPEN); + p_tcb->payload_size = GATT_DEF_BLE_MTU_SIZE; + + gatt_send_conn_cback(p_tcb); + } + if (check_srv_chg) + gatt_chk_srv_chg (p_srv_chg_clt); + } + /* this is incoming connection or background connection callback */ + + else + { + if ((p_tcb = gatt_allocate_tcb_by_bdaddr(bd_addr, BT_TRANSPORT_LE)) != NULL) + { + p_tcb->att_lcid = L2CAP_ATT_CID; + + gatt_set_ch_state(p_tcb, GATT_CH_OPEN); + + p_tcb->payload_size = GATT_DEF_BLE_MTU_SIZE; + + gatt_send_conn_cback (p_tcb); + if (check_srv_chg) + { + gatt_chk_srv_chg (p_srv_chg_clt); + } + } + else + { + GATT_TRACE_ERROR("CCB max out, no rsources"); + } + } + } + else + { + gatt_cleanup_upon_disc(bd_addr, reason, transport); + GATT_TRACE_DEBUG ("ATT disconnected"); + } +} + +/******************************************************************************* +** +** Function gatt_channel_congestion +** +** Description This function is called to process the congestion callback +** from lcb +** +** Returns void +** +*******************************************************************************/ +static void gatt_channel_congestion(tGATT_TCB *p_tcb, BOOLEAN congested) +{ + UINT8 i = 0; + tGATT_REG *p_reg=NULL; + UINT16 conn_id; + + /* if uncongested, check to see if there is any more pending data */ + if (p_tcb != NULL && congested == FALSE) + { + gatt_cl_send_next_cmd_inq(p_tcb); + } + /* notifying all applications for the connection up event */ + for (i = 0, p_reg = gatt_cb.cl_rcb ; i < GATT_MAX_APPS; i++, p_reg++) + { + if (p_reg->in_use) + { + if (p_reg->app_cb.p_congestion_cb) + { + conn_id = GATT_CREATE_CONN_ID(p_tcb->tcb_idx, p_reg->gatt_if); + (*p_reg->app_cb.p_congestion_cb)(conn_id, congested); + } + } + } +} + +/******************************************************************************* +** +** Function gatt_le_cong_cback +** +** Description This function is called when GATT fixed channel is congested +** or uncongested. +** +** Returns void +** +*******************************************************************************/ +static void gatt_le_cong_cback(BD_ADDR remote_bda, BOOLEAN congested) +{ + tGATT_TCB *p_tcb = gatt_find_tcb_by_addr(remote_bda, BT_TRANSPORT_LE); + + /* if uncongested, check to see if there is any more pending data */ + if (p_tcb != NULL) + { + gatt_channel_congestion(p_tcb, congested); + } +} + +/******************************************************************************* +** +** Function gatt_le_data_ind +** +** Description This function is called when data is received from L2CAP. +** if we are the originator of the connection, we are the ATT +** client, and the received message is queued up for the client. +** +** If we are the destination of the connection, we are the ATT +** server, so the message is passed to the server processing +** function. +** +** Returns void +** +*******************************************************************************/ +static void gatt_le_data_ind (UINT16 chan, BD_ADDR bd_addr, BT_HDR *p_buf) +{ + tGATT_TCB *p_tcb; + + /* Find CCB based on bd addr */ + if ((p_tcb = gatt_find_tcb_by_addr (bd_addr, BT_TRANSPORT_LE)) != NULL && + gatt_get_ch_state(p_tcb) >= GATT_CH_OPEN) + { + gatt_data_process(p_tcb, p_buf); + } + else + { + GKI_freebuf (p_buf); + + if (p_tcb != NULL) + { + GATT_TRACE_WARNING ("ATT - Ignored L2CAP data while in state: %d", + gatt_get_ch_state(p_tcb)); + } + } +} + +/******************************************************************************* +** +** Function gatt_l2cif_connect_ind +** +** Description This function handles an inbound connection indication +** from L2CAP. This is the case where we are acting as a +** server. +** +** Returns void +** +*******************************************************************************/ +static void gatt_l2cif_connect_ind_cback (BD_ADDR bd_addr, UINT16 lcid, UINT16 psm, UINT8 id) +{ + /* do we already have a control channel for this peer? */ + UINT8 result = L2CAP_CONN_OK; + tL2CAP_CFG_INFO cfg; + tGATT_TCB *p_tcb = gatt_find_tcb_by_addr(bd_addr, BT_TRANSPORT_BR_EDR); + UNUSED(psm); + + GATT_TRACE_ERROR("Connection indication cid = %d", lcid); + /* new connection ? */ + if (p_tcb == NULL) + { + /* allocate tcb */ + if ((p_tcb = gatt_allocate_tcb_by_bdaddr(bd_addr, BT_TRANSPORT_BR_EDR)) == NULL) + { + /* no tcb available, reject L2CAP connection */ + result = L2CAP_CONN_NO_RESOURCES; + } + else + p_tcb->att_lcid = lcid; + + } + else /* existing connection , reject it */ + { + result = L2CAP_CONN_NO_RESOURCES; + } + + /* Send L2CAP connect rsp */ + L2CA_ConnectRsp(bd_addr, id, lcid, result, 0); + + /* if result ok, proceed with connection */ + if (result == L2CAP_CONN_OK) + { + /* transition to configuration state */ + gatt_set_ch_state(p_tcb, GATT_CH_CFG); + + /* Send L2CAP config req */ + memset(&cfg, 0, sizeof(tL2CAP_CFG_INFO)); + cfg.mtu_present = TRUE; + cfg.mtu = GATT_MAX_MTU_SIZE; + + L2CA_ConfigReq(lcid, &cfg); + } +} + +/******************************************************************************* +** +** Function gatt_l2c_connect_cfm_cback +** +** Description This is the L2CAP connect confirm callback function. +** +** +** Returns void +** +*******************************************************************************/ +static void gatt_l2cif_connect_cfm_cback(UINT16 lcid, UINT16 result) +{ + tGATT_TCB *p_tcb; + tL2CAP_CFG_INFO cfg; + + /* look up clcb for this channel */ + if ((p_tcb = gatt_find_tcb_by_cid(lcid)) != NULL) + { + GATT_TRACE_DEBUG("gatt_l2c_connect_cfm_cback result: %d ch_state: %d, lcid:0x%x", result, gatt_get_ch_state(p_tcb), p_tcb->att_lcid); + + /* if in correct state */ + if (gatt_get_ch_state(p_tcb) == GATT_CH_CONN) + { + /* if result successful */ + if (result == L2CAP_CONN_OK) + { + /* set channel state */ + gatt_set_ch_state(p_tcb, GATT_CH_CFG); + + /* Send L2CAP config req */ + memset(&cfg, 0, sizeof(tL2CAP_CFG_INFO)); + cfg.mtu_present = TRUE; + cfg.mtu = GATT_MAX_MTU_SIZE; + L2CA_ConfigReq(lcid, &cfg); + } + /* else initiating connection failure */ + else + { + gatt_cleanup_upon_disc(p_tcb->peer_bda, result, GATT_TRANSPORT_BR_EDR); + } + } + else /* wrong state, disconnect it */ + { + if (result == L2CAP_CONN_OK) + { + /* just in case the peer also accepts our connection - Send L2CAP disconnect req */ + L2CA_DisconnectReq(lcid); + } + } + } +} + +/******************************************************************************* +** +** Function gatt_l2cif_config_cfm_cback +** +** Description This is the L2CAP config confirm callback function. +** +** +** Returns void +** +*******************************************************************************/ +void gatt_l2cif_config_cfm_cback(UINT16 lcid, tL2CAP_CFG_INFO *p_cfg) +{ + tGATT_TCB *p_tcb; + tGATTS_SRV_CHG *p_srv_chg_clt=NULL; + + /* look up clcb for this channel */ + if ((p_tcb = gatt_find_tcb_by_cid(lcid)) != NULL) + { + /* if in correct state */ + if ( gatt_get_ch_state(p_tcb) == GATT_CH_CFG) + { + /* if result successful */ + if (p_cfg->result == L2CAP_CFG_OK) + { + /* update flags */ + p_tcb->ch_flags |= GATT_L2C_CFG_CFM_DONE; + + /* if configuration complete */ + if (p_tcb->ch_flags & GATT_L2C_CFG_IND_DONE) + { + gatt_set_ch_state(p_tcb, GATT_CH_OPEN); + + if ((p_srv_chg_clt = gatt_is_bda_in_the_srv_chg_clt_list(p_tcb->peer_bda)) != NULL) + { + gatt_chk_srv_chg(p_srv_chg_clt); + } + else + { + if (btm_sec_is_a_bonded_dev(p_tcb->peer_bda)) + gatt_add_a_bonded_dev_for_srv_chg(p_tcb->peer_bda); + } + + /* send callback */ + gatt_send_conn_cback(p_tcb); + } + } + /* else failure */ + else + { + /* Send L2CAP disconnect req */ + L2CA_DisconnectReq(lcid); + } + } + } +} + +/******************************************************************************* +** +** Function gatt_l2cif_config_ind_cback +** +** Description This is the L2CAP config indication callback function. +** +** +** Returns void +** +*******************************************************************************/ +void gatt_l2cif_config_ind_cback(UINT16 lcid, tL2CAP_CFG_INFO *p_cfg) +{ + tGATT_TCB *p_tcb; + tGATTS_SRV_CHG *p_srv_chg_clt=NULL; + /* look up clcb for this channel */ + if ((p_tcb = gatt_find_tcb_by_cid(lcid)) != NULL) + { + /* GATT uses the smaller of our MTU and peer's MTU */ + if ( p_cfg->mtu_present && + (p_cfg->mtu >= GATT_MIN_BR_MTU_SIZE && p_cfg->mtu < L2CAP_DEFAULT_MTU)) + p_tcb->payload_size = p_cfg->mtu; + else + p_tcb->payload_size = L2CAP_DEFAULT_MTU; + + /* send L2CAP configure response */ + memset(p_cfg, 0, sizeof(tL2CAP_CFG_INFO)); + p_cfg->result = L2CAP_CFG_OK; + L2CA_ConfigRsp(lcid, p_cfg); + + /* if first config ind */ + if ((p_tcb->ch_flags & GATT_L2C_CFG_IND_DONE) == 0) + { + /* update flags */ + p_tcb->ch_flags |= GATT_L2C_CFG_IND_DONE; + + /* if configuration complete */ + if (p_tcb->ch_flags & GATT_L2C_CFG_CFM_DONE) + { + gatt_set_ch_state(p_tcb, GATT_CH_OPEN); + if ((p_srv_chg_clt = gatt_is_bda_in_the_srv_chg_clt_list(p_tcb->peer_bda)) != NULL) + { + gatt_chk_srv_chg(p_srv_chg_clt); + } + else + { + if (btm_sec_is_a_bonded_dev(p_tcb->peer_bda)) + gatt_add_a_bonded_dev_for_srv_chg(p_tcb->peer_bda); + } + + /* send callback */ + gatt_send_conn_cback(p_tcb); + } + } + } +} + +/******************************************************************************* +** +** Function gatt_l2cif_disconnect_ind_cback +** +** Description This is the L2CAP disconnect indication callback function. +** +** +** Returns void +** +*******************************************************************************/ +void gatt_l2cif_disconnect_ind_cback(UINT16 lcid, BOOLEAN ack_needed) +{ + tGATT_TCB *p_tcb; + UINT16 reason; + + /* look up clcb for this channel */ + if ((p_tcb = gatt_find_tcb_by_cid(lcid)) != NULL) + { + if (ack_needed) + { + /* send L2CAP disconnect response */ + L2CA_DisconnectRsp(lcid); + } + if (gatt_is_bda_in_the_srv_chg_clt_list(p_tcb->peer_bda) == NULL) + { + if (btm_sec_is_a_bonded_dev(p_tcb->peer_bda)) + gatt_add_a_bonded_dev_for_srv_chg(p_tcb->peer_bda); + } + /* if ACL link is still up, no reason is logged, l2cap is disconnect from peer */ + if ((reason = L2CA_GetDisconnectReason(p_tcb->peer_bda, p_tcb->transport)) == 0) + reason = GATT_CONN_TERMINATE_PEER_USER; + + /* send disconnect callback */ + gatt_cleanup_upon_disc(p_tcb->peer_bda, reason, GATT_TRANSPORT_BR_EDR); + } +} + +/******************************************************************************* +** +** Function gatt_l2cif_disconnect_cfm_cback +** +** Description This is the L2CAP disconnect confirm callback function. +** +** +** Returns void +** +*******************************************************************************/ +static void gatt_l2cif_disconnect_cfm_cback(UINT16 lcid, UINT16 result) +{ + tGATT_TCB *p_tcb; + UINT16 reason; + UNUSED(result); + + /* look up clcb for this channel */ + if ((p_tcb = gatt_find_tcb_by_cid(lcid)) != NULL) + { + /* If the device is not in the service changed client list, add it... */ + if (gatt_is_bda_in_the_srv_chg_clt_list(p_tcb->peer_bda) == NULL) + { + if (btm_sec_is_a_bonded_dev(p_tcb->peer_bda)) + gatt_add_a_bonded_dev_for_srv_chg(p_tcb->peer_bda); + } + + /* send disconnect callback */ + /* if ACL link is still up, no reason is logged, l2cap is disconnect from peer */ + if ((reason = L2CA_GetDisconnectReason(p_tcb->peer_bda, p_tcb->transport)) == 0) + reason = GATT_CONN_TERMINATE_LOCAL_HOST; + + gatt_cleanup_upon_disc(p_tcb->peer_bda, reason, GATT_TRANSPORT_BR_EDR); + } +} + +/******************************************************************************* +** +** Function gatt_l2cif_data_ind_cback +** +** Description This is the L2CAP data indication callback function. +** +** +** Returns void +** +*******************************************************************************/ +static void gatt_l2cif_data_ind_cback(UINT16 lcid, BT_HDR *p_buf) +{ + tGATT_TCB *p_tcb; + + /* look up clcb for this channel */ + if ((p_tcb = gatt_find_tcb_by_cid(lcid)) != NULL && + gatt_get_ch_state(p_tcb) == GATT_CH_OPEN) + { + /* process the data */ + gatt_data_process(p_tcb, p_buf); + } + else /* prevent buffer leak */ + GKI_freebuf(p_buf); +} + +/******************************************************************************* +** +** Function gatt_l2cif_congest_cback +** +** Description L2CAP congestion callback +** +** Returns void +** +*******************************************************************************/ +static void gatt_l2cif_congest_cback (UINT16 lcid, BOOLEAN congested) +{ + tGATT_TCB *p_tcb = gatt_find_tcb_by_cid(lcid); + + if (p_tcb != NULL) + { + gatt_channel_congestion(p_tcb, congested); + } +} + +/******************************************************************************* +** +** Function gatt_send_conn_cback +** +** Description Callback used to notify layer above about a connection. +** +** +** Returns void +** +*******************************************************************************/ +static void gatt_send_conn_cback(tGATT_TCB *p_tcb) +{ + UINT8 i; + tGATT_REG *p_reg; + tGATT_BG_CONN_DEV *p_bg_dev=NULL; + UINT16 conn_id; + + p_bg_dev = gatt_find_bg_dev(p_tcb->peer_bda); + + /* notifying all applications for the connection up event */ + for (i = 0, p_reg = gatt_cb.cl_rcb ; i < GATT_MAX_APPS; i++, p_reg++) + { + if (p_reg->in_use) + { + if (p_bg_dev && gatt_is_bg_dev_for_app(p_bg_dev, p_reg->gatt_if)) + gatt_update_app_use_link_flag(p_reg->gatt_if, p_tcb, TRUE, TRUE); + + if (p_reg->app_cb.p_conn_cb) + { + conn_id = GATT_CREATE_CONN_ID(p_tcb->tcb_idx, p_reg->gatt_if); + (*p_reg->app_cb.p_conn_cb)(p_reg->gatt_if, p_tcb->peer_bda, conn_id, + TRUE, 0, p_tcb->transport); + } + } + } + + + if (gatt_num_apps_hold_link(p_tcb) && p_tcb->att_lcid == L2CAP_ATT_CID ) + { + /* disable idle timeout if one or more clients are holding the link disable the idle timer */ + GATT_SetIdleTimeout(p_tcb->peer_bda, GATT_LINK_NO_IDLE_TIMEOUT, p_tcb->transport); + } +} + +/******************************************************************************* +** +** Function gatt_le_data_ind +** +** Description This function is called when data is received from L2CAP. +** if we are the originator of the connection, we are the ATT +** client, and the received message is queued up for the client. +** +** If we are the destination of the connection, we are the ATT +** server, so the message is passed to the server processing +** function. +** +** Returns void +** +*******************************************************************************/ +void gatt_data_process (tGATT_TCB *p_tcb, BT_HDR *p_buf) +{ + UINT8 *p = (UINT8 *)(p_buf + 1) + p_buf->offset; + UINT8 op_code, pseudo_op_code; + UINT16 msg_len; + + + if (p_buf->len > 0) + { + msg_len = p_buf->len - 1; + STREAM_TO_UINT8(op_code, p); + + /* remove the two MSBs associated with sign write and write cmd */ + pseudo_op_code = op_code & (~GATT_WRITE_CMD_MASK); + + if (pseudo_op_code < GATT_OP_CODE_MAX) + { + if (op_code == GATT_SIGN_CMD_WRITE) + { + gatt_verify_signature(p_tcb, p_buf); + } + else + { + /* message from client */ + if ((op_code % 2) == 0) + gatt_server_handle_client_req (p_tcb, op_code, msg_len, p); + else + gatt_client_handle_server_rsp (p_tcb, op_code, msg_len, p); + } + } + else + { + GATT_TRACE_ERROR ("ATT - Rcvd L2CAP data, unknown cmd: 0x%x", op_code); + } + } + else + { + GATT_TRACE_ERROR ("invalid data length, ignore"); + } + + GKI_freebuf (p_buf); +} + +/******************************************************************************* +** +** Function gatt_add_a_bonded_dev_for_srv_chg +** +** Description Add a bonded dev to the service changed client list +** +** Returns void +** +*******************************************************************************/ +void gatt_add_a_bonded_dev_for_srv_chg (BD_ADDR bda) +{ + tGATTS_SRV_CHG_REQ req; + tGATTS_SRV_CHG srv_chg_clt; + + memcpy(srv_chg_clt.bda, bda, BD_ADDR_LEN); + srv_chg_clt.srv_changed = FALSE; + if (gatt_add_srv_chg_clt(&srv_chg_clt) != NULL) + { + memcpy(req.srv_chg.bda, bda, BD_ADDR_LEN); + req.srv_chg.srv_changed = FALSE; + if (gatt_cb.cb_info.p_srv_chg_callback) + (*gatt_cb.cb_info.p_srv_chg_callback)(GATTS_SRV_CHG_CMD_ADD_CLIENT, &req, NULL); + } +} + +/******************************************************************************* +** +** Function gatt_send_srv_chg_ind +** +** Description This function is called to send a service chnaged indication to +** the specified bd address +** +** Returns void +** +*******************************************************************************/ +void gatt_send_srv_chg_ind (BD_ADDR peer_bda) +{ + UINT8 handle_range[GATT_SIZE_OF_SRV_CHG_HNDL_RANGE]; + UINT8 *p = handle_range; + UINT16 conn_id; + + GATT_TRACE_DEBUG("gatt_send_srv_chg_ind"); + + if (gatt_cb.handle_of_h_r) + { + if ((conn_id = gatt_profile_find_conn_id_by_bd_addr(peer_bda)) != GATT_INVALID_CONN_ID) + { + UINT16_TO_STREAM (p, 1); + UINT16_TO_STREAM (p, 0xFFFF); + GATTS_HandleValueIndication (conn_id, + gatt_cb.handle_of_h_r, + GATT_SIZE_OF_SRV_CHG_HNDL_RANGE, + handle_range); + } + else + { + GATT_TRACE_ERROR("Unable to find conn_id for %08x%04x ", + (peer_bda[0]<<24)+(peer_bda[1]<<16)+(peer_bda[2]<<8)+peer_bda[3], + (peer_bda[4]<<8)+peer_bda[5] ); + } + } +} + +/******************************************************************************* +** +** Function gatt_chk_srv_chg +** +** Description Check sending service chnaged Indication is required or not +** if required then send the Indication +** +** Returns void +** +*******************************************************************************/ +void gatt_chk_srv_chg(tGATTS_SRV_CHG *p_srv_chg_clt) +{ + GATT_TRACE_DEBUG("gatt_chk_srv_chg srv_changed=%d", p_srv_chg_clt->srv_changed ); + + if (p_srv_chg_clt->srv_changed) + { + gatt_send_srv_chg_ind(p_srv_chg_clt->bda); + } +} + +/******************************************************************************* +** +** Function gatt_init_srv_chg +** +** Description This function is used to initialize the service changed +** attribute value +** +** Returns void +** +*******************************************************************************/ +void gatt_init_srv_chg (void) +{ + tGATTS_SRV_CHG_REQ req; + tGATTS_SRV_CHG_RSP rsp; + BOOLEAN status; + UINT8 num_clients,i; + tGATTS_SRV_CHG srv_chg_clt; + + GATT_TRACE_DEBUG("gatt_init_srv_chg"); + if (gatt_cb.cb_info.p_srv_chg_callback) + { + status = (*gatt_cb.cb_info.p_srv_chg_callback)(GATTS_SRV_CHG_CMD_READ_NUM_CLENTS, NULL, &rsp); + + if (status && rsp.num_clients) + { + GATT_TRACE_DEBUG("gatt_init_srv_chg num_srv_chg_clt_clients=%d", rsp.num_clients); + num_clients = rsp.num_clients; + i = 1; /* use one based index */ + while ((i <= num_clients) && status) + { + req.client_read_index = i; + if ((status = (*gatt_cb.cb_info.p_srv_chg_callback)(GATTS_SRV_CHG_CMD_READ_CLENT, &req, &rsp)) == TRUE) + { + memcpy(&srv_chg_clt, &rsp.srv_chg ,sizeof(tGATTS_SRV_CHG)); + if (gatt_add_srv_chg_clt(&srv_chg_clt) == NULL) + { + GATT_TRACE_ERROR("Unable to add a service change client"); + status = FALSE; + } + } + i++; + } + } + } + else + { + GATT_TRACE_DEBUG("gatt_init_srv_chg callback not registered yet"); + } +} + +/******************************************************************************* +** +** Function gatt_proc_srv_chg +** +** Description This function is process the service changed request +** +** Returns void +** +*******************************************************************************/ +void gatt_proc_srv_chg (void) +{ + UINT8 start_idx, found_idx; + BD_ADDR bda; + BOOLEAN srv_chg_ind_pending=FALSE; + tGATT_TCB *p_tcb; + tBT_TRANSPORT transport; + + GATT_TRACE_DEBUG ("gatt_proc_srv_chg"); + + if (gatt_cb.cb_info.p_srv_chg_callback && gatt_cb.handle_of_h_r) + { + gatt_set_srv_chg(); + start_idx =0; + while (gatt_find_the_connected_bda(start_idx, bda, &found_idx, &transport)) + { + p_tcb = &gatt_cb.tcb[found_idx];; + srv_chg_ind_pending = gatt_is_srv_chg_ind_pending(p_tcb); + + if (!srv_chg_ind_pending) + { + gatt_send_srv_chg_ind(bda); + } + else + { + GATT_TRACE_DEBUG ("discard srv chg - already has one in the queue"); + } + start_idx = ++found_idx; + } + } +} + +/******************************************************************************* +** +** Function gatt_set_ch_state +** +** Description This function set the ch_state in tcb +** +** Returns none +** +*******************************************************************************/ +void gatt_set_ch_state(tGATT_TCB *p_tcb, tGATT_CH_STATE ch_state) +{ + if (p_tcb) + { + GATT_TRACE_DEBUG ("gatt_set_ch_state: old=%d new=%d", p_tcb->ch_state, ch_state); + p_tcb->ch_state = ch_state; + } +} + +/******************************************************************************* +** +** Function gatt_get_ch_state +** +** Description This function get the ch_state in tcb +** +** Returns none +** +*******************************************************************************/ +tGATT_CH_STATE gatt_get_ch_state(tGATT_TCB *p_tcb) +{ + tGATT_CH_STATE ch_state = GATT_CH_CLOSE; + if (p_tcb) + { + GATT_TRACE_DEBUG ("gatt_get_ch_state: ch_state=%d", p_tcb->ch_state); + ch_state = p_tcb->ch_state; + } + return ch_state; +} + +#endif /* BLE_INCLUDED */ diff --git a/components/bt/bluedroid/stack/gatt/gatt_sr.c b/components/bt/bluedroid/stack/gatt/gatt_sr.c new file mode 100755 index 0000000000..7e6417babf --- /dev/null +++ b/components/bt/bluedroid/stack/gatt/gatt_sr.c @@ -0,0 +1,1532 @@ +/****************************************************************************** + * + * Copyright (C) 2008-2012 Broadcom Corporation + * + * 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 GATT server functions + * + ******************************************************************************/ + +#include "bt_target.h" +//#include "bt_utils.h" + +#if BLE_INCLUDED == TRUE +#include +#include "gatt_int.h" +#include "l2c_api.h" +#include "l2c_int.h" +#define GATT_MTU_REQ_MIN_LEN 2 + + +/******************************************************************************* +** +** Function gatt_sr_enqueue_cmd +** +** Description This function enqueue the request from client which needs a +** application response, and update the transaction ID. +** +** Returns void +** +*******************************************************************************/ +UINT32 gatt_sr_enqueue_cmd (tGATT_TCB *p_tcb, UINT8 op_code, UINT16 handle) +{ + tGATT_SR_CMD *p_cmd = &p_tcb->sr_cmd; + UINT32 trans_id = 0; + + if ( (p_cmd->op_code == 0) || + (op_code == GATT_HANDLE_VALUE_CONF)) /* no pending request */ + { + if (op_code == GATT_CMD_WRITE || + op_code == GATT_SIGN_CMD_WRITE || + op_code == GATT_REQ_MTU || + op_code == GATT_HANDLE_VALUE_CONF) + { + trans_id = ++p_tcb->trans_id; + } + else + { + p_cmd->trans_id = ++p_tcb->trans_id; + p_cmd->op_code = op_code; + p_cmd->handle = handle; + p_cmd->status = GATT_NOT_FOUND; + p_tcb->trans_id %= GATT_TRANS_ID_MAX; + trans_id = p_cmd->trans_id; + } + } + + return trans_id; +} + +/******************************************************************************* +** +** Function gatt_sr_cmd_empty +** +** Description This function check the server command queue is empty or not. +** +** Returns TRUE if empty, FALSE if there is pending command. +** +*******************************************************************************/ +BOOLEAN gatt_sr_cmd_empty (tGATT_TCB *p_tcb) +{ + return(p_tcb->sr_cmd.op_code == 0); +} + +/******************************************************************************* +** +** Function gatt_dequeue_sr_cmd +** +** Description This function dequeue the request from command queue. +** +** Returns void +** +*******************************************************************************/ +void gatt_dequeue_sr_cmd (tGATT_TCB *p_tcb) +{ + /* Double check in case any buffers are queued */ + GATT_TRACE_DEBUG("gatt_dequeue_sr_cmd" ); + if (p_tcb->sr_cmd.p_rsp_msg) + { + GATT_TRACE_ERROR("free p_tcb->sr_cmd.p_rsp_msg = %d", p_tcb->sr_cmd.p_rsp_msg); + + GKI_freebuf (p_tcb->sr_cmd.p_rsp_msg); + } + + while (GKI_getfirst(&p_tcb->sr_cmd.multi_rsp_q)) + GKI_freebuf (GKI_dequeue (&p_tcb->sr_cmd.multi_rsp_q)); + memset( &p_tcb->sr_cmd, 0, sizeof(tGATT_SR_CMD)); +} + +/******************************************************************************* +** +** Function process_read_multi_rsp +** +** Description This function check the read multiple response. +** +** Returns BOOLEAN if all replies have been received +** +*******************************************************************************/ +static BOOLEAN process_read_multi_rsp (tGATT_SR_CMD *p_cmd, tGATT_STATUS status, + tGATTS_RSP *p_msg, UINT16 mtu) +{ + tGATTS_RSP *p_rsp = NULL; + UINT16 ii, total_len, len; + BT_HDR *p_buf = (BT_HDR *)GKI_getbuf((UINT16)sizeof(tGATTS_RSP)); + UINT8 *p; + BOOLEAN is_overflow = FALSE; + + GATT_TRACE_DEBUG ("process_read_multi_rsp status=%d mtu=%d", status, mtu); + + if (p_buf == NULL) + { + p_cmd->status = GATT_INSUF_RESOURCE; + return FALSE; + } + + /* Enqueue the response */ + memcpy((void *)p_buf, (const void *)p_msg, sizeof(tGATTS_RSP)); + GKI_enqueue (&p_cmd->multi_rsp_q, p_buf); + + p_cmd->status = status; + if (status == GATT_SUCCESS) + { + GATT_TRACE_DEBUG ("Multi read count=%d num_hdls=%d", + GKI_queue_length(&p_cmd->multi_rsp_q), p_cmd->multi_req.num_handles); + /* Wait till we get all the responses */ + if (GKI_queue_length(&p_cmd->multi_rsp_q) == p_cmd->multi_req.num_handles) + { + len = sizeof(BT_HDR) + L2CAP_MIN_OFFSET + mtu; + if ((p_buf = (BT_HDR *)GKI_getbuf(len)) == NULL) + { + p_cmd->status = GATT_INSUF_RESOURCE; + return(TRUE); + } + + memset(p_buf, 0, len); + p_buf->offset = L2CAP_MIN_OFFSET; + p = (UINT8 *)(p_buf + 1) + p_buf->offset; + + /* First byte in the response is the opcode */ + *p++ = GATT_RSP_READ_MULTI; + p_buf->len = 1; + + /* Now walk through the buffers puting the data into the response in order */ + for (ii = 0; ii < p_cmd->multi_req.num_handles; ii++) + { + if (ii==0) + { + p_rsp = (tGATTS_RSP *)GKI_getfirst (&p_cmd->multi_rsp_q); + } + else + { + p_rsp = (tGATTS_RSP *)GKI_getnext (p_rsp); + } + + if (p_rsp != NULL) + { + + total_len = (p_buf->len + p_rsp->attr_value.len); + + if (total_len > mtu) + { + /* just send the partial response for the overflow case */ + len = p_rsp->attr_value.len - (total_len - mtu); + is_overflow = TRUE; + GATT_TRACE_DEBUG ("multi read overflow available len=%d val_len=%d", len, p_rsp->attr_value.len ); + } + else + { + len = p_rsp->attr_value.len; + } + + if (p_rsp->attr_value.handle == p_cmd->multi_req.handles[ii]) + { + memcpy (p, p_rsp->attr_value.value, len); + if (!is_overflow) + p += len; + p_buf->len += len; + } + else + { + p_cmd->status = GATT_NOT_FOUND; + break; + } + + if (is_overflow) + break; + + } + else + { + p_cmd->status = GATT_NOT_FOUND; + break; + } + + } /* loop through all handles*/ + + + /* Sanity check on the buffer length */ + if (p_buf->len == 0) + { + GATT_TRACE_ERROR("process_read_multi_rsp - nothing found!!"); + p_cmd->status = GATT_NOT_FOUND; + GKI_freebuf (p_buf); + GATT_TRACE_DEBUG(" GKI_freebuf (p_buf)"); + } + else if (p_cmd->p_rsp_msg != NULL) + { + GKI_freebuf (p_buf); + } + else + { + p_cmd->p_rsp_msg = p_buf; + } + + return(TRUE); + } + } + else /* any handle read exception occurs, return error */ + { + return(TRUE); + } + + /* If here, still waiting */ + return(FALSE); +} + +/******************************************************************************* +** +** Function gatt_sr_process_app_rsp +** +** Description This function checks whether the response message from application +** match any pending request or not. +** +** Returns void +** +*******************************************************************************/ +tGATT_STATUS gatt_sr_process_app_rsp (tGATT_TCB *p_tcb, tGATT_IF gatt_if, + UINT32 trans_id, UINT8 op_code, + tGATT_STATUS status, tGATTS_RSP *p_msg) +{ + tGATT_STATUS ret_code = GATT_SUCCESS; + UNUSED(trans_id); + + GATT_TRACE_DEBUG("gatt_sr_process_app_rsp gatt_if=%d", gatt_if); + + gatt_sr_update_cback_cnt(p_tcb, gatt_if, FALSE, FALSE); + + if (op_code == GATT_REQ_READ_MULTI) + { + /* If no error and still waiting, just return */ + if (!process_read_multi_rsp (&p_tcb->sr_cmd, status, p_msg, p_tcb->payload_size)) + return(GATT_SUCCESS); + } + else + { + if (op_code == GATT_REQ_PREPARE_WRITE && status == GATT_SUCCESS) + gatt_sr_update_prep_cnt(p_tcb, gatt_if, TRUE, FALSE); + + if (op_code == GATT_REQ_EXEC_WRITE && status != GATT_SUCCESS) + gatt_sr_reset_cback_cnt(p_tcb); + + p_tcb->sr_cmd.status = status; + + if (gatt_sr_is_cback_cnt_zero(p_tcb) + && status == GATT_SUCCESS) + { + if (p_tcb->sr_cmd.p_rsp_msg == NULL) + { + p_tcb->sr_cmd.p_rsp_msg = attp_build_sr_msg (p_tcb, (UINT8)(op_code + 1), (tGATT_SR_MSG *)p_msg); + } + else + { + GATT_TRACE_ERROR("Exception!!! already has respond message"); + } + } + } + if (gatt_sr_is_cback_cnt_zero(p_tcb)) + { + if ( (p_tcb->sr_cmd.status == GATT_SUCCESS) && (p_tcb->sr_cmd.p_rsp_msg) ) + { + ret_code = attp_send_sr_msg (p_tcb, p_tcb->sr_cmd.p_rsp_msg); + p_tcb->sr_cmd.p_rsp_msg = NULL; + } + else + { + ret_code = gatt_send_error_rsp (p_tcb, status, op_code, p_tcb->sr_cmd.handle, FALSE); + } + + gatt_dequeue_sr_cmd(p_tcb); + } + + GATT_TRACE_DEBUG("gatt_sr_process_app_rsp ret_code=%d", ret_code); + + return ret_code; +} + +/******************************************************************************* +** +** Function gatt_process_exec_write_req +** +** Description This function is called to process the execute write request +** from client. +** +** Returns void +** +*******************************************************************************/ +void gatt_process_exec_write_req (tGATT_TCB *p_tcb, UINT8 op_code, UINT16 len, UINT8 *p_data) +{ + UINT8 *p = p_data, flag, i = 0; + UINT32 trans_id = 0; + tGATT_IF gatt_if; + UINT16 conn_id; + + UNUSED(len); + +#if GATT_CONFORMANCE_TESTING == TRUE + if (gatt_cb.enable_err_rsp && gatt_cb.req_op_code == op_code) + { + GATT_TRACE_DEBUG("Conformance tst: forced err rspv for Execute Write: error status=%d", + gatt_cb.err_status); + + gatt_send_error_rsp (p_tcb, gatt_cb.err_status, gatt_cb.req_op_code, gatt_cb.handle, FALSE); + + return; + } +#endif + + STREAM_TO_UINT8(flag, p); + + /* mask the flag */ + flag &= GATT_PREP_WRITE_EXEC; + + + /* no prep write is queued */ + if (!gatt_sr_is_prep_cnt_zero(p_tcb)) + { + trans_id = gatt_sr_enqueue_cmd(p_tcb, op_code, 0); + gatt_sr_copy_prep_cnt_to_cback_cnt(p_tcb); + + for (i=0; iprep_cnt[i]) + { + gatt_if = (tGATT_IF) (i+1); + conn_id = GATT_CREATE_CONN_ID(p_tcb->tcb_idx, gatt_if); + gatt_sr_send_req_callback(conn_id, + trans_id, + GATTS_REQ_TYPE_WRITE_EXEC, + (tGATTS_DATA *)&flag); + p_tcb->prep_cnt[i]= 0; + } + } + } + else /* nothing needs to be executed , send response now */ + { + GATT_TRACE_ERROR("gatt_process_exec_write_req: no prepare write pending"); + gatt_send_error_rsp(p_tcb, GATT_ERROR, GATT_REQ_EXEC_WRITE, 0, FALSE); + } +} + +/******************************************************************************* +** +** Function gatt_process_read_multi_req +** +** Description This function is called to process the read multiple request +** from client. +** +** Returns void +** +*******************************************************************************/ +void gatt_process_read_multi_req (tGATT_TCB *p_tcb, UINT8 op_code, UINT16 len, UINT8 *p_data) +{ + UINT32 trans_id; + UINT16 handle = 0, ll = len; + UINT8 *p = p_data, i_rcb; + tGATT_STATUS err = GATT_SUCCESS; + UINT8 sec_flag, key_size; + tGATTS_RSP *p_msg; + + GATT_TRACE_DEBUG("gatt_process_read_multi_req" ); + p_tcb->sr_cmd.multi_req.num_handles = 0; + + gatt_sr_get_sec_info(p_tcb->peer_bda, + p_tcb->transport, + &sec_flag, + &key_size); + +#if GATT_CONFORMANCE_TESTING == TRUE + if (gatt_cb.enable_err_rsp && gatt_cb.req_op_code == op_code) + { + GATT_TRACE_DEBUG("Conformance tst: forced err rspvofr ReadMultiple: error status=%d", gatt_cb.err_status); + + STREAM_TO_UINT16(handle, p); + + gatt_send_error_rsp (p_tcb, gatt_cb.err_status, gatt_cb.req_op_code, handle, FALSE); + + return; + } +#endif + + while (ll >= 2 && p_tcb->sr_cmd.multi_req.num_handles < GATT_MAX_READ_MULTI_HANDLES) + { + STREAM_TO_UINT16(handle, p); + + if ((i_rcb = gatt_sr_find_i_rcb_by_handle(handle)) < GATT_MAX_SR_PROFILES) + { + p_tcb->sr_cmd.multi_req.handles[p_tcb->sr_cmd.multi_req.num_handles++] = handle; + + /* check read permission */ + if ((err = gatts_read_attr_perm_check( gatt_cb.sr_reg[i_rcb].p_db, + FALSE, + handle, + sec_flag, + key_size)) + != GATT_SUCCESS) + { + GATT_TRACE_DEBUG("read permission denied : 0x%02x", err); + break; + } + } + else + { + /* invalid handle */ + err = GATT_INVALID_HANDLE; + break; + } + ll -= 2; + } + + if (ll != 0) + { + GATT_TRACE_ERROR("max attribute handle reached in ReadMultiple Request."); + } + + if (p_tcb->sr_cmd.multi_req.num_handles == 0) + err = GATT_INVALID_HANDLE; + + if (err == GATT_SUCCESS) + { + if ((trans_id = gatt_sr_enqueue_cmd (p_tcb, op_code, p_tcb->sr_cmd.multi_req.handles[0])) != 0) + { + gatt_sr_reset_cback_cnt(p_tcb); /* read multiple use multi_rsp_q's count*/ + + for (ll = 0; ll < p_tcb->sr_cmd.multi_req.num_handles; ll ++) + { + if ((p_msg = (tGATTS_RSP *)GKI_getbuf(sizeof(tGATTS_RSP))) != NULL) + { + memset(p_msg, 0, sizeof(tGATTS_RSP)) + ; + handle = p_tcb->sr_cmd.multi_req.handles[ll]; + i_rcb = gatt_sr_find_i_rcb_by_handle(handle); + + p_msg->attr_value.handle = handle; + err = gatts_read_attr_value_by_handle(p_tcb, + gatt_cb.sr_reg[i_rcb].p_db, + op_code, + handle, + 0, + p_msg->attr_value.value, + &p_msg->attr_value.len, + GATT_MAX_ATTR_LEN, + sec_flag, + key_size, + trans_id); + + if (err == GATT_SUCCESS) + { + gatt_sr_process_app_rsp(p_tcb, gatt_cb.sr_reg[i_rcb].gatt_if ,trans_id, op_code, GATT_SUCCESS, p_msg); + } + /* either not using or done using the buffer, release it now */ + GKI_freebuf(p_msg); + } + else + { + err = GATT_NO_RESOURCES; + gatt_dequeue_sr_cmd(p_tcb); + break; + } + } + } + else + err = GATT_NO_RESOURCES; + } + + /* in theroy BUSY is not possible(should already been checked), protected check */ + if (err != GATT_SUCCESS && err != GATT_PENDING && err != GATT_BUSY) + gatt_send_error_rsp(p_tcb, err, op_code, handle, FALSE); +} + +/******************************************************************************* +** +** Function gatt_build_primary_service_rsp +** +** Description Primamry service request processed internally. Theretically +** only deal with ReadByTypeVAlue and ReadByGroupType. +** +** Returns void +** +*******************************************************************************/ +static tGATT_STATUS gatt_build_primary_service_rsp (BT_HDR *p_msg, tGATT_TCB *p_tcb, + UINT8 op_code, UINT16 s_hdl, + UINT16 e_hdl, UINT8 *p_data, tBT_UUID value) +{ + tGATT_STATUS status = GATT_NOT_FOUND; + UINT8 handle_len =4, *p ; + tGATT_SR_REG *p_rcb; + tGATT_SRV_LIST_INFO *p_list= &gatt_cb.srv_list_info; + tGATT_SRV_LIST_ELEM *p_srv=NULL; + tBT_UUID *p_uuid; + + UNUSED(p_data); + + p = (UINT8 *)(p_msg + 1) + L2CAP_MIN_OFFSET; + + p_srv = p_list->p_first; + + while (p_srv) + { + p_rcb = GATT_GET_SR_REG_PTR(p_srv->i_sreg); + + if (p_rcb->in_use && + p_rcb->s_hdl >= s_hdl && + p_rcb->s_hdl <= e_hdl && + p_rcb->type == GATT_UUID_PRI_SERVICE) + { + if ((p_uuid = gatts_get_service_uuid (p_rcb->p_db)) != NULL) + { + if (op_code == GATT_REQ_READ_BY_GRP_TYPE) + handle_len = 4 + p_uuid->len; + + /* get the length byte in the repsonse */ + if (p_msg->offset ==0) + { + *p ++ = op_code + 1; + p_msg->len ++; + p_msg->offset = handle_len; + + if (op_code == GATT_REQ_READ_BY_GRP_TYPE) + { + *p ++ = (UINT8)p_msg->offset; /* length byte */ + p_msg->len ++; + } + } + + if (p_msg->len + p_msg->offset <= p_tcb->payload_size && + handle_len == p_msg->offset) + { + if (op_code != GATT_REQ_FIND_TYPE_VALUE || + gatt_uuid_compare(value, *p_uuid)) + { + UINT16_TO_STREAM(p, p_rcb->s_hdl); + + if (p_list->p_last_primary == p_srv && + p_list->p_last_primary == p_list->p_last) + { + GATT_TRACE_DEBUG("Use 0xFFFF for the last primary attribute"); + UINT16_TO_STREAM(p, 0xFFFF); /* see GATT ERRATA 4065, 4063, ATT ERRATA 4062 */ + } + else + { + UINT16_TO_STREAM(p, p_rcb->e_hdl); + } + + if (op_code == GATT_REQ_READ_BY_GRP_TYPE) + gatt_build_uuid_to_stream(&p, *p_uuid); + + status = GATT_SUCCESS; + p_msg->len += p_msg->offset; + } + } + else + break; + } + } + p_srv = p_srv->p_next; + } + p_msg->offset = L2CAP_MIN_OFFSET; + + return status; +} + +/******************************************************************************* +** +** Function gatt_build_find_info_rsp +** +** Description fill the find information response information in the given +** buffer. +** +** Returns TRUE: if data filled sucessfully. +** FALSE: packet full, or format mismatch. +** +*******************************************************************************/ +static tGATT_STATUS gatt_build_find_info_rsp(tGATT_SR_REG *p_rcb, BT_HDR *p_msg, UINT16 *p_len, + UINT16 s_hdl, UINT16 e_hdl) +{ + tGATT_STATUS status = GATT_NOT_FOUND; + UINT8 *p; + UINT16 len = *p_len; + tGATT_ATTR16 *p_attr = NULL; + UINT8 info_pair_len[2] = {4, 18}; + + if (!p_rcb->p_db || !p_rcb->p_db->p_attr_list) + return status; + + /* check the attribute database */ + p_attr = (tGATT_ATTR16 *) p_rcb->p_db->p_attr_list; + + p = (UINT8 *)(p_msg + 1) + L2CAP_MIN_OFFSET + p_msg->len; + + while (p_attr) + { + if (p_attr->handle > e_hdl) + { + break; + } + + if (p_attr->handle >= s_hdl) + { + if (p_msg->offset == 0) + p_msg->offset = (p_attr->uuid_type == GATT_ATTR_UUID_TYPE_16) ? GATT_INFO_TYPE_PAIR_16 : GATT_INFO_TYPE_PAIR_128; + + if (len >= info_pair_len[p_msg->offset - 1]) + { + if (p_msg->offset == GATT_INFO_TYPE_PAIR_16 && p_attr->uuid_type == GATT_ATTR_UUID_TYPE_16) + { + UINT16_TO_STREAM(p, p_attr->handle); + UINT16_TO_STREAM(p, p_attr->uuid); + } + else if (p_msg->offset == GATT_INFO_TYPE_PAIR_128 && p_attr->uuid_type == GATT_ATTR_UUID_TYPE_128 ) + { + UINT16_TO_STREAM(p, p_attr->handle); + ARRAY_TO_STREAM (p, ((tGATT_ATTR128 *) p_attr)->uuid, LEN_UUID_128); + } + else if (p_msg->offset == GATT_INFO_TYPE_PAIR_128 && p_attr->uuid_type == GATT_ATTR_UUID_TYPE_32) + { + UINT16_TO_STREAM(p, p_attr->handle); + gatt_convert_uuid32_to_uuid128(p, ((tGATT_ATTR32 *) p_attr)->uuid); + p += LEN_UUID_128; + } + else + { + GATT_TRACE_ERROR("format mismatch"); + status = GATT_NO_RESOURCES; + break; + /* format mismatch */ + } + p_msg->len += info_pair_len[p_msg->offset - 1]; + len -= info_pair_len[p_msg->offset - 1]; + status = GATT_SUCCESS; + + } + else + { + status = GATT_NO_RESOURCES; + break; + } + } + p_attr = (tGATT_ATTR16 *)p_attr->p_next; + } + + *p_len = len; + return status; +} + +/******************************************************************************* +** +** Function gatts_internal_read_by_type_req +** +** Description check to see if the ReadByType request can be handled internally. +** +** Returns void +** +*******************************************************************************/ +static tGATT_STATUS gatts_validate_packet_format(UINT8 op_code, UINT16 *p_len, + UINT8 **p_data, tBT_UUID *p_uuid_filter, + UINT16 *p_s_hdl, UINT16 *p_e_hdl) +{ + tGATT_STATUS reason = GATT_SUCCESS; + UINT16 uuid_len, s_hdl = 0, e_hdl = 0; + UINT16 len = *p_len; + UINT8 *p = *p_data; + + if (len >= 4) + { + /* obtain starting handle, and ending handle */ + STREAM_TO_UINT16(s_hdl, p); + STREAM_TO_UINT16(e_hdl, p); + len -= 4; + + if (s_hdl > e_hdl || !GATT_HANDLE_IS_VALID(s_hdl) || !GATT_HANDLE_IS_VALID(e_hdl)) + { + reason = GATT_INVALID_HANDLE; + } + /* for these PDUs, uuid filter must present */ + else if (op_code == GATT_REQ_READ_BY_GRP_TYPE || + op_code == GATT_REQ_FIND_TYPE_VALUE || + op_code == GATT_REQ_READ_BY_TYPE) + { + if (len >= 2 && p_uuid_filter != NULL) + { + uuid_len = (op_code == GATT_REQ_FIND_TYPE_VALUE) ? 2 : len; + + /* parse uuid now */ + if (gatt_parse_uuid_from_cmd (p_uuid_filter, uuid_len, &p) == FALSE || + p_uuid_filter->len == 0) + { + GATT_TRACE_DEBUG("UUID filter does not exsit"); + reason = GATT_INVALID_PDU; + } + else + len -= p_uuid_filter->len; + } + else + reason = GATT_INVALID_PDU; + } + } + else + reason = GATT_INVALID_PDU; + + *p_data = p; + *p_len = len; + *p_s_hdl = s_hdl; + *p_e_hdl = e_hdl; + + return reason; +} + +/******************************************************************************* +** +** Function gatts_process_primary_service_req +** +** Description process ReadByGroupType/ReadByTypeValue request, for discover +** all primary services or discover primary service by UUID request. +** +** Returns void +** +*******************************************************************************/ +void gatts_process_primary_service_req(tGATT_TCB *p_tcb, UINT8 op_code, UINT16 len, UINT8 *p_data) +{ + UINT8 reason = GATT_INVALID_PDU; + UINT16 s_hdl = 0, e_hdl = 0; + tBT_UUID uuid, value, primary_service = {LEN_UUID_16, {GATT_UUID_PRI_SERVICE}}; + BT_HDR *p_msg = NULL; + UINT16 msg_len = (UINT16)(sizeof(BT_HDR) + p_tcb->payload_size + L2CAP_MIN_OFFSET); + + memset (&value, 0, sizeof(tBT_UUID)); + reason = gatts_validate_packet_format(op_code, &len, &p_data, &uuid, &s_hdl, &e_hdl); + + if (reason == GATT_SUCCESS) + { + if (gatt_uuid_compare(uuid, primary_service)) + { + if (op_code == GATT_REQ_FIND_TYPE_VALUE) + { + if (gatt_parse_uuid_from_cmd(&value, len, &p_data) == FALSE) + reason = GATT_INVALID_PDU; + } + + if (reason == GATT_SUCCESS) + { + if ((p_msg = (BT_HDR *)GKI_getbuf(msg_len)) == NULL) + { + GATT_TRACE_ERROR("gatts_process_primary_service_req failed. no resources."); + reason = GATT_NO_RESOURCES; + } + else + { + memset(p_msg, 0, msg_len); + reason = gatt_build_primary_service_rsp (p_msg, p_tcb, op_code, s_hdl, e_hdl, p_data, value); + } + } + } + else + { + if (op_code == GATT_REQ_READ_BY_GRP_TYPE) + { + reason = GATT_UNSUPPORT_GRP_TYPE; + GATT_TRACE_DEBUG("unexpected ReadByGrpType Group: 0x%04x", uuid.uu.uuid16); + } + else + { + /* we do not support ReadByTypeValue with any non-primamry_service type */ + reason = GATT_NOT_FOUND; + GATT_TRACE_DEBUG("unexpected ReadByTypeValue type: 0x%04x", uuid.uu.uuid16); + } + } + } + + if (reason != GATT_SUCCESS) + { + if (p_msg) GKI_freebuf(p_msg); + gatt_send_error_rsp (p_tcb, reason, op_code, s_hdl, FALSE); + } + else + attp_send_sr_msg(p_tcb, p_msg); + +} + +/******************************************************************************* +** +** Function gatts_process_find_info +** +** Description process find information request, for discover character +** descriptors. +** +** Returns void +** +*******************************************************************************/ +static void gatts_process_find_info(tGATT_TCB *p_tcb, UINT8 op_code, UINT16 len, UINT8 *p_data) +{ + UINT8 reason = GATT_INVALID_PDU, *p; + UINT16 s_hdl = 0, e_hdl = 0, buf_len; + BT_HDR *p_msg = NULL; + tGATT_SR_REG *p_rcb; + tGATT_SRV_LIST_INFO *p_list= &gatt_cb.srv_list_info; + tGATT_SRV_LIST_ELEM *p_srv=NULL; + + reason = gatts_validate_packet_format(op_code, &len, &p_data, NULL, &s_hdl, &e_hdl); + + if (reason == GATT_SUCCESS) + { + buf_len = (UINT16)(sizeof(BT_HDR) + p_tcb->payload_size + L2CAP_MIN_OFFSET); + + if ((p_msg = (BT_HDR *)GKI_getbuf(buf_len)) == NULL) + { + reason = GATT_NO_RESOURCES; + } + else + { + reason = GATT_NOT_FOUND; + + memset(p_msg, 0, buf_len); + p = (UINT8 *)(p_msg + 1) + L2CAP_MIN_OFFSET; + *p ++ = op_code + 1; + p_msg->len = 2; + + buf_len = p_tcb->payload_size - 2; + + p_srv = p_list->p_first; + + while (p_srv) + { + p_rcb = GATT_GET_SR_REG_PTR(p_srv->i_sreg); + + if (p_rcb->in_use && + !(p_rcb->s_hdl > e_hdl || + p_rcb->e_hdl < s_hdl)) + { + reason = gatt_build_find_info_rsp(p_rcb, p_msg, &buf_len, s_hdl, e_hdl); + if (reason == GATT_NO_RESOURCES) + { + reason = GATT_SUCCESS; + break; + } + } + p_srv = p_srv->p_next; + } + *p = (UINT8)p_msg->offset; + + p_msg->offset = L2CAP_MIN_OFFSET; + } + } + + if (reason != GATT_SUCCESS) + { + if (p_msg) GKI_freebuf(p_msg); + gatt_send_error_rsp (p_tcb, reason, op_code, s_hdl, FALSE); + } + else + attp_send_sr_msg(p_tcb, p_msg); + +} + +/******************************************************************************* +** +** Function gatts_process_mtu_req +** +** Description This function is called to process excahnge MTU request. +** Only used on LE. +** +** Returns void +** +*******************************************************************************/ +static void gatts_process_mtu_req (tGATT_TCB *p_tcb, UINT16 len, UINT8 *p_data) +{ + UINT16 mtu = 0; + UINT8 *p = p_data, i; + BT_HDR *p_buf; + UINT16 conn_id; + + /* BR/EDR conenction, send error response */ + if (p_tcb->att_lcid != L2CAP_ATT_CID) + { + gatt_send_error_rsp (p_tcb, GATT_REQ_NOT_SUPPORTED, GATT_REQ_MTU, 0, FALSE); + } + else if (len < GATT_MTU_REQ_MIN_LEN) + { + GATT_TRACE_ERROR("invalid MTU request PDU received."); + gatt_send_error_rsp (p_tcb, GATT_INVALID_PDU, GATT_REQ_MTU, 0, FALSE); + } + else + { + STREAM_TO_UINT16 (mtu, p); + /* mtu must be greater than default MTU which is 23/48 */ + if (mtu < GATT_DEF_BLE_MTU_SIZE) + p_tcb->payload_size = GATT_DEF_BLE_MTU_SIZE; + else if (mtu > GATT_MAX_MTU_SIZE) + p_tcb->payload_size = GATT_MAX_MTU_SIZE; + else + p_tcb->payload_size = mtu; + + GATT_TRACE_ERROR("MTU request PDU with MTU size %d", p_tcb->payload_size); + + l2cble_set_fixed_channel_tx_data_length(p_tcb->peer_bda, L2CAP_ATT_CID, p_tcb->payload_size); + + if ((p_buf = attp_build_sr_msg(p_tcb, GATT_RSP_MTU, (tGATT_SR_MSG *) &p_tcb->payload_size)) != NULL) + { + attp_send_sr_msg (p_tcb, p_buf); + + /* Notify all registered applicaiton with new MTU size. Us a transaction ID */ + /* of 0, as no response is allowed from applcations */ + + for (i = 0; i < GATT_MAX_APPS; i ++) + { + if (gatt_cb.cl_rcb[i].in_use ) + { + conn_id = GATT_CREATE_CONN_ID(p_tcb->tcb_idx, gatt_cb.cl_rcb[i].gatt_if); + gatt_sr_send_req_callback(conn_id, 0, GATTS_REQ_TYPE_MTU, + (tGATTS_DATA *)&p_tcb->payload_size); + } + } + + } + } +} + +/******************************************************************************* +** +** Function gatts_process_read_by_type_req +** +** Description process Read By type request. +** This PDU can be used to perform: +** - read characteristic value +** - read characteristic descriptor value +** - discover characteristic +** - discover characteristic by UUID +** - relationship discovery +** +** Returns void +** +*******************************************************************************/ +void gatts_process_read_by_type_req(tGATT_TCB *p_tcb, UINT8 op_code, UINT16 len, UINT8 *p_data) +{ + tBT_UUID uuid; + tGATT_SR_REG *p_rcb; + UINT16 msg_len = (UINT16)(sizeof(BT_HDR) + p_tcb->payload_size + L2CAP_MIN_OFFSET), + buf_len, + s_hdl, e_hdl, err_hdl = 0; + BT_HDR *p_msg = NULL; + tGATT_STATUS reason, ret; + UINT8 *p; + UINT8 sec_flag, key_size; + tGATT_SRV_LIST_INFO *p_list= &gatt_cb.srv_list_info; + tGATT_SRV_LIST_ELEM *p_srv=NULL; + + reason = gatts_validate_packet_format(op_code, &len, &p_data, &uuid, &s_hdl, &e_hdl); + +#if GATT_CONFORMANCE_TESTING == TRUE + if (gatt_cb.enable_err_rsp && gatt_cb.req_op_code == op_code) + { + GATT_TRACE_DEBUG("Conformance tst: forced err rsp for ReadByType: error status=%d", gatt_cb.err_status); + + gatt_send_error_rsp (p_tcb, gatt_cb.err_status, gatt_cb.req_op_code, s_hdl, FALSE); + + return; + } +#endif + + if (reason == GATT_SUCCESS) + { + if ((p_msg = (BT_HDR *)GKI_getbuf(msg_len)) == NULL) + { + GATT_TRACE_ERROR("gatts_process_find_info failed. no resources."); + + reason = GATT_NO_RESOURCES; + } + else + { + memset(p_msg, 0, msg_len); + p = (UINT8 *)(p_msg + 1) + L2CAP_MIN_OFFSET; + + *p ++ = op_code + 1; + /* reserve length byte */ + p_msg->len = 2; + buf_len = p_tcb->payload_size - 2; + + reason = GATT_NOT_FOUND; + + p_srv = p_list->p_first; + + while (p_srv) + { + p_rcb = GATT_GET_SR_REG_PTR(p_srv->i_sreg); + + if (p_rcb->in_use && + !(p_rcb->s_hdl > e_hdl || + p_rcb->e_hdl < s_hdl)) + { + gatt_sr_get_sec_info(p_tcb->peer_bda, + p_tcb->transport, + &sec_flag, + &key_size); + + ret = gatts_db_read_attr_value_by_type(p_tcb, + p_rcb->p_db, + op_code, + p_msg, + s_hdl, + e_hdl, + uuid, + &buf_len, + sec_flag, + key_size, + 0, + &err_hdl); + if (ret != GATT_NOT_FOUND) + { + reason = ret; + + if (ret == GATT_NO_RESOURCES) + reason = GATT_SUCCESS; + } + if (ret != GATT_SUCCESS && ret != GATT_NOT_FOUND) + { + s_hdl = err_hdl; + break; + } + } + p_srv = p_srv->p_next; + } + *p = (UINT8)p_msg->offset; + p_msg->offset = L2CAP_MIN_OFFSET; + } + } + if (reason != GATT_SUCCESS) + { + if (p_msg) GKI_freebuf(p_msg); + + /* in theroy BUSY is not possible(should already been checked), protected check */ + if (reason != GATT_PENDING && reason != GATT_BUSY) + gatt_send_error_rsp (p_tcb, reason, op_code, s_hdl, FALSE); + } + else + attp_send_sr_msg(p_tcb, p_msg); + +} + +/******************************************************************************* +** +** Function gatts_process_write_req +** +** Description This function is called to process the write request +** from client. +** +** Returns void +** +*******************************************************************************/ +void gatts_process_write_req (tGATT_TCB *p_tcb, UINT8 i_rcb, UINT16 handle, + UINT8 op_code, UINT16 len, UINT8 *p_data) +{ + tGATTS_DATA sr_data; + UINT32 trans_id; + tGATT_STATUS status; + UINT8 sec_flag, key_size, *p = p_data; + tGATT_SR_REG *p_sreg; + UINT16 conn_id; + + memset(&sr_data, 0, sizeof(tGATTS_DATA)); + + switch (op_code) + { + case GATT_REQ_PREPARE_WRITE: + sr_data.write_req.is_prep = TRUE; + STREAM_TO_UINT16(sr_data.write_req.offset, p); + len -= 2; + /* fall through */ + case GATT_SIGN_CMD_WRITE: + if (op_code == GATT_SIGN_CMD_WRITE) + { + GATT_TRACE_DEBUG("Write CMD with data sigining" ); + len -= GATT_AUTH_SIGN_LEN; + } + /* fall through */ + case GATT_CMD_WRITE: + case GATT_REQ_WRITE: + if (op_code == GATT_REQ_WRITE || op_code == GATT_REQ_PREPARE_WRITE) + sr_data.write_req.need_rsp = TRUE; + sr_data.write_req.handle = handle; + sr_data.write_req.len = len; + if (len != 0 && p != NULL) + { + memcpy (sr_data.write_req.value, p, len); + } + break; + } + + gatt_sr_get_sec_info(p_tcb->peer_bda, + p_tcb->transport, + &sec_flag, + &key_size); + + status = gatts_write_attr_perm_check (gatt_cb.sr_reg[i_rcb].p_db, + op_code, + handle, + sr_data.write_req.offset, + p, + len, + sec_flag, + key_size); + + if (status == GATT_SUCCESS) + { + if ((trans_id = gatt_sr_enqueue_cmd(p_tcb, op_code, handle)) != 0) + { + p_sreg = &gatt_cb.sr_reg[i_rcb]; + conn_id = GATT_CREATE_CONN_ID(p_tcb->tcb_idx, p_sreg->gatt_if); + gatt_sr_send_req_callback(conn_id, + trans_id, + GATTS_REQ_TYPE_WRITE, + &sr_data); + + status = GATT_PENDING; + } + else + { + GATT_TRACE_ERROR("max pending command, send error"); + status = GATT_BUSY; /* max pending command, application error */ + } + } + + /* in theroy BUSY is not possible(should already been checked), protected check */ + if (status != GATT_PENDING && status != GATT_BUSY && + (op_code == GATT_REQ_PREPARE_WRITE || op_code == GATT_REQ_WRITE)) + { + gatt_send_error_rsp (p_tcb, status, op_code, handle, FALSE); + } + return; +} + +/******************************************************************************* +** +** Function gatts_process_read_req +** +** Description This function is called to process the read request +** from client. +** +** Returns void +** +*******************************************************************************/ +static void gatts_process_read_req(tGATT_TCB *p_tcb, tGATT_SR_REG *p_rcb, UINT8 op_code, + UINT16 handle, UINT16 len, UINT8 *p_data) +{ + UINT16 buf_len = (UINT16)(sizeof(BT_HDR) + p_tcb->payload_size + L2CAP_MIN_OFFSET); + tGATT_STATUS reason; + BT_HDR *p_msg = NULL; + UINT8 sec_flag, key_size, *p; + UINT16 offset = 0, value_len = 0; + + UNUSED (len); + if ((p_msg = (BT_HDR *)GKI_getbuf(buf_len)) == NULL) + { + GATT_TRACE_ERROR("gatts_process_find_info failed. no resources."); + + reason = GATT_NO_RESOURCES; + } + else + { + if (op_code == GATT_REQ_READ_BLOB) + STREAM_TO_UINT16(offset, p_data); + + memset(p_msg, 0, buf_len); + p = (UINT8 *)(p_msg + 1) + L2CAP_MIN_OFFSET; + *p ++ = op_code + 1; + p_msg->len = 1; + buf_len = p_tcb->payload_size - 1; + + gatt_sr_get_sec_info(p_tcb->peer_bda, + p_tcb->transport, + &sec_flag, + &key_size); + + reason = gatts_read_attr_value_by_handle(p_tcb, + p_rcb->p_db, + op_code, + handle, + offset, + p, + &value_len, + buf_len, + sec_flag, + key_size, + 0); + + p_msg->len += value_len; + } + + if (reason != GATT_SUCCESS) + { + if (p_msg) GKI_freebuf(p_msg); + + /* in theroy BUSY is not possible(should already been checked), protected check */ + if (reason != GATT_PENDING && reason != GATT_BUSY) + gatt_send_error_rsp (p_tcb, reason, op_code, handle, FALSE); + } + else + attp_send_sr_msg(p_tcb, p_msg); + +} + +/******************************************************************************* +** +** Function gatts_process_attribute_req +** +** Description This function is called to process the per attribute handle request +** from client. +** +** Returns void +** +*******************************************************************************/ +void gatts_process_attribute_req (tGATT_TCB *p_tcb, UINT8 op_code, + UINT16 len, UINT8 *p_data) +{ + UINT16 handle = 0; + UINT8 *p = p_data, i; + tGATT_SR_REG *p_rcb = gatt_cb.sr_reg; + tGATT_STATUS status = GATT_INVALID_HANDLE; + tGATT_ATTR16 *p_attr; + + if (len < 2) + { + GATT_TRACE_ERROR("Illegal PDU length, discard request"); + status = GATT_INVALID_PDU; + } + else + { + STREAM_TO_UINT16(handle, p); + len -= 2; + } + +#if GATT_CONFORMANCE_TESTING == TRUE + gatt_cb.handle = handle; + if (gatt_cb.enable_err_rsp && gatt_cb.req_op_code == op_code) + { + GATT_TRACE_DEBUG("Conformance tst: forced err rsp: error status=%d", gatt_cb.err_status); + + gatt_send_error_rsp (p_tcb, gatt_cb.err_status, gatt_cb.req_op_code, handle, FALSE); + + return; + } +#endif + + if (GATT_HANDLE_IS_VALID(handle)) + { + for (i = 0; i < GATT_MAX_SR_PROFILES; i ++, p_rcb ++) + { + if (p_rcb->in_use && p_rcb->s_hdl <= handle && p_rcb->e_hdl >= handle) + { + p_attr = (tGATT_ATTR16 *)p_rcb->p_db->p_attr_list; + + while (p_attr) + { + if (p_attr->handle == handle) + { + switch (op_code) + { + case GATT_REQ_READ: /* read char/char descriptor value */ + case GATT_REQ_READ_BLOB: + gatts_process_read_req(p_tcb, p_rcb, op_code, handle, len, p); + break; + + case GATT_REQ_WRITE: /* write char/char descriptor value */ + case GATT_CMD_WRITE: + case GATT_SIGN_CMD_WRITE: + case GATT_REQ_PREPARE_WRITE: + gatts_process_write_req(p_tcb, i, handle, op_code, len, p); + break; + default: + break; + } + status = GATT_SUCCESS; + break; + } + p_attr = (tGATT_ATTR16 *)p_attr->p_next; + } + break; + } + } + } + + if (status != GATT_SUCCESS && op_code != GATT_CMD_WRITE && op_code != GATT_SIGN_CMD_WRITE) + gatt_send_error_rsp (p_tcb, status, op_code, handle, FALSE); +} + +/******************************************************************************* +** +** Function gatts_proc_srv_chg_ind_ack +** +** Description This function process the service changed indicaiton ACK +** +** Returns void +** +*******************************************************************************/ +static void gatts_proc_srv_chg_ind_ack(tGATT_TCB *p_tcb ) +{ + tGATTS_SRV_CHG_REQ req; + tGATTS_SRV_CHG *p_buf = NULL; + + GATT_TRACE_DEBUG("gatts_proc_srv_chg_ind_ack"); + + if ((p_buf = gatt_is_bda_in_the_srv_chg_clt_list(p_tcb->peer_bda)) != NULL) + { + GATT_TRACE_DEBUG("NV update set srv chg = FALSE"); + p_buf->srv_changed = FALSE; + memcpy(&req.srv_chg, p_buf, sizeof(tGATTS_SRV_CHG)); + if (gatt_cb.cb_info.p_srv_chg_callback) + (*gatt_cb.cb_info.p_srv_chg_callback)(GATTS_SRV_CHG_CMD_UPDATE_CLIENT,&req, NULL); + } +} + +/******************************************************************************* +** +** Function gatts_chk_pending_ind +** +** Description This function check any pending indication needs to be sent if +** there is a pending indication then sent the indication +** +** Returns void +** +*******************************************************************************/ +static void gatts_chk_pending_ind(tGATT_TCB *p_tcb ) +{ + tGATT_VALUE *p_buf = (tGATT_VALUE *)GKI_getfirst(&p_tcb->pending_ind_q); + GATT_TRACE_DEBUG("gatts_chk_pending_ind"); + + if (p_buf ) + { + GATTS_HandleValueIndication (p_buf->conn_id, + p_buf->handle, + p_buf->len, + p_buf->value); + GKI_freebuf(GKI_remove_from_queue (&p_tcb->pending_ind_q, p_buf)); + } +} + +/******************************************************************************* +** +** Function gatts_proc_ind_ack +** +** Description This function process the Indication ack +** +** Returns TRUE continue to process the indication ack by the aaplication +** if the ACk is not a Service Changed Indication Ack +** +*******************************************************************************/ +static BOOLEAN gatts_proc_ind_ack(tGATT_TCB *p_tcb, UINT16 ack_handle) +{ + BOOLEAN continue_processing = TRUE; + + GATT_TRACE_DEBUG ("gatts_proc_ind_ack ack handle=%d", ack_handle); + + if (ack_handle == gatt_cb.handle_of_h_r) + { + gatts_proc_srv_chg_ind_ack(p_tcb); + /* there is no need to inform the application since srv chg is handled internally by GATT */ + continue_processing = FALSE; + } + + gatts_chk_pending_ind(p_tcb); + return continue_processing; +} + +/******************************************************************************* +** +** Function gatts_process_value_conf +** +** Description This function is called to process the handle value confirmation. +** +** Returns void +** +*******************************************************************************/ +void gatts_process_value_conf(tGATT_TCB *p_tcb, UINT8 op_code) +{ + UINT16 handle = p_tcb->indicate_handle; + UINT32 trans_id; + UINT8 i; + tGATT_SR_REG *p_rcb = gatt_cb.sr_reg; + BOOLEAN continue_processing; + UINT16 conn_id; + + btu_stop_timer (&p_tcb->conf_timer_ent); + if (GATT_HANDLE_IS_VALID(handle)) + { + p_tcb->indicate_handle = 0; + continue_processing = gatts_proc_ind_ack(p_tcb, handle); + + if (continue_processing) + { + for (i = 0; i < GATT_MAX_SR_PROFILES; i ++, p_rcb ++) + { + if (p_rcb->in_use && p_rcb->s_hdl <= handle && p_rcb->e_hdl >= handle) + { + trans_id = gatt_sr_enqueue_cmd(p_tcb, op_code, handle); + conn_id = GATT_CREATE_CONN_ID(p_tcb->tcb_idx, p_rcb->gatt_if); + gatt_sr_send_req_callback(conn_id, + trans_id, GATTS_REQ_TYPE_CONF, (tGATTS_DATA *)&handle); + } + } + } + } + else + { + GATT_TRACE_ERROR("unexpected handle value confirmation"); + } +} + +/******************************************************************************* +** +** Function gatt_server_handle_client_req +** +** Description This function is called to handle the client requests to +** server. +** +** +** Returns void +** +*******************************************************************************/ +void gatt_server_handle_client_req (tGATT_TCB *p_tcb, UINT8 op_code, + UINT16 len, UINT8 *p_data) +{ + /* there is pending command, discard this one */ + if (!gatt_sr_cmd_empty(p_tcb) && op_code != GATT_HANDLE_VALUE_CONF) + return; + + /* the size of the message may not be bigger than the local max PDU size*/ + /* The message has to be smaller than the agreed MTU, len does not include op code */ + if (len >= p_tcb->payload_size) + { + GATT_TRACE_ERROR("server receive invalid PDU size:%d pdu size:%d", len + 1, p_tcb->payload_size ); + /* for invalid request expecting response, send it now */ + if (op_code != GATT_CMD_WRITE && + op_code != GATT_SIGN_CMD_WRITE && + op_code != GATT_HANDLE_VALUE_CONF) + { + gatt_send_error_rsp (p_tcb, GATT_INVALID_PDU, op_code, 0, FALSE); + } + /* otherwise, ignore the pkt */ + } + else + { + switch (op_code) + { + case GATT_REQ_READ_BY_GRP_TYPE: /* discover primary services */ + case GATT_REQ_FIND_TYPE_VALUE: /* discover service by UUID */ + gatts_process_primary_service_req (p_tcb, op_code, len, p_data); + break; + + case GATT_REQ_FIND_INFO:/* discover char descrptor */ + gatts_process_find_info(p_tcb, op_code, len, p_data); + break; + + case GATT_REQ_READ_BY_TYPE: /* read characteristic value, char descriptor value */ + /* discover characteristic, discover char by UUID */ + gatts_process_read_by_type_req(p_tcb, op_code, len, p_data); + break; + + + case GATT_REQ_READ: /* read char/char descriptor value */ + case GATT_REQ_READ_BLOB: + case GATT_REQ_WRITE: /* write char/char descriptor value */ + case GATT_CMD_WRITE: + case GATT_SIGN_CMD_WRITE: + case GATT_REQ_PREPARE_WRITE: + gatts_process_attribute_req (p_tcb, op_code, len, p_data); + break; + + case GATT_HANDLE_VALUE_CONF: + gatts_process_value_conf (p_tcb, op_code); + break; + + case GATT_REQ_MTU: + gatts_process_mtu_req (p_tcb, len, p_data); + break; + + case GATT_REQ_EXEC_WRITE: + gatt_process_exec_write_req (p_tcb, op_code, len, p_data); + break; + + case GATT_REQ_READ_MULTI: + gatt_process_read_multi_req (p_tcb, op_code, len, p_data); + break; + + default: + break; + } + } +} + +#endif /* BLE_INCLUDED */ diff --git a/components/bt/bluedroid/stack/gatt/gatt_utils.c b/components/bt/bluedroid/stack/gatt/gatt_utils.c new file mode 100755 index 0000000000..c882a1b3d2 --- /dev/null +++ b/components/bt/bluedroid/stack/gatt/gatt_utils.c @@ -0,0 +1,2804 @@ +/****************************************************************************** + * + * Copyright (C) 2009-2012 Broadcom Corporation + * + * 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 GATT utility functions + * + ******************************************************************************/ +#include "bt_target.h" +//#include "bt_utils.h" + +#if BLE_INCLUDED == TRUE + #include + #include + #include "gki.h" + + #include "l2cdefs.h" + #include "gatt_int.h" + #include "gatt_api.h" + #include "gattdefs.h" + #include "sdp_api.h" + #include "btm_int.h" +/* check if [x, y] and [a, b] have overlapping range */ + #define GATT_VALIDATE_HANDLE_RANGE(x, y, a, b) (y >= a && x <= b) + + #define GATT_GET_NEXT_VALID_HANDLE(x) (((x)/10 + 1) * 10) + +const char * const op_code_name[] = +{ + "UNKNOWN", + "ATT_RSP_ERROR", + "ATT_REQ_MTU", + "ATT_RSP_MTU", + "ATT_REQ_READ_INFO", + "ATT_RSP_READ_INFO", + "ATT_REQ_FIND_TYPE_VALUE", + "ATT_RSP_FIND_TYPE_VALUE", + "ATT_REQ_READ_BY_TYPE", + "ATT_RSP_READ_BY_TYPE", + "ATT_REQ_READ", + "ATT_RSP_READ", + "ATT_REQ_READ_BLOB", + "ATT_RSP_READ_BLOB", + "GATT_REQ_READ_MULTI", + "GATT_RSP_READ_MULTI", + "GATT_REQ_READ_BY_GRP_TYPE", + "GATT_RSP_READ_BY_GRP_TYPE", + "ATT_REQ_WRITE", + "ATT_RSP_WRITE", + "ATT_CMD_WRITE", + "ATT_SIGN_CMD_WRITE", + "ATT_REQ_PREPARE_WRITE", + "ATT_RSP_PREPARE_WRITE", + "ATT_REQ_EXEC_WRITE", + "ATT_RSP_EXEC_WRITE", + "Reserved", + "ATT_HANDLE_VALUE_NOTIF", + "Reserved", + "ATT_HANDLE_VALUE_IND", + "ATT_HANDLE_VALUE_CONF", + "ATT_OP_CODE_MAX" +}; + +static const UINT8 base_uuid[LEN_UUID_128] = {0xFB, 0x34, 0x9B, 0x5F, 0x80, 0x00, 0x00, 0x80, + 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + + +/******************************************************************************* +** +** Function gatt_free_pending_ind +** +** Description Free all pending indications +** +** Returns None +** +*******************************************************************************/ +void gatt_free_pending_ind(tGATT_TCB *p_tcb) +{ + GATT_TRACE_DEBUG("gatt_free_pending_ind"); + /* release all queued indications */ + while (!GKI_queue_is_empty(&p_tcb->pending_ind_q)) + GKI_freebuf (GKI_dequeue (&p_tcb->pending_ind_q)); +} + +/******************************************************************************* +** +** Function gatt_free_pending_enc_queue +** +** Description Free all buffers in pending encyption queue +** +** Returns None +** +*******************************************************************************/ +void gatt_free_pending_enc_queue(tGATT_TCB *p_tcb) +{ + GATT_TRACE_DEBUG("gatt_free_pending_enc_queue"); + /* release all queued indications */ + while (!GKI_queue_is_empty(&p_tcb->pending_enc_clcb)) + GKI_freebuf (GKI_dequeue (&p_tcb->pending_enc_clcb)); +} + +/******************************************************************************* +** +** Function gatt_delete_dev_from_srv_chg_clt_list +** +** Description Delete a device from the service changed client lit +** +** Returns None +** +*******************************************************************************/ +void gatt_delete_dev_from_srv_chg_clt_list(BD_ADDR bd_addr) +{ + tGATTS_SRV_CHG *p_buf; + tGATTS_SRV_CHG_REQ req; + + GATT_TRACE_DEBUG ("gatt_delete_dev_from_srv_chg_clt_list"); + if ((p_buf = gatt_is_bda_in_the_srv_chg_clt_list(bd_addr)) != NULL) + { + if (gatt_cb.cb_info.p_srv_chg_callback) + { + /* delete from NV */ + memcpy(req.srv_chg.bda, bd_addr, BD_ADDR_LEN); + (*gatt_cb.cb_info.p_srv_chg_callback)(GATTS_SRV_CHG_CMD_REMOVE_CLIENT,&req, NULL); + } + GKI_freebuf (GKI_remove_from_queue (&gatt_cb.srv_chg_clt_q, p_buf)); + } + +} + +/******************************************************************************* +** +** Function gatt_set_srv_chg +** +** Description Set the service changed flag to TRUE +** +** Returns None +** +*******************************************************************************/ +void gatt_set_srv_chg(void) +{ + tGATTS_SRV_CHG *p_buf = (tGATTS_SRV_CHG *)GKI_getfirst(&gatt_cb.srv_chg_clt_q); + tGATTS_SRV_CHG_REQ req; + + GATT_TRACE_DEBUG ("gatt_set_srv_chg"); + while (p_buf) + { + GATT_TRACE_DEBUG ("found a srv_chg clt"); + if (!p_buf->srv_changed) + { + GATT_TRACE_DEBUG ("set srv_changed to TRUE"); + p_buf->srv_changed= TRUE; + memcpy(&req.srv_chg, p_buf, sizeof(tGATTS_SRV_CHG)); + if (gatt_cb.cb_info.p_srv_chg_callback) + (*gatt_cb.cb_info.p_srv_chg_callback)(GATTS_SRV_CHG_CMD_UPDATE_CLIENT,&req, NULL); + } + p_buf = (tGATTS_SRV_CHG *)GKI_getnext(p_buf); + } +} + +/******************************************************************************* +** +** Function gatt_sr_is_new_srv_chg +** +** Description Find the app id in on the new service changed list +** +** Returns Pointer to the found new service changed item othwerwise NULL +** +*******************************************************************************/ +tGATTS_PENDING_NEW_SRV_START *gatt_sr_is_new_srv_chg(tBT_UUID *p_app_uuid128, tBT_UUID *p_svc_uuid, UINT16 svc_inst) +{ + tGATTS_HNDL_RANGE *p; + tGATTS_PENDING_NEW_SRV_START *p_buf = (tGATTS_PENDING_NEW_SRV_START *)GKI_getfirst(&gatt_cb.pending_new_srv_start_q); + + while (p_buf != NULL) + { + p = p_buf->p_new_srv_start; + if ( gatt_uuid_compare (*p_app_uuid128, p->app_uuid128) + && gatt_uuid_compare (*p_svc_uuid, p->svc_uuid) + && (svc_inst == p->svc_inst) ) + { + GATT_TRACE_DEBUG ("gatt_sr_is_new_srv_chg: Yes"); + break; + } + p_buf = (tGATTS_PENDING_NEW_SRV_START *)GKI_getnext(p_buf); + } + + return p_buf; +} + + +/******************************************************************************* +** +** Function gatt_add_pending_ind +** +** Description Add a pending indication +** +** Returns Pointer to the current pending indication buffer, NULL no buffer available +** +*******************************************************************************/ +tGATT_VALUE *gatt_add_pending_ind(tGATT_TCB *p_tcb, tGATT_VALUE *p_ind) +{ + tGATT_VALUE *p_buf; + GATT_TRACE_DEBUG ("gatt_add_pending_ind"); + if ((p_buf = (tGATT_VALUE *)GKI_getbuf((UINT16)sizeof(tGATT_VALUE))) != NULL) + { + GATT_TRACE_DEBUG ("enqueue a pending indication"); + memcpy(p_buf, p_ind, sizeof(tGATT_VALUE)); + GKI_enqueue (&p_tcb->pending_ind_q, p_buf); + } + return p_buf; +} + + +/******************************************************************************* +** +** Function gatt_add_pending_new_srv_start +** +** Description Add a pending new srv start to the new service start queue +** +** Returns Pointer to the new service start buffer, NULL no buffer available +** +*******************************************************************************/ +tGATTS_PENDING_NEW_SRV_START *gatt_add_pending_new_srv_start(tGATTS_HNDL_RANGE *p_new_srv_start) +{ + tGATTS_PENDING_NEW_SRV_START *p_buf; + + GATT_TRACE_DEBUG ("gatt_add_pending_new_srv_start"); + if ((p_buf = (tGATTS_PENDING_NEW_SRV_START *)GKI_getbuf((UINT16)sizeof(tGATTS_PENDING_NEW_SRV_START))) != NULL) + { + GATT_TRACE_DEBUG ("enqueue a new pending new srv start"); + p_buf->p_new_srv_start = p_new_srv_start; + GKI_enqueue (&gatt_cb.pending_new_srv_start_q, p_buf); + } + return p_buf; +} + + +/******************************************************************************* +** +** Function gatt_add_srv_chg_clt +** +** Description Add a service chnage client to the service change client queue +** +** Returns Pointer to the service change client buffer; Null no buffer available +** +*******************************************************************************/ +tGATTS_SRV_CHG *gatt_add_srv_chg_clt(tGATTS_SRV_CHG *p_srv_chg) +{ + tGATTS_SRV_CHG *p_buf; + GATT_TRACE_DEBUG ("gatt_add_srv_chg_clt"); + if ((p_buf = (tGATTS_SRV_CHG *)GKI_getbuf((UINT16)sizeof(tGATTS_SRV_CHG))) != NULL) + { + GATT_TRACE_DEBUG ("enqueue a srv chg client"); + memcpy(p_buf, p_srv_chg, sizeof(tGATTS_SRV_CHG)); + GKI_enqueue (&gatt_cb.srv_chg_clt_q, p_buf); + } + + return p_buf; +} + + +/******************************************************************************* +** +** Function gatt_alloc_hdl_buffer +** +** Description Allocate a handle buufer +** +** Returns Pointer to the allocated buffer, NULL no buffer available +** +*******************************************************************************/ +tGATT_HDL_LIST_ELEM *gatt_alloc_hdl_buffer(void) +{ + UINT8 i; + tGATT_CB *p_cb = &gatt_cb; + tGATT_HDL_LIST_ELEM * p_elem= &p_cb->hdl_list[0]; + + for (i = 0; i < GATT_MAX_SR_PROFILES; i++, p_elem ++) + { + if (!p_cb->hdl_list[i].in_use) + { + memset(p_elem, 0, sizeof(tGATT_HDL_LIST_ELEM)); + p_elem->in_use = TRUE; + return p_elem; + } + } + + return NULL; +} + +/******************************************************************************* +** +** Function gatt_find_hdl_buffer_by_handle +** +** Description Find handle range buffer by service handle. +** +** Returns Pointer to the buffer, NULL no buffer available +** +*******************************************************************************/ +tGATT_HDL_LIST_ELEM *gatt_find_hdl_buffer_by_handle(UINT16 handle) +{ + tGATT_HDL_LIST_INFO *p_list_info= &gatt_cb.hdl_list_info; + tGATT_HDL_LIST_ELEM *p_list = NULL; + + p_list = p_list_info->p_first; + + while (p_list != NULL) + { + if (p_list->in_use && p_list->asgn_range.s_handle == handle) + { + return(p_list); + } + p_list = p_list->p_next; + } + return NULL; +} +/******************************************************************************* +** +** Function gatt_find_hdl_buffer_by_app_id +** +** Description Find handle range buffer by app ID, service and service instance ID. +** +** Returns Pointer to the buffer, NULL no buffer available +** +*******************************************************************************/ +tGATT_HDL_LIST_ELEM *gatt_find_hdl_buffer_by_app_id (tBT_UUID *p_app_uuid128, + tBT_UUID *p_svc_uuid, + UINT16 svc_inst) +{ + tGATT_HDL_LIST_INFO *p_list_info= &gatt_cb.hdl_list_info; + tGATT_HDL_LIST_ELEM *p_list = NULL; + + p_list = p_list_info->p_first; + + while (p_list != NULL) + { + if ( gatt_uuid_compare (*p_app_uuid128, p_list->asgn_range.app_uuid128) + && gatt_uuid_compare (*p_svc_uuid, p_list->asgn_range.svc_uuid) + && (svc_inst == p_list->asgn_range.svc_inst) ) + { + GATT_TRACE_DEBUG ("Already allocated handles for this service before!!"); + return(p_list); + } + p_list = p_list->p_next; + } + return NULL; +} +/******************************************************************************* +** +** Function gatt_free_hdl_buffer +** +** Description free a handle buffer +** +** Returns None +** +*******************************************************************************/ +void gatt_free_hdl_buffer(tGATT_HDL_LIST_ELEM *p) +{ + + if (p) + { + while (!GKI_queue_is_empty(&p->svc_db.svc_buffer)) + GKI_freebuf (GKI_dequeue (&p->svc_db.svc_buffer)); + memset(p, 0, sizeof(tGATT_HDL_LIST_ELEM)); + } +} +/******************************************************************************* +** +** Function gatt_free_srvc_db_buffer_app_id +** +** Description free the service attribute database buffers by the owner of the +** service app ID. +** +** Returns None +** +*******************************************************************************/ +void gatt_free_srvc_db_buffer_app_id(tBT_UUID *p_app_id) +{ + tGATT_HDL_LIST_ELEM *p_elem = &gatt_cb.hdl_list[0]; + UINT8 i; + + for (i = 0; i < GATT_MAX_SR_PROFILES; i ++, p_elem ++) + { + if (memcmp(p_app_id, &p_elem->asgn_range.app_uuid128, sizeof(tBT_UUID)) == 0) + { + while (!GKI_queue_is_empty(&p_elem->svc_db.svc_buffer)) + GKI_freebuf (GKI_dequeue (&p_elem->svc_db.svc_buffer)); + + p_elem->svc_db.mem_free = 0; + p_elem->svc_db.p_attr_list = p_elem->svc_db.p_free_mem = NULL; + } + } +} +/******************************************************************************* +** +** Function gatt_is_last_attribute +** +** Description Check this is the last attribute of the specified value or not +** +** Returns TRUE - yes this is the last attribute +** +*******************************************************************************/ +BOOLEAN gatt_is_last_attribute(tGATT_SRV_LIST_INFO *p_list, tGATT_SRV_LIST_ELEM *p_start, tBT_UUID value) +{ + tGATT_SRV_LIST_ELEM *p_srv= p_start->p_next; + BOOLEAN is_last_attribute = TRUE; + tGATT_SR_REG *p_rcb = NULL; + tBT_UUID *p_svc_uuid; + + p_list->p_last_primary = NULL; + + while (p_srv) + { + p_rcb = GATT_GET_SR_REG_PTR(p_srv->i_sreg); + + p_svc_uuid = gatts_get_service_uuid (p_rcb->p_db); + + if (gatt_uuid_compare(value, *p_svc_uuid)) + { + is_last_attribute = FALSE; + break; + + } + p_srv = p_srv->p_next; + } + + return is_last_attribute; + +} + +/******************************************************************************* +** +** Function gatt_update_last_pri_srv_info +** +** Description Update the the last primary info for the service list info +** +** Returns None +** +*******************************************************************************/ +void gatt_update_last_pri_srv_info(tGATT_SRV_LIST_INFO *p_list) +{ + tGATT_SRV_LIST_ELEM *p_srv= p_list->p_first; + + p_list->p_last_primary = NULL; + + while (p_srv) + { + if (p_srv->is_primary) + { + p_list->p_last_primary = p_srv; + } + p_srv = p_srv->p_next; + } + +} +/******************************************************************************* +** +** Function gatts_update_srv_list_elem +** +** Description update an element in the service list. +** +** Returns None. +** +*******************************************************************************/ +void gatts_update_srv_list_elem(UINT8 i_sreg, UINT16 handle, BOOLEAN is_primary) +{ + UNUSED(handle); + + gatt_cb.srv_list[i_sreg].in_use = TRUE; + gatt_cb.srv_list[i_sreg].i_sreg = i_sreg; + gatt_cb.srv_list[i_sreg].s_hdl = gatt_cb.sr_reg[i_sreg].s_hdl; + gatt_cb.srv_list[i_sreg].is_primary = is_primary; + + return; +} +/******************************************************************************* +** +** Function gatt_add_a_srv_to_list +** +** Description add an service to the list in ascending +** order of the start handle +** +** Returns BOOLEAN TRUE-if add is successful +** +*******************************************************************************/ +BOOLEAN gatt_add_a_srv_to_list(tGATT_SRV_LIST_INFO *p_list, tGATT_SRV_LIST_ELEM *p_new) +{ + tGATT_SRV_LIST_ELEM *p_old; + + if (!p_new) + { + GATT_TRACE_DEBUG("p_new==NULL"); + return FALSE; + } + + if (!p_list->p_first) + { + /* this is an empty list */ + p_list->p_first = + p_list->p_last = p_new; + p_new->p_next = + p_new->p_prev = NULL; + } + else + { + p_old = p_list->p_first; + while (1) + { + if (p_old == NULL) + { + p_list->p_last->p_next = p_new; + p_new->p_prev = p_list->p_last; + p_new->p_next = NULL; + p_list->p_last = p_new; + break; + } + else + { + if (p_new->s_hdl < p_old->s_hdl) + { + /* if not the first in list */ + if (p_old->p_prev != NULL) + p_old->p_prev->p_next = p_new; + else + p_list->p_first = p_new; + + p_new->p_prev = p_old->p_prev; + p_new->p_next = p_old; + p_old->p_prev = p_new; + break; + } + } + p_old = p_old->p_next; + } + } + p_list->count++; + + gatt_update_last_pri_srv_info(p_list); + return TRUE; + +} + +/******************************************************************************* +** +** Function gatt_remove_a_srv_from_list +** +** Description Remove a service from the list +** +** Returns BOOLEAN TRUE-if remove is successful +** +*******************************************************************************/ +BOOLEAN gatt_remove_a_srv_from_list(tGATT_SRV_LIST_INFO *p_list, tGATT_SRV_LIST_ELEM *p_remove) +{ + if (!p_remove || !p_list->p_first) + { + GATT_TRACE_DEBUG("p_remove==NULL || p_list->p_first==NULL"); + return FALSE; + } + + if (p_remove->p_prev == NULL) + { + p_list->p_first = p_remove->p_next; + if (p_remove->p_next) + p_remove->p_next->p_prev = NULL; + } + else if (p_remove->p_next == NULL) + { + p_list->p_last = p_remove->p_prev; + p_remove->p_prev->p_next = NULL; + } + else + { + p_remove->p_next->p_prev = p_remove->p_prev; + p_remove->p_prev->p_next = p_remove->p_next; + } + p_list->count--; + gatt_update_last_pri_srv_info(p_list); + return TRUE; + +} + +/******************************************************************************* +** +** Function gatt_add_an_item_to_list +** +** Description add an service handle range to the list in decending +** order of the start handle +** +** Returns BOOLEAN TRUE-if add is successful +** +*******************************************************************************/ +BOOLEAN gatt_add_an_item_to_list(tGATT_HDL_LIST_INFO *p_list, tGATT_HDL_LIST_ELEM *p_new) +{ + tGATT_HDL_LIST_ELEM *p_old; + if (!p_new) + { + GATT_TRACE_DEBUG("p_new==NULL"); + return FALSE; + } + + if (!p_list->p_first) + { + /* this is an empty list */ + p_list->p_first = + p_list->p_last = p_new; + p_new->p_next = + p_new->p_prev = NULL; + } + else + { + p_old = p_list->p_first; + while (1) + { + if (p_old == NULL) + { + p_list->p_last->p_next = p_new; + p_new->p_prev = p_list->p_last; + p_new->p_next = NULL; + p_list->p_last = p_new; + + break; + + } + else + { + if (p_new->asgn_range.s_handle > p_old->asgn_range.s_handle) + { + if (p_old == p_list->p_first) + p_list->p_first = p_new; + + p_new->p_prev = p_old->p_prev; + p_new->p_next = p_old; + + + p_old->p_prev = p_new; + break; + } + } + p_old = p_old->p_next; + } + } + p_list->count++; + return TRUE; + +} + +/******************************************************************************* +** +** Function gatt_remove_an_item_from_list +** +** Description Remove an service handle range from the list +** +** Returns BOOLEAN TRUE-if remove is successful +** +*******************************************************************************/ +BOOLEAN gatt_remove_an_item_from_list(tGATT_HDL_LIST_INFO *p_list, tGATT_HDL_LIST_ELEM *p_remove) +{ + if (!p_remove || !p_list->p_first) + { + GATT_TRACE_DEBUG("p_remove==NULL || p_list->p_first==NULL"); + return FALSE; + } + + if (p_remove->p_prev == NULL) + { + p_list->p_first = p_remove->p_next; + if (p_remove->p_next) + p_remove->p_next->p_prev = NULL; + } + else if (p_remove->p_next == NULL) + { + p_list->p_last = p_remove->p_prev; + p_remove->p_prev->p_next = NULL; + } + else + { + p_remove->p_next->p_prev = p_remove->p_prev; + p_remove->p_prev->p_next = p_remove->p_next; + } + p_list->count--; + return TRUE; + +} + +/******************************************************************************* +** +** Function gatt_find_the_connected_bda +** +** Description This function find the connected bda +** +** Returns TRUE if found +** +*******************************************************************************/ +BOOLEAN gatt_find_the_connected_bda(UINT8 start_idx, BD_ADDR bda, UINT8 *p_found_idx, + tBT_TRANSPORT *p_transport) +{ + UINT8 i; + BOOLEAN found = FALSE; + GATT_TRACE_DEBUG("gatt_find_the_connected_bda start_idx=%d",start_idx); + + for (i = start_idx ; i < GATT_MAX_PHY_CHANNEL; i ++) + { + if (gatt_cb.tcb[i].in_use && gatt_cb.tcb[i].ch_state == GATT_CH_OPEN) + { + memcpy( bda, gatt_cb.tcb[i].peer_bda, BD_ADDR_LEN); + *p_found_idx = i; + *p_transport = gatt_cb.tcb[i].transport; + found = TRUE; + GATT_TRACE_DEBUG("gatt_find_the_connected_bda bda :%02x-%02x-%02x-%02x-%02x-%02x", + bda[0], bda[1], bda[2], bda[3], bda[4], bda[5]); + break; + } + } + GATT_TRACE_DEBUG("gatt_find_the_connected_bda found=%d found_idx=%d", found, i); + return found; +} + + + +/******************************************************************************* +** +** Function gatt_is_srv_chg_ind_pending +** +** Description Check whether a service chnaged is in the indication pending queue +** or waiting for an Ack already +** +** Returns BOOLEAN +** +*******************************************************************************/ +BOOLEAN gatt_is_srv_chg_ind_pending (tGATT_TCB *p_tcb) +{ + tGATT_VALUE *p_buf = (tGATT_VALUE *)GKI_getfirst(&p_tcb->pending_ind_q); + BOOLEAN srv_chg_ind_pending = FALSE; + + GATT_TRACE_DEBUG("gatt_is_srv_chg_ind_pending is_queue_empty=%d", GKI_queue_is_empty(&p_tcb->pending_ind_q) ); + + if (p_tcb->indicate_handle == gatt_cb.handle_of_h_r) + { + srv_chg_ind_pending = TRUE; + } + else + { + while (p_buf) + { + if (p_buf->handle == gatt_cb.handle_of_h_r) + { + srv_chg_ind_pending = TRUE; + break; + } + p_buf = (tGATT_VALUE *)GKI_getnext(p_buf); + } + } + + GATT_TRACE_DEBUG("srv_chg_ind_pending = %d", srv_chg_ind_pending); + return srv_chg_ind_pending; +} + + +/******************************************************************************* +** +** Function gatt_is_bda_in_the_srv_chg_clt_list +** +** Description This function check the specified bda is in the srv chg clinet list or not +** +** Returns pointer to the found elemenet otherwise NULL +** +*******************************************************************************/ +tGATTS_SRV_CHG *gatt_is_bda_in_the_srv_chg_clt_list (BD_ADDR bda) +{ + tGATTS_SRV_CHG *p_buf = (tGATTS_SRV_CHG *)GKI_getfirst(&gatt_cb.srv_chg_clt_q); + + GATT_TRACE_DEBUG("gatt_is_bda_in_the_srv_chg_clt_list :%02x-%02x-%02x-%02x-%02x-%02x", + bda[0], bda[1], bda[2], bda[3], bda[4], bda[5]); + + while (p_buf != NULL) + { + if (!memcmp( bda, p_buf->bda, BD_ADDR_LEN)) + { + GATT_TRACE_DEBUG("bda is in the srv chg clt list"); + break; + } + p_buf = (tGATTS_SRV_CHG *)GKI_getnext(p_buf); + } + + return p_buf; +} + + +/******************************************************************************* +** +** Function gatt_is_bda_connected +** +** Description +** +** Returns GATT_INDEX_INVALID if not found. Otherwise index to the tcb. +** +*******************************************************************************/ +BOOLEAN gatt_is_bda_connected(BD_ADDR bda) +{ + UINT8 i = 0; + BOOLEAN connected=FALSE; + + for ( i=0; i < GATT_MAX_PHY_CHANNEL; i ++) + { + if (gatt_cb.tcb[i].in_use && + !memcmp(gatt_cb.tcb[i].peer_bda, bda, BD_ADDR_LEN)) + { + connected = TRUE; + break; + } + } + return connected; +} + +/******************************************************************************* +** +** Function gatt_find_i_tcb_by_addr +** +** Description The function searches for an empty tcb entry, and return the index. +** +** Returns GATT_INDEX_INVALID if not found. Otherwise index to the tcb. +** +*******************************************************************************/ +UINT8 gatt_find_i_tcb_by_addr(BD_ADDR bda, tBT_TRANSPORT transport) +{ + UINT8 i = 0; + + for ( ; i < GATT_MAX_PHY_CHANNEL; i ++) + { + if (!memcmp(gatt_cb.tcb[i].peer_bda, bda, BD_ADDR_LEN) && + gatt_cb.tcb[i].transport == transport) + { + return i; + } + } + return GATT_INDEX_INVALID; +} + + +/******************************************************************************* +** +** Function gatt_get_tcb_by_idx +** +** Description The function get TCB using the TCB index +** +** Returns NULL if not found. Otherwise index to the tcb. +** +*******************************************************************************/ +tGATT_TCB * gatt_get_tcb_by_idx(UINT8 tcb_idx) +{ + tGATT_TCB *p_tcb = NULL; + + if ( (tcb_idx < GATT_MAX_PHY_CHANNEL) && gatt_cb.tcb[tcb_idx].in_use) + p_tcb = &gatt_cb.tcb[tcb_idx]; + + return p_tcb; +} + +/******************************************************************************* +** +** Function gatt_find_tcb_by_addr +** +** Description The function searches for an empty tcb entry, and return pointer. +** +** Returns NULL if not found. Otherwise index to the tcb. +** +*******************************************************************************/ +tGATT_TCB * gatt_find_tcb_by_addr(BD_ADDR bda, tBT_TRANSPORT transport) +{ + tGATT_TCB *p_tcb = NULL; + UINT8 i = 0; + + if ((i = gatt_find_i_tcb_by_addr(bda, transport)) != GATT_INDEX_INVALID) + p_tcb = &gatt_cb.tcb[i]; + + return p_tcb; +} +/******************************************************************************* +** +** Function gatt_find_i_tcb_free +** +** Description The function searches for an empty tcb entry, and return the index. +** +** Returns GATT_INDEX_INVALID if not found. Otherwise index to the tcb. +** +*******************************************************************************/ +UINT8 gatt_find_i_tcb_free(void) +{ + UINT8 i = 0, j = GATT_INDEX_INVALID; + + for (i = 0; i < GATT_MAX_PHY_CHANNEL; i ++) + { + if (!gatt_cb.tcb[i].in_use) + { + j = i; + break; + } + } + return j; +} +/******************************************************************************* +** +** Function gatt_allocate_tcb_by_bdaddr +** +** Description The function locate or allocate new tcb entry for matching bda. +** +** Returns GATT_INDEX_INVALID if not found. Otherwise index to the tcb. +** +*******************************************************************************/ +tGATT_TCB * gatt_allocate_tcb_by_bdaddr(BD_ADDR bda, tBT_TRANSPORT transport) +{ + UINT8 i = 0; + BOOLEAN allocated = FALSE; + tGATT_TCB *p_tcb = NULL; + + /* search for existing tcb with matching bda */ + i = gatt_find_i_tcb_by_addr(bda, transport); + /* find free tcb */ + if (i == GATT_INDEX_INVALID) + { + i = gatt_find_i_tcb_free(); + allocated = TRUE; + } + if (i != GATT_INDEX_INVALID) + { + p_tcb = &gatt_cb.tcb[i]; + + if (allocated) + { + memset(p_tcb, 0, sizeof(tGATT_TCB)); + GKI_init_q (&p_tcb->pending_enc_clcb); + GKI_init_q (&p_tcb->pending_ind_q); + p_tcb->in_use = TRUE; + p_tcb->tcb_idx = i; + p_tcb->transport = transport; + } + memcpy(p_tcb->peer_bda, bda, BD_ADDR_LEN); + } + return p_tcb; +} + +/******************************************************************************* +** +** Function gatt_convert_uuid16_to_uuid128 +** +** Description Convert a 16 bits UUID to be an standard 128 bits one. +** +** Returns TRUE if two uuid match; FALSE otherwise. +** +*******************************************************************************/ +void gatt_convert_uuid16_to_uuid128(UINT8 uuid_128[LEN_UUID_128], UINT16 uuid_16) +{ + UINT8 *p = &uuid_128[LEN_UUID_128 - 4]; + + memcpy (uuid_128, base_uuid, LEN_UUID_128); + + UINT16_TO_STREAM(p, uuid_16); +} + +/******************************************************************************* +** +** Function gatt_convert_uuid32_to_uuid128 +** +** Description Convert a 32 bits UUID to be an standard 128 bits one. +** +** Returns TRUE if two uuid match; FALSE otherwise. +** +*******************************************************************************/ +void gatt_convert_uuid32_to_uuid128(UINT8 uuid_128[LEN_UUID_128], UINT32 uuid_32) +{ + UINT8 *p = &uuid_128[LEN_UUID_128 - 4]; + + memcpy (uuid_128, base_uuid, LEN_UUID_128); + + UINT32_TO_STREAM(p, uuid_32); +} +/******************************************************************************* +** +** Function gatt_uuid_compare +** +** Description Compare two UUID to see if they are the same. +** +** Returns TRUE if two uuid match; FALSE otherwise. +** +*******************************************************************************/ +BOOLEAN gatt_uuid_compare (tBT_UUID src, tBT_UUID tar) +{ + UINT8 su[LEN_UUID_128], tu[LEN_UUID_128]; + UINT8 *ps, *pt; + + /* any of the UUID is unspecified */ + if (src.len == 0 || tar.len == 0) + { + return TRUE; + } + + /* If both are 16-bit, we can do a simple compare */ + if (src.len == LEN_UUID_16 && tar.len == LEN_UUID_16) + { + return src.uu.uuid16 == tar.uu.uuid16; + } + + /* If both are 32-bit, we can do a simple compare */ + if (src.len == LEN_UUID_32 && tar.len == LEN_UUID_32) + { + return src.uu.uuid32 == tar.uu.uuid32; + } + + /* One or both of the UUIDs is 128-bit */ + if (src.len == LEN_UUID_16) + { + /* convert a 16 bits UUID to 128 bits value */ + gatt_convert_uuid16_to_uuid128(su, src.uu.uuid16); + ps = su; + } + else if (src.len == LEN_UUID_32) + { + gatt_convert_uuid32_to_uuid128(su, src.uu.uuid32); + ps = su; + } + else + ps = src.uu.uuid128; + + if (tar.len == LEN_UUID_16) + { + /* convert a 16 bits UUID to 128 bits value */ + gatt_convert_uuid16_to_uuid128(tu, tar.uu.uuid16); + pt = tu; + } + else if (tar.len == LEN_UUID_32) + { + /* convert a 32 bits UUID to 128 bits value */ + gatt_convert_uuid32_to_uuid128(tu, tar.uu.uuid32); + pt = tu; + } + else + pt = tar.uu.uuid128; + + return(memcmp(ps, pt, LEN_UUID_128) == 0); +} + +/******************************************************************************* +** +** Function gatt_build_uuid_to_stream +** +** Description Add UUID into stream. +** +** Returns UUID length. +** +*******************************************************************************/ +UINT8 gatt_build_uuid_to_stream(UINT8 **p_dst, tBT_UUID uuid) +{ + UINT8 *p = *p_dst; + UINT8 len = 0; + + if (uuid.len == LEN_UUID_16) + { + UINT16_TO_STREAM (p, uuid.uu.uuid16); + len = LEN_UUID_16; + } + else if (uuid.len == LEN_UUID_32) /* always convert 32 bits into 128 bits as alwats */ + { + gatt_convert_uuid32_to_uuid128(p, uuid.uu.uuid32); + p += LEN_UUID_128; + len = LEN_UUID_128; + } + else if (uuid.len == LEN_UUID_128) + { + ARRAY_TO_STREAM (p, uuid.uu.uuid128, LEN_UUID_128); + len = LEN_UUID_128; + } + + *p_dst = p; + return len; +} + +/******************************************************************************* +** +** Function gatt_parse_uuid_from_cmd +** +** Description Convert a 128 bits UUID into a 16 bits UUID. +** +** Returns TRUE if command sent, otherwise FALSE. +** +*******************************************************************************/ +BOOLEAN gatt_parse_uuid_from_cmd(tBT_UUID *p_uuid_rec, UINT16 uuid_size, UINT8 **p_data) +{ + BOOLEAN is_base_uuid, ret = TRUE; + UINT8 xx; + UINT8 *p_uuid = *p_data; + + memset(p_uuid_rec, 0, sizeof(tBT_UUID)); + + switch (uuid_size) + { + case LEN_UUID_16: + p_uuid_rec->len = uuid_size; + STREAM_TO_UINT16 (p_uuid_rec->uu.uuid16, p_uuid); + *p_data += LEN_UUID_16; + break; + + case LEN_UUID_128: + /* See if we can compress his UUID down to 16 or 32bit UUIDs */ + is_base_uuid = TRUE; + for (xx = 0; xx < LEN_UUID_128 - 4; xx++) + { + if (p_uuid[xx] != base_uuid[xx]) + { + is_base_uuid = FALSE; + break; + } + } + if (is_base_uuid) + { + if ((p_uuid[LEN_UUID_128 - 1] == 0) && (p_uuid[LEN_UUID_128 - 2] == 0)) + { + p_uuid += (LEN_UUID_128 - 4); + p_uuid_rec->len = LEN_UUID_16; + STREAM_TO_UINT16(p_uuid_rec->uu.uuid16, p_uuid); + } + else + { + p_uuid += (LEN_UUID_128 - LEN_UUID_32); + p_uuid_rec->len = LEN_UUID_32; + STREAM_TO_UINT32(p_uuid_rec->uu.uuid32, p_uuid); + } + } + if (!is_base_uuid) + { + p_uuid_rec->len = LEN_UUID_128; + memcpy(p_uuid_rec->uu.uuid128, p_uuid, LEN_UUID_128); + } + *p_data += LEN_UUID_128; + break; + + /* do not allow 32 bits UUID in ATT PDU now */ + case LEN_UUID_32: + GATT_TRACE_ERROR("DO NOT ALLOW 32 BITS UUID IN ATT PDU"); + case 0: + default: + if (uuid_size != 0) ret = FALSE; + GATT_TRACE_WARNING("gatt_parse_uuid_from_cmd invalid uuid size"); + break; + } + + return( ret); +} + +/******************************************************************************* +** +** Function gatt_start_rsp_timer +** +** Description Start a wait_for_response timer. +** +** Returns TRUE if command sent, otherwise FALSE. +** +*******************************************************************************/ +void gatt_start_rsp_timer(UINT16 clcb_idx) +{ + tGATT_CLCB *p_clcb = &gatt_cb.clcb[clcb_idx]; + UINT32 timeout = GATT_WAIT_FOR_RSP_TOUT; + p_clcb->rsp_timer_ent.param = (TIMER_PARAM_TYPE)p_clcb; + if (p_clcb->operation == GATTC_OPTYPE_DISCOVERY && + p_clcb->op_subtype == GATT_DISC_SRVC_ALL) + { + timeout = GATT_WAIT_FOR_DISC_RSP_TOUT; + } + btu_start_timer (&p_clcb->rsp_timer_ent, BTU_TTYPE_ATT_WAIT_FOR_RSP, + timeout); +} +/******************************************************************************* +** +** Function gatt_start_conf_timer +** +** Description Start a wait_for_confirmation timer. +** +** Returns TRUE if command sent, otherwise FALSE. +** +*******************************************************************************/ +void gatt_start_conf_timer(tGATT_TCB *p_tcb) +{ + p_tcb->conf_timer_ent.param = (TIMER_PARAM_TYPE)p_tcb; + btu_start_timer (&p_tcb->conf_timer_ent, BTU_TTYPE_ATT_WAIT_FOR_RSP, + GATT_WAIT_FOR_RSP_TOUT); +} +/******************************************************************************* +** +** Function gatt_start_ind_ack_timer +** +** Description start the application ack timer +** +** Returns void +** +*******************************************************************************/ +void gatt_start_ind_ack_timer(tGATT_TCB *p_tcb) +{ + p_tcb->ind_ack_timer_ent.param = (TIMER_PARAM_TYPE)p_tcb; + /* start notification cache timer */ + btu_start_timer (&p_tcb->ind_ack_timer_ent, BTU_TTYPE_ATT_WAIT_FOR_IND_ACK, + GATT_WAIT_FOR_RSP_TOUT); + +} +/******************************************************************************* +** +** Function gatt_rsp_timeout +** +** Description Called when GATT wait for ATT command response timer expires +** +** Returns void +** +*******************************************************************************/ +void gatt_rsp_timeout(TIMER_LIST_ENT *p_tle) +{ + tGATT_CLCB *p_clcb = (tGATT_CLCB *)p_tle->param; + if (p_clcb == NULL || p_clcb->p_tcb == NULL) + { + GATT_TRACE_WARNING("gatt_rsp_timeout clcb is already deleted"); + return; + } + if (p_clcb->operation == GATTC_OPTYPE_DISCOVERY && + p_clcb->op_subtype == GATT_DISC_SRVC_ALL && + p_clcb->retry_count < GATT_REQ_RETRY_LIMIT) + { + UINT8 rsp_code; + GATT_TRACE_WARNING("gatt_rsp_timeout retry discovery primary service"); + if (p_clcb != gatt_cmd_dequeue(p_clcb->p_tcb, &rsp_code)) + { + GATT_TRACE_ERROR("gatt_rsp_timeout command queue out of sync, disconnect"); + } + else + { + p_clcb->retry_count++; + gatt_act_discovery(p_clcb); + return; + } + } + + GATT_TRACE_WARNING("gatt_rsp_timeout disconnecting..."); + gatt_disconnect (p_clcb->p_tcb); +} + +/******************************************************************************* +** +** Function gatt_ind_ack_timeout +** +** Description Called when GATT wait for ATT handle confirmation timeout +** +** Returns void +** +*******************************************************************************/ +void gatt_ind_ack_timeout(TIMER_LIST_ENT *p_tle) +{ + tGATT_TCB * p_tcb = (tGATT_TCB *)p_tle->param; + + GATT_TRACE_WARNING("gatt_ind_ack_timeout send ack now"); + + if (p_tcb != NULL) + p_tcb->ind_count = 0; + + attp_send_cl_msg(((tGATT_TCB *)p_tle->param), 0, GATT_HANDLE_VALUE_CONF, NULL); +} +/******************************************************************************* +** +** Function gatt_sr_find_i_rcb_by_handle +** +** Description The function searches for a service that owns a specific handle. +** +** Returns GATT_MAX_SR_PROFILES if not found. Otherwise index of th eservice. +** +*******************************************************************************/ +UINT8 gatt_sr_find_i_rcb_by_handle(UINT16 handle) +{ + UINT8 i_rcb = 0; + + for ( ; i_rcb < GATT_MAX_SR_PROFILES; i_rcb++) + { + if (gatt_cb.sr_reg[i_rcb].in_use && + gatt_cb.sr_reg[i_rcb].s_hdl <= handle && + gatt_cb.sr_reg[i_rcb].e_hdl >= handle ) + { + break; + } + } + return i_rcb; +} + +/******************************************************************************* +** +** Function gatt_sr_find_i_rcb_by_handle +** +** Description The function searches for a service that owns a specific handle. +** +** Returns 0 if not found. Otherwise index of th eservice. +** +*******************************************************************************/ +UINT8 gatt_sr_find_i_rcb_by_app_id(tBT_UUID *p_app_uuid128, tBT_UUID *p_svc_uuid, UINT16 svc_inst) +{ + UINT8 i_rcb = 0; + tGATT_SR_REG *p_sreg; + tBT_UUID *p_this_uuid; + + for (i_rcb = 0, p_sreg = gatt_cb.sr_reg; i_rcb < GATT_MAX_SR_PROFILES; i_rcb++, p_sreg++) + { + if ( p_sreg->in_use ) + { + p_this_uuid = gatts_get_service_uuid (p_sreg->p_db); + + if (p_this_uuid && + gatt_uuid_compare (*p_app_uuid128, p_sreg->app_uuid ) && + gatt_uuid_compare (*p_svc_uuid, *p_this_uuid) && + (svc_inst == p_sreg->service_instance)) + { + GATT_TRACE_ERROR ("Active Service Found "); + gatt_dbg_display_uuid(*p_svc_uuid); + + break; + } + } + } + return i_rcb; +} +/******************************************************************************* +** +** Function gatt_sr_find_i_rcb_by_handle +** +** Description The function searches for a service that owns a specific handle. +** +** Returns 0 if not found. Otherwise index of th eservice. +** +*******************************************************************************/ +UINT8 gatt_sr_alloc_rcb(tGATT_HDL_LIST_ELEM *p_list ) +{ + UINT8 ii = 0; + tGATT_SR_REG *p_sreg = NULL; + + /*this is a new application servoce start */ + for (ii = 0, p_sreg = gatt_cb.sr_reg; ii < GATT_MAX_SR_PROFILES; ii++, p_sreg++) + { + if (!p_sreg->in_use) + { + memset (p_sreg, 0, sizeof(tGATT_SR_REG)); + + p_sreg->in_use = TRUE; + memcpy (&p_sreg->app_uuid, &p_list->asgn_range.app_uuid128, sizeof(tBT_UUID)); + + p_sreg->service_instance = p_list->asgn_range.svc_inst; + p_sreg->type = p_list->asgn_range.is_primary ? GATT_UUID_PRI_SERVICE: GATT_UUID_SEC_SERVICE; + p_sreg->s_hdl = p_list->asgn_range.s_handle; + p_sreg->e_hdl = p_list->asgn_range.e_handle; + p_sreg->p_db = &p_list->svc_db; + + GATT_TRACE_DEBUG ("total GKI buffer in db [%d]",GKI_queue_length(&p_sreg->p_db->svc_buffer)); + break; + } + } + + return ii; +} +/******************************************************************************* +** +** Function gatt_sr_get_sec_info +** +** Description Get the security flag and key size information for the peer +** device. +** +** Returns void +** +*******************************************************************************/ +void gatt_sr_get_sec_info(BD_ADDR rem_bda, tBT_TRANSPORT transport, UINT8 *p_sec_flag, UINT8 *p_key_size) +{ + UINT8 sec_flag = 0; + + BTM_GetSecurityFlagsByTransport(rem_bda, &sec_flag, transport); + + sec_flag &= (GATT_SEC_FLAG_LKEY_UNAUTHED | GATT_SEC_FLAG_LKEY_AUTHED | GATT_SEC_FLAG_ENCRYPTED); + + *p_key_size = btm_ble_read_sec_key_size(rem_bda); + *p_sec_flag = sec_flag; +} +/******************************************************************************* +** +** Function gatt_sr_send_req_callback +** +** Description +** +** +** Returns void +** +*******************************************************************************/ +void gatt_sr_send_req_callback(UINT16 conn_id, + UINT32 trans_id, + tGATTS_REQ_TYPE type, tGATTS_DATA *p_data) +{ + tGATT_IF gatt_if = GATT_GET_GATT_IF(conn_id); + tGATT_REG *p_reg = gatt_get_regcb(gatt_if); + + if (!p_reg ) + { + GATT_TRACE_ERROR ("p_reg not found discard request"); + return; + } + + if ( p_reg->in_use && + p_reg->app_cb.p_req_cb) + { + (*p_reg->app_cb.p_req_cb)(conn_id, trans_id, type, p_data); + } + else + { + GATT_TRACE_WARNING("Call back not found for application conn_id=%d", conn_id); + } + +} + +/******************************************************************************* +** +** Function gatt_send_error_rsp +** +** Description This function sends an error response. +** +** Returns void +** +*******************************************************************************/ +tGATT_STATUS gatt_send_error_rsp (tGATT_TCB *p_tcb, UINT8 err_code, UINT8 op_code, + UINT16 handle, BOOLEAN deq) +{ + tGATT_ERROR error; + tGATT_STATUS status; + BT_HDR *p_buf; + + error.cmd_code = op_code; + error.reason = err_code; + error.handle =handle; + + if ((p_buf = attp_build_sr_msg(p_tcb, GATT_RSP_ERROR, (tGATT_SR_MSG *)&error)) != NULL) + { + status = attp_send_sr_msg (p_tcb, p_buf); + } + else + status = GATT_INSUF_RESOURCE; + + if (deq) + gatt_dequeue_sr_cmd(p_tcb); + + return status; +} + + +/******************************************************************************* +** +** Function gatt_add_sdp_record +** +** Description This function add a SDP record for a GATT primary service +** +** Returns 0 if error else sdp handle for the record. +** +*******************************************************************************/ +UINT32 gatt_add_sdp_record (tBT_UUID *p_uuid, UINT16 start_hdl, UINT16 end_hdl) +{ + tSDP_PROTOCOL_ELEM proto_elem_list[2]; + UINT32 sdp_handle; + UINT16 list = UUID_SERVCLASS_PUBLIC_BROWSE_GROUP; + UINT8 buff[60]; + UINT8 *p = buff; + + GATT_TRACE_DEBUG("gatt_add_sdp_record s_hdl=0x%x s_hdl=0x%x",start_hdl, end_hdl); + + if ((sdp_handle = SDP_CreateRecord()) == 0) + return 0; + + switch (p_uuid->len) + { + case LEN_UUID_16: + SDP_AddServiceClassIdList(sdp_handle, 1, &p_uuid->uu.uuid16); + break; + + case LEN_UUID_32: + UINT8_TO_BE_STREAM (p, (UUID_DESC_TYPE << 3) | SIZE_FOUR_BYTES); + UINT32_TO_BE_STREAM (p, p_uuid->uu.uuid32); + SDP_AddAttribute (sdp_handle, ATTR_ID_SERVICE_CLASS_ID_LIST, DATA_ELE_SEQ_DESC_TYPE, + (UINT32) (p - buff), buff); + break; + + case LEN_UUID_128: + UINT8_TO_BE_STREAM (p, (UUID_DESC_TYPE << 3) | SIZE_SIXTEEN_BYTES); + ARRAY_TO_BE_STREAM_REVERSE (p, p_uuid->uu.uuid128, LEN_UUID_128); + SDP_AddAttribute (sdp_handle, ATTR_ID_SERVICE_CLASS_ID_LIST, DATA_ELE_SEQ_DESC_TYPE, + (UINT32) (p - buff), buff); + break; + + default: + GATT_TRACE_ERROR("inavlid UUID len=%d", p_uuid->len); + SDP_DeleteRecord(sdp_handle); + return 0; + break; + } + + /*** Fill out the protocol element sequence for SDP ***/ + proto_elem_list[0].protocol_uuid = UUID_PROTOCOL_L2CAP; + proto_elem_list[0].num_params = 1; + proto_elem_list[0].params[0] = BT_PSM_ATT; + proto_elem_list[1].protocol_uuid = UUID_PROTOCOL_ATT; + proto_elem_list[1].num_params = 2; + proto_elem_list[1].params[0] = start_hdl; + proto_elem_list[1].params[1] = end_hdl; + + SDP_AddProtocolList(sdp_handle, 2, proto_elem_list); + + /* Make the service browseable */ + SDP_AddUuidSequence (sdp_handle, ATTR_ID_BROWSE_GROUP_LIST, 1, &list); + + return(sdp_handle); +} + + + #if GATT_CONFORMANCE_TESTING == TRUE +/******************************************************************************* +** +** Function gatt_set_err_rsp +** +** Description This function is called to set the test confirm value +** +** Returns void +** +*******************************************************************************/ +void gatt_set_err_rsp(BOOLEAN enable, UINT8 req_op_code, UINT8 err_status) +{ + GATT_TRACE_DEBUG("gatt_set_err_rsp enable=%d op_code=%d, err_status=%d", enable, req_op_code, err_status); + gatt_cb.enable_err_rsp = enable; + gatt_cb.req_op_code = req_op_code; + gatt_cb.err_status = err_status; +} + #endif + + + +/******************************************************************************* +** +** Function gatt_get_regcb +** +** Description The function returns the registration control block. +** +** Returns pointer to the registration control block or NULL +** +*******************************************************************************/ +tGATT_REG *gatt_get_regcb (tGATT_IF gatt_if) +{ + UINT8 ii = (UINT8)gatt_if; + tGATT_REG *p_reg = NULL; + + if (ii < 1 || ii > GATT_MAX_APPS) { + GATT_TRACE_WARNING("gatt_if out of range [ = %d]", ii); + return NULL; + } + + // Index for cl_rcb is always 1 less than gatt_if. + p_reg = &gatt_cb.cl_rcb[ii - 1]; + + if (!p_reg->in_use) { + GATT_TRACE_WARNING("gatt_if found but not in use."); + return NULL; + } + + return p_reg; +} + + +/******************************************************************************* +** +** Function gatt_is_clcb_allocated +** +** Description The function check clcb for conn_id is allocated or not +** +** Returns True already allocated +** +*******************************************************************************/ + +BOOLEAN gatt_is_clcb_allocated (UINT16 conn_id) +{ + UINT8 i = 0; + BOOLEAN is_allocated= FALSE; + + for (i = 0; i < GATT_CL_MAX_LCB; i++) + { + if (gatt_cb.clcb[i].in_use && (gatt_cb.clcb[i].conn_id == conn_id)) + { + is_allocated = TRUE; + break; + } + } + + return is_allocated; +} + +/******************************************************************************* +** +** Function gatt_clcb_alloc +** +** Description The function allocates a GATT connection link control block +** +** Returns NULL if not found. Otherwise pointer to the connection link block. +** +*******************************************************************************/ +tGATT_CLCB *gatt_clcb_alloc (UINT16 conn_id) +{ + UINT8 i = 0; + tGATT_CLCB *p_clcb = NULL; + tGATT_IF gatt_if=GATT_GET_GATT_IF(conn_id); + UINT8 tcb_idx = GATT_GET_TCB_IDX(conn_id); + tGATT_TCB *p_tcb = gatt_get_tcb_by_idx(tcb_idx); + tGATT_REG *p_reg = gatt_get_regcb(gatt_if); + + for (i = 0; i < GATT_CL_MAX_LCB; i++) + { + if (!gatt_cb.clcb[i].in_use) + { + p_clcb = &gatt_cb.clcb[i]; + + p_clcb->in_use = TRUE; + p_clcb->conn_id = conn_id; + p_clcb->clcb_idx = i; + p_clcb->p_reg = p_reg; + p_clcb->p_tcb = p_tcb; + break; + } + } + return p_clcb; +} + +/******************************************************************************* +** +** Function gatt_clcb_dealloc +** +** Description The function de allocates a GATT connection link control block +** +** Returns None +** +*******************************************************************************/ +void gatt_clcb_dealloc (tGATT_CLCB *p_clcb) +{ + if (p_clcb && p_clcb->in_use) + { + memset(p_clcb, 0, sizeof(tGATT_CLCB)); + } +} + + + +/******************************************************************************* +** +** Function gatt_find_tcb_by_cid +** +** Description The function searches for an empty entry +** in registration info table for GATT client +** +** Returns NULL if not found. Otherwise pointer to the rcb. +** +*******************************************************************************/ +tGATT_TCB * gatt_find_tcb_by_cid (UINT16 lcid) +{ + UINT16 xx = 0; + tGATT_TCB *p_tcb = NULL; + + for (xx = 0; xx < GATT_MAX_PHY_CHANNEL; xx++) + { + if (gatt_cb.tcb[xx].in_use && gatt_cb.tcb[xx].att_lcid == lcid) + { + p_tcb = &gatt_cb.tcb[xx]; + break; + } + } + return p_tcb; +} + + +/******************************************************************************* +** +** Function gatt_num_apps_hold_link +** +** Description The function find the number of applcaitions is holding the link +** +** Returns total number of applications holding this acl link. +** +*******************************************************************************/ +UINT8 gatt_num_apps_hold_link(tGATT_TCB *p_tcb) +{ + UINT8 i, num = 0; + + for (i = 0; i < GATT_MAX_APPS; i ++) + { + if (p_tcb->app_hold_link[i]) + num ++; + } + + GATT_TRACE_DEBUG("gatt_num_apps_hold_link num=%d", num); + return num; +} + + +/******************************************************************************* +** +** Function gatt_num_clcb_by_bd_addr +** +** Description The function searches all LCB with macthing bd address +** +** Returns total number of clcb found. +** +*******************************************************************************/ +UINT8 gatt_num_clcb_by_bd_addr(BD_ADDR bda) +{ + UINT8 i, num = 0; + + for (i = 0; i < GATT_CL_MAX_LCB; i ++) + { + if (gatt_cb.clcb[i].in_use && memcmp(gatt_cb.clcb[i].p_tcb->peer_bda, bda, BD_ADDR_LEN) == 0) + num ++; + } + return num; +} + +/******************************************************************************* +** +** Function gatt_sr_update_cback_cnt +** +** Description The function searches all LCB with macthing bd address +** +** Returns total number of clcb found. +** +*******************************************************************************/ +void gatt_sr_copy_prep_cnt_to_cback_cnt(tGATT_TCB *p_tcb ) +{ + UINT8 i; + + if (p_tcb) + { + for (i = 0; i < GATT_MAX_APPS; i ++) + { + if (p_tcb->prep_cnt[i]) + { + p_tcb->sr_cmd.cback_cnt[i]=1; + } + } + } + +} + +/******************************************************************************* +** +** Function gatt_sr_is_cback_cnt_zero +** +** Description The function searches all LCB with macthing bd address +** +** Returns True if thetotal application callback count is zero +** +*******************************************************************************/ +BOOLEAN gatt_sr_is_cback_cnt_zero(tGATT_TCB *p_tcb ) +{ + BOOLEAN status = TRUE; + UINT8 i; + + if (p_tcb) + { + for (i = 0; i < GATT_MAX_APPS; i ++) + { + if (p_tcb->sr_cmd.cback_cnt[i]) + { + status = FALSE; + break; + } + } + } + else + { + status = FALSE; + } + return status; +} + +/******************************************************************************* +** +** Function gatt_sr_is_prep_cnt_zero +** +** Description Check the prepare write request count is zero or not +** +** Returns True no prepare write request +** +*******************************************************************************/ +BOOLEAN gatt_sr_is_prep_cnt_zero(tGATT_TCB *p_tcb) +{ + BOOLEAN status = TRUE; + UINT8 i; + + if (p_tcb) + { + for (i = 0; i < GATT_MAX_APPS; i ++) + { + if (p_tcb->prep_cnt[i]) + { + status = FALSE; + break; + } + } + } + else + { + status = FALSE; + } + return status; +} + + +/******************************************************************************* +** +** Function gatt_sr_reset_cback_cnt +** +** Description Reset the application callback count to zero +** +** Returns None +** +*******************************************************************************/ +void gatt_sr_reset_cback_cnt(tGATT_TCB *p_tcb ) +{ + UINT8 i; + + if (p_tcb) + { + for (i = 0; i < GATT_MAX_APPS; i ++) + { + p_tcb->sr_cmd.cback_cnt[i]=0; + } + } +} + +/******************************************************************************* +** +** Function gatt_sr_reset_prep_cnt +** +** Description Reset the prep write count to zero +** +** Returns None +** +*******************************************************************************/ +void gatt_sr_reset_prep_cnt(tGATT_TCB *p_tcb ) +{ + UINT8 i; + if (p_tcb) + { + for (i = 0; i < GATT_MAX_APPS; i ++) + { + p_tcb->prep_cnt[i]=0; + } + } +} + + +/******************************************************************************* +** +** Function gatt_sr_update_cback_cnt +** +** Description Update the teh applicaiton callback count +** +** Returns None +** +*******************************************************************************/ +void gatt_sr_update_cback_cnt(tGATT_TCB *p_tcb, tGATT_IF gatt_if, BOOLEAN is_inc, BOOLEAN is_reset_first) +{ + + UINT8 idx = ((UINT8) gatt_if) - 1 ; + + if (p_tcb) + { + if (is_reset_first) + { + gatt_sr_reset_cback_cnt(p_tcb); + } + if (is_inc) + { + p_tcb->sr_cmd.cback_cnt[idx]++; + } + else + { + if ( p_tcb->sr_cmd.cback_cnt[idx]) + { + p_tcb->sr_cmd.cback_cnt[idx]--; + } + } + } +} + + +/******************************************************************************* +** +** Function gatt_sr_update_prep_cnt +** +** Description Update the teh prepare write request count +** +** Returns None +** +*******************************************************************************/ +void gatt_sr_update_prep_cnt(tGATT_TCB *p_tcb, tGATT_IF gatt_if, BOOLEAN is_inc, BOOLEAN is_reset_first) +{ + UINT8 idx = ((UINT8) gatt_if) - 1 ; + + GATT_TRACE_DEBUG("gatt_sr_update_prep_cnt tcb idx=%d gatt_if=%d is_inc=%d is_reset_first=%d", + p_tcb->tcb_idx, gatt_if, is_inc, is_reset_first); + + if (p_tcb) + { + if (is_reset_first) + { + gatt_sr_reset_prep_cnt(p_tcb); + } + if (is_inc) + { + p_tcb->prep_cnt[idx]++; + } + else + { + if (p_tcb->prep_cnt[idx]) + { + p_tcb->prep_cnt[idx]--; + } + } + } +} +/******************************************************************************* +** +** Function gatt_cancel_open +** +** Description Cancel open request +** +** Returns Boolean +** +*******************************************************************************/ +BOOLEAN gatt_cancel_open(tGATT_IF gatt_if, BD_ADDR bda) +{ + tGATT_TCB *p_tcb=NULL; + BOOLEAN status= TRUE; + + p_tcb = gatt_find_tcb_by_addr(bda, BT_TRANSPORT_LE); + + if (p_tcb) + { + if (gatt_get_ch_state(p_tcb) == GATT_CH_OPEN) + { + GATT_TRACE_ERROR("GATT_CancelConnect - link connected Too late to cancel"); + status = FALSE; + } + else + { + gatt_update_app_use_link_flag(gatt_if, p_tcb, FALSE, FALSE); + if (!gatt_num_apps_hold_link(p_tcb)) + { + gatt_disconnect(p_tcb); + } + } + } + + return status; +} + +/******************************************************************************* +** +** Function gatt_find_app_hold_link +** +** Description find the applicaiton that is holding the specified link +** +** Returns Boolean +** +*******************************************************************************/ +BOOLEAN gatt_find_app_hold_link(tGATT_TCB *p_tcb, UINT8 start_idx, UINT8 *p_found_idx, tGATT_IF *p_gatt_if) +{ + UINT8 i; + BOOLEAN found= FALSE; + + for (i = start_idx; i < GATT_MAX_APPS; i ++) + { + if (p_tcb->app_hold_link[i]) + { + *p_gatt_if = gatt_cb.clcb[i].p_reg->gatt_if; + *p_found_idx = i; + found = TRUE; + break; + } + } + return found; +} + +/******************************************************************************* +** +** Function gatt_cmd_enq +** +** Description Enqueue this command. +** +** Returns None. +** +*******************************************************************************/ +BOOLEAN gatt_cmd_enq(tGATT_TCB *p_tcb, UINT16 clcb_idx, BOOLEAN to_send, UINT8 op_code, BT_HDR *p_buf) +{ + tGATT_CMD_Q *p_cmd = &p_tcb->cl_cmd_q[p_tcb->next_slot_inq]; + + p_cmd->to_send = to_send; /* waiting to be sent */ + p_cmd->op_code = op_code; + p_cmd->p_cmd = p_buf; + p_cmd->clcb_idx = clcb_idx; + + if (!to_send) + { + p_tcb->pending_cl_req = p_tcb->next_slot_inq; + } + + p_tcb->next_slot_inq ++; + p_tcb->next_slot_inq %= GATT_CL_MAX_LCB; + + return TRUE; +} + +/******************************************************************************* +** +** Function gatt_cmd_dequeue +** +** Description dequeue the command in the client CCB command queue. +** +** Returns total number of clcb found. +** +*******************************************************************************/ +tGATT_CLCB * gatt_cmd_dequeue(tGATT_TCB *p_tcb, UINT8 *p_op_code) +{ + tGATT_CMD_Q *p_cmd = &p_tcb->cl_cmd_q[p_tcb->pending_cl_req]; + tGATT_CLCB *p_clcb = NULL; + + if (p_tcb->pending_cl_req != p_tcb->next_slot_inq) + { + p_clcb = &gatt_cb.clcb[p_cmd->clcb_idx]; + + *p_op_code = p_cmd->op_code; + + p_tcb->pending_cl_req ++; + p_tcb->pending_cl_req %= GATT_CL_MAX_LCB; + } + + return p_clcb; +} + +/******************************************************************************* +** +** Function gatt_send_write_msg +** +** Description This real function send out the ATT message for write. +** +** Returns status code +** +*******************************************************************************/ +UINT8 gatt_send_write_msg (tGATT_TCB *p_tcb, UINT16 clcb_idx, UINT8 op_code, + UINT16 handle, UINT16 len, + UINT16 offset, UINT8 *p_data) +{ + tGATT_CL_MSG msg; + + msg.attr_value.handle = handle; + msg.attr_value.len = len; + msg.attr_value.offset = offset; + + memcpy (msg.attr_value.value, p_data, len); + + /* write by handle */ + return attp_send_cl_msg(p_tcb, clcb_idx, op_code, &msg); +} + +/******************************************************************************* +** +** Function gatt_act_send_browse +** +** Description This function ends a browse command request, including read +** information request and read by type request. +** +** Returns status code +** +*******************************************************************************/ +UINT8 gatt_act_send_browse(tGATT_TCB *p_tcb, UINT16 index, UINT8 op, UINT16 s_handle, + UINT16 e_handle, tBT_UUID uuid) +{ + tGATT_CL_MSG msg; + + msg.browse.s_handle = s_handle; + msg.browse.e_handle = e_handle; + memcpy(&msg.browse.uuid, &uuid, sizeof(tBT_UUID)); + + /* write by handle */ + return attp_send_cl_msg(p_tcb, index, op, &msg); +} + +/******************************************************************************* +** +** Function gatt_end_operation +** +** Description This function ends a discovery, send callback and finalize +** some control value. +** +** Returns 16 bits uuid. +** +*******************************************************************************/ +void gatt_end_operation(tGATT_CLCB *p_clcb, tGATT_STATUS status, void *p_data) +{ + tGATT_CL_COMPLETE cb_data; + tGATT_CMPL_CBACK *p_cmpl_cb = (p_clcb->p_reg) ? p_clcb->p_reg->app_cb.p_cmpl_cb : NULL; + UINT8 op = p_clcb->operation, disc_type=GATT_DISC_MAX; + tGATT_DISC_CMPL_CB *p_disc_cmpl_cb = (p_clcb->p_reg) ? p_clcb->p_reg->app_cb.p_disc_cmpl_cb : NULL; + UINT16 conn_id; + UINT8 operation; + + GATT_TRACE_DEBUG ("gatt_end_operation status=%d op=%d subtype=%d", + status, p_clcb->operation, p_clcb->op_subtype); + memset(&cb_data.att_value, 0, sizeof(tGATT_VALUE)); + + if (p_cmpl_cb != NULL && p_clcb->operation != 0) + { + if (p_clcb->operation == GATTC_OPTYPE_READ) + { + cb_data.att_value.handle = p_clcb->s_handle; + cb_data.att_value.len = p_clcb->counter; + + if (p_data && p_clcb->counter) + memcpy (cb_data.att_value.value, p_data, cb_data.att_value.len); + } + + if (p_clcb->operation == GATTC_OPTYPE_WRITE) + { + memset(&cb_data.att_value, 0, sizeof(tGATT_VALUE)); + cb_data.handle = + cb_data.att_value.handle = p_clcb->s_handle; + if (p_clcb->op_subtype == GATT_WRITE_PREPARE) + { + if (p_data) + { + cb_data.att_value = *((tGATT_VALUE *) p_data); + } + else + { + GATT_TRACE_DEBUG("Rcv Prepare write rsp but no data"); + } + } + } + + if (p_clcb->operation == GATTC_OPTYPE_CONFIG) + cb_data.mtu = p_clcb->p_tcb->payload_size; + + if (p_clcb->operation == GATTC_OPTYPE_DISCOVERY) + { + disc_type = p_clcb->op_subtype; + } + } + + if (p_clcb->p_attr_buf) + { + GKI_freebuf(p_clcb->p_attr_buf); + } + + operation = p_clcb->operation; + conn_id = p_clcb->conn_id; + btu_stop_timer(&p_clcb->rsp_timer_ent); + + gatt_clcb_dealloc(p_clcb); + + if (p_disc_cmpl_cb && (op == GATTC_OPTYPE_DISCOVERY)) + (*p_disc_cmpl_cb)(conn_id, disc_type, status); + else if (p_cmpl_cb && op) + (*p_cmpl_cb)(conn_id, op, status, &cb_data); + else + GATT_TRACE_WARNING ("gatt_end_operation not sent out op=%d p_disc_cmpl_cb:%p p_cmpl_cb:%p", + operation, p_disc_cmpl_cb, p_cmpl_cb); +} + +/******************************************************************************* +** +** Function gatt_cleanup_upon_disc +** +** Description This function cleans up the control blocks when L2CAP channel +** disconnect. +** +** Returns 16 bits uuid. +** +*******************************************************************************/ +void gatt_cleanup_upon_disc(BD_ADDR bda, UINT16 reason, tBT_TRANSPORT transport) +{ + tGATT_TCB *p_tcb = NULL; + tGATT_CLCB *p_clcb; + UINT8 i; + UINT16 conn_id; + tGATT_REG *p_reg=NULL; + + + GATT_TRACE_DEBUG ("gatt_cleanup_upon_disc "); + + if ((p_tcb = gatt_find_tcb_by_addr(bda, transport)) != NULL) + { + GATT_TRACE_DEBUG ("found p_tcb "); + gatt_set_ch_state(p_tcb, GATT_CH_CLOSE); + for (i = 0; i < GATT_CL_MAX_LCB; i ++) + { + p_clcb = &gatt_cb.clcb[i]; + if (p_clcb->in_use && p_clcb->p_tcb == p_tcb) + { + btu_stop_timer(&p_clcb->rsp_timer_ent); + GATT_TRACE_DEBUG ("found p_clcb conn_id=%d clcb_idx=%d", p_clcb->conn_id, p_clcb->clcb_idx); + if (p_clcb->operation != GATTC_OPTYPE_NONE) + gatt_end_operation(p_clcb, GATT_ERROR, NULL); + + gatt_clcb_dealloc(p_clcb); + + } + } + + btu_stop_timer (&p_tcb->ind_ack_timer_ent); + btu_stop_timer (&p_tcb->conf_timer_ent); + gatt_free_pending_ind(p_tcb); + gatt_free_pending_enc_queue(p_tcb); + + for (i = 0; i < GATT_MAX_APPS; i ++) + { + p_reg = &gatt_cb.cl_rcb[i]; + if (p_reg->in_use && p_reg->app_cb.p_conn_cb) + { + conn_id = GATT_CREATE_CONN_ID(p_tcb->tcb_idx, p_reg->gatt_if); + GATT_TRACE_DEBUG ("found p_reg tcb_idx=%d gatt_if=%d conn_id=0x%x", p_tcb->tcb_idx, p_reg->gatt_if, conn_id); + (*p_reg->app_cb.p_conn_cb)(p_reg->gatt_if, bda, conn_id, FALSE, reason, transport); + } + } + memset(p_tcb, 0, sizeof(tGATT_TCB)); + + } + GATT_TRACE_DEBUG ("exit gatt_cleanup_upon_disc "); +} +/******************************************************************************* +** +** Function gatt_dbg_req_op_name +** +** Description Get op code description name, for debug information. +** +** Returns UINT8 *: name of the operation. +** +*******************************************************************************/ +UINT8 * gatt_dbg_op_name(UINT8 op_code) +{ + UINT8 pseduo_op_code_idx = op_code & (~GATT_WRITE_CMD_MASK); + + if (op_code == GATT_CMD_WRITE ) + { + pseduo_op_code_idx = 0x14; /* just an index to op_code_name */ + + } + + if (op_code == GATT_SIGN_CMD_WRITE) + { + pseduo_op_code_idx = 0x15; /* just an index to op_code_name */ + } + + if (pseduo_op_code_idx <= GATT_OP_CODE_MAX) + return(UINT8*) op_code_name[pseduo_op_code_idx]; + else + return(UINT8 *)"Op Code Exceed Max"; +} + +/******************************************************************************* +** +** Function gatt_dbg_display_uuid +** +** Description Disaplay the UUID +** +** Returns None +** +*******************************************************************************/ +void gatt_dbg_display_uuid(tBT_UUID bt_uuid) +{ + char str_buf[50]; + int x = 0; + + if (bt_uuid.len == LEN_UUID_16) + { + sprintf(str_buf, "0x%04x", bt_uuid.uu.uuid16); + } + else if (bt_uuid.len == LEN_UUID_32) + { + sprintf(str_buf, "0x%08x", (unsigned int)bt_uuid.uu.uuid32); + } + else if (bt_uuid.len == LEN_UUID_128) + { + x += sprintf(&str_buf[x], "0x%02x%02x%02x%02x%02x%02x%02x%02x", + bt_uuid.uu.uuid128[15], bt_uuid.uu.uuid128[14], + bt_uuid.uu.uuid128[13], bt_uuid.uu.uuid128[12], + bt_uuid.uu.uuid128[11], bt_uuid.uu.uuid128[10], + bt_uuid.uu.uuid128[9], bt_uuid.uu.uuid128[8]); + sprintf(&str_buf[x], "%02x%02x%02x%02x%02x%02x%02x%02x", + bt_uuid.uu.uuid128[7], bt_uuid.uu.uuid128[6], + bt_uuid.uu.uuid128[5], bt_uuid.uu.uuid128[4], + bt_uuid.uu.uuid128[3], bt_uuid.uu.uuid128[2], + bt_uuid.uu.uuid128[1], bt_uuid.uu.uuid128[0]); + } + else + BCM_STRNCPY_S(str_buf, sizeof(str_buf), "Unknown UUID 0", 15); + + GATT_TRACE_DEBUG ("UUID=[%s]", str_buf); + +} + + +/******************************************************************************* +** +** Function gatt_is_bg_dev_for_app +** +** Description find is this one of the background devices for the application +** +** Returns TRUE this is one of the background devices for the application +** +*******************************************************************************/ +BOOLEAN gatt_is_bg_dev_for_app(tGATT_BG_CONN_DEV *p_dev, tGATT_IF gatt_if) +{ + UINT8 i; + + for (i = 0; i < GATT_MAX_APPS; i ++ ) + { + if (p_dev->in_use && (p_dev->gatt_if[i] == gatt_if)) + { + return TRUE; + } + } + return FALSE; +} +/******************************************************************************* +** +** Function gatt_find_bg_dev +** +** Description find background connection device from the list. +** +** Returns pointer to the device record +** +*******************************************************************************/ +tGATT_BG_CONN_DEV * gatt_find_bg_dev(BD_ADDR remote_bda) +{ + tGATT_BG_CONN_DEV *p_dev_list = &gatt_cb.bgconn_dev[0]; + UINT8 i; + + for (i = 0; i < GATT_MAX_BG_CONN_DEV; i ++, p_dev_list ++) + { + if (p_dev_list->in_use && !memcmp(p_dev_list->remote_bda, remote_bda, BD_ADDR_LEN)) + { + return p_dev_list; + } + } + return NULL; +} +/******************************************************************************* +** +** Function gatt_alloc_bg_dev +** +** Description allocate a background connection device record +** +** Returns pointer to the device record +** +*******************************************************************************/ +tGATT_BG_CONN_DEV * gatt_alloc_bg_dev(BD_ADDR remote_bda) +{ + tGATT_BG_CONN_DEV *p_dev_list = &gatt_cb.bgconn_dev[0]; + UINT8 i; + + for (i = 0; i < GATT_MAX_BG_CONN_DEV; i ++, p_dev_list ++) + { + if (!p_dev_list->in_use) + { + p_dev_list->in_use = TRUE; + memcpy(p_dev_list->remote_bda, remote_bda, BD_ADDR_LEN); + + return p_dev_list; + } + } + return NULL; +} + +/******************************************************************************* +** +** Function gatt_add_bg_dev_list +** +** Description add/remove device from the back ground connection device list +** +** Returns TRUE if device added to the list; FALSE failed +** +*******************************************************************************/ +BOOLEAN gatt_add_bg_dev_list(tGATT_REG *p_reg, BD_ADDR bd_addr, BOOLEAN is_initator) +{ + tGATT_IF gatt_if = p_reg->gatt_if; + tGATT_BG_CONN_DEV *p_dev = NULL; + UINT8 i; + BOOLEAN ret = FALSE; + + if ((p_dev = gatt_find_bg_dev(bd_addr)) == NULL) + { + p_dev = gatt_alloc_bg_dev(bd_addr); + } + + if (p_dev) + { + for (i = 0; i < GATT_MAX_APPS; i ++) + { + if (is_initator) + { + if (p_dev->gatt_if[i] == gatt_if) + { + GATT_TRACE_ERROR("device already in iniator white list"); + return TRUE; + } + else if (p_dev->gatt_if[i] == 0) + { + p_dev->gatt_if[i] = gatt_if; + if (i == 0) + ret = BTM_BleUpdateBgConnDev(TRUE, bd_addr); + else + ret = TRUE; + break; + } + } + else + { + if (p_dev->listen_gif[i] == gatt_if) + { + GATT_TRACE_ERROR("device already in adv white list"); + return TRUE; + } + else if (p_dev->listen_gif[i] == 0) + { + if (p_reg->listening == GATT_LISTEN_TO_ALL) + p_reg->listening = GATT_LISTEN_TO_NONE; + + p_reg->listening ++; + p_dev->listen_gif[i] = gatt_if; + + if (i == 0) + ret = BTM_BleUpdateAdvWhitelist(TRUE, bd_addr); + else + ret = TRUE; + break; + } + } + } + } + else + { + GATT_TRACE_ERROR("no device record available"); + } + + return ret; +} + +/******************************************************************************* +** +** Function gatt_remove_bg_dev_for_app +** +** Description Remove the application interface for the specified background device +** +** Returns Boolean +** +*******************************************************************************/ +BOOLEAN gatt_remove_bg_dev_for_app(tGATT_IF gatt_if, BD_ADDR bd_addr) +{ + tGATT_TCB *p_tcb = gatt_find_tcb_by_addr(bd_addr, BT_TRANSPORT_LE); + BOOLEAN status; + + if (p_tcb) + gatt_update_app_use_link_flag(gatt_if, p_tcb, FALSE, FALSE); + status = gatt_update_auto_connect_dev(gatt_if, FALSE, bd_addr, TRUE); + return status; +} + + +/******************************************************************************* +** +** Function gatt_get_num_apps_for_bg_dev +** +** Description Gte the number of applciations for the specified background device +** +** Returns UINT8 total number fo applications +** +*******************************************************************************/ +UINT8 gatt_get_num_apps_for_bg_dev(BD_ADDR bd_addr) +{ + tGATT_BG_CONN_DEV *p_dev = NULL; + UINT8 i; + UINT8 cnt = 0; + + if ((p_dev = gatt_find_bg_dev(bd_addr)) != NULL) + { + for (i = 0; i < GATT_MAX_APPS; i ++) + { + if (p_dev->gatt_if[i]) + cnt++; + } + } + return cnt; +} + +/******************************************************************************* +** +** Function gatt_find_app_for_bg_dev +** +** Description find the application interface for the specified background device +** +** Returns Boolean +** +*******************************************************************************/ +BOOLEAN gatt_find_app_for_bg_dev(BD_ADDR bd_addr, tGATT_IF *p_gatt_if) +{ + tGATT_BG_CONN_DEV *p_dev = NULL; + UINT8 i; + BOOLEAN ret = FALSE; + + if ((p_dev = gatt_find_bg_dev(bd_addr)) == NULL) + { + return ret; + } + + for (i = 0; i < GATT_MAX_APPS; i ++) + { + if (p_dev->gatt_if[i] != 0 ) + { + *p_gatt_if = p_dev->gatt_if[i]; + ret = TRUE; + break; + } + } + return ret; +} + + +/******************************************************************************* +** +** Function gatt_remove_bg_dev_from_list +** +** Description add/remove device from the back ground connection device list or +** listening to advertising list. +** +** Returns pointer to the device record +** +*******************************************************************************/ +BOOLEAN gatt_remove_bg_dev_from_list(tGATT_REG *p_reg, BD_ADDR bd_addr, BOOLEAN is_initiator) +{ + tGATT_IF gatt_if = p_reg->gatt_if; + tGATT_BG_CONN_DEV *p_dev = NULL; + UINT8 i, j; + BOOLEAN ret = FALSE; + + if ((p_dev = gatt_find_bg_dev(bd_addr)) == NULL) + { + return ret; + } + + for (i = 0; i < GATT_MAX_APPS && (p_dev->gatt_if[i] > 0 || p_dev->listen_gif[i]); i ++) + { + if (is_initiator) + { + if (p_dev->gatt_if[i] == gatt_if) + { + p_dev->gatt_if[i] = 0; + /* move all element behind one forward */ + for (j = i + 1; j < GATT_MAX_APPS; j ++) + p_dev->gatt_if[j - 1] = p_dev->gatt_if[j]; + + if (p_dev->gatt_if[0] == 0) + ret = BTM_BleUpdateBgConnDev(FALSE, p_dev->remote_bda); + else + ret = TRUE; + + break; + } + } + else + { + if (p_dev->listen_gif[i] == gatt_if) + { + p_dev->listen_gif[i] = 0; + p_reg->listening --; + /* move all element behind one forward */ + for (j = i + 1; j < GATT_MAX_APPS; j ++) + p_dev->listen_gif[j - 1] = p_dev->listen_gif[j]; + + if (p_dev->listen_gif[0] == 0) + ret = BTM_BleUpdateAdvWhitelist(FALSE, p_dev->remote_bda); + else + ret = TRUE; + break; + } + } + } + + if (i != GATT_MAX_APPS && p_dev->gatt_if[0] == 0 && p_dev->listen_gif[0] == 0) + { + memset(p_dev, 0, sizeof(tGATT_BG_CONN_DEV)); + } + + return ret; +} +/******************************************************************************* +** +** Function gatt_deregister_bgdev_list +** +** Description deregister all related back ground connetion device. +** +** Returns pointer to the device record +** +*******************************************************************************/ +void gatt_deregister_bgdev_list(tGATT_IF gatt_if) +{ + tGATT_BG_CONN_DEV *p_dev_list = &gatt_cb.bgconn_dev[0]; + UINT8 i , j, k; + tGATT_REG *p_reg = gatt_get_regcb(gatt_if); + + /* update the BG conn device list */ + for (i = 0 ; i in_use) + { + for (j = 0; j < GATT_MAX_APPS; j ++) + { + if (p_dev_list->gatt_if[j] == 0 && p_dev_list->listen_gif[j] == 0) + break; + + if (p_dev_list->gatt_if[j] == gatt_if) + { + for (k = j + 1; k < GATT_MAX_APPS; k ++) + p_dev_list->gatt_if[k - 1] = p_dev_list->gatt_if[k]; + + if (p_dev_list->gatt_if[0] == 0) + BTM_BleUpdateBgConnDev(FALSE, p_dev_list->remote_bda); + } + + if (p_dev_list->listen_gif[j] == gatt_if) + { + p_dev_list->listen_gif[j] = 0; + + if (p_reg != NULL && p_reg->listening > 0) + p_reg->listening --; + + /* move all element behind one forward */ + for (k = j + 1; k < GATT_MAX_APPS; k ++) + p_dev_list->listen_gif[k - 1] = p_dev_list->listen_gif[k]; + + if (p_dev_list->listen_gif[0] == 0) + BTM_BleUpdateAdvWhitelist(FALSE, p_dev_list->remote_bda); + } + } + } + } +} + + +/******************************************************************************* +** +** Function gatt_reset_bgdev_list +** +** Description reset bg device list +** +** Returns pointer to the device record +** +*******************************************************************************/ +void gatt_reset_bgdev_list(void) +{ + memset(&gatt_cb.bgconn_dev, 0 , sizeof(tGATT_BG_CONN_DEV)*GATT_MAX_BG_CONN_DEV); + +} +/******************************************************************************* +** +** Function gatt_update_auto_connect_dev +** +** Description This function add or remove a device for background connection +** procedure. +** +** Parameters gatt_if: Application ID. +** add: add peer device +** bd_addr: peer device address. +** +** Returns TRUE if connection started; FALSE if connection start failure. +** +*******************************************************************************/ +BOOLEAN gatt_update_auto_connect_dev (tGATT_IF gatt_if, BOOLEAN add, BD_ADDR bd_addr, BOOLEAN is_initator) +{ + BOOLEAN ret = FALSE; + tGATT_REG *p_reg; + tGATT_TCB *p_tcb = gatt_find_tcb_by_addr(bd_addr, BT_TRANSPORT_LE); + + GATT_TRACE_API ("gatt_update_auto_connect_dev "); + /* Make sure app is registered */ + if ((p_reg = gatt_get_regcb(gatt_if)) == NULL) + { + GATT_TRACE_ERROR("gatt_update_auto_connect_dev - gatt_if is not registered", gatt_if); + return(FALSE); + } + + if (add) + { + ret = gatt_add_bg_dev_list(p_reg, bd_addr, is_initator); + + if (ret && p_tcb != NULL) + { + /* if a connected device, update the link holding number */ + gatt_update_app_use_link_flag(gatt_if, p_tcb, TRUE, TRUE); + } + } + else + { + ret = gatt_remove_bg_dev_from_list(p_reg, bd_addr, is_initator); + } + return ret; +} + + + +/******************************************************************************* +** +** Function gatt_add_pending_new_srv_start +** +** Description Add a pending new srv start to the new service start queue +** +** Returns Pointer to the new service start buffer, NULL no buffer available +** +*******************************************************************************/ +tGATT_PENDING_ENC_CLCB* gatt_add_pending_enc_channel_clcb(tGATT_TCB *p_tcb, tGATT_CLCB *p_clcb ) +{ + tGATT_PENDING_ENC_CLCB *p_buf; + + GATT_TRACE_DEBUG ("gatt_add_pending_new_srv_start"); + if ((p_buf = (tGATT_PENDING_ENC_CLCB *)GKI_getbuf((UINT16)sizeof(tGATT_PENDING_ENC_CLCB))) != NULL) + { + GATT_TRACE_DEBUG ("enqueue a new pending encryption channel clcb"); + p_buf->p_clcb = p_clcb; + GKI_enqueue (&p_tcb->pending_enc_clcb, p_buf); + } + return p_buf; +} +/******************************************************************************* +** +** Function gatt_update_listen_mode +** +** Description update peripheral role listening mode +** +** Returns Pointer to the new service start buffer, NULL no buffer available +** +*******************************************************************************/ +BOOLEAN gatt_update_listen_mode(void) +{ + UINT8 ii = 0; + tGATT_REG *p_reg = &gatt_cb.cl_rcb[0]; + UINT8 listening = 0; + UINT16 connectability, window, interval; + BOOLEAN rt = TRUE; + + for (; ii < GATT_MAX_APPS; ii ++, p_reg ++) + { + if ( p_reg->in_use && p_reg->listening > listening) + { + listening = p_reg->listening; + } + } + + if (listening == GATT_LISTEN_TO_ALL || + listening == GATT_LISTEN_TO_NONE) + BTM_BleUpdateAdvFilterPolicy (AP_SCAN_CONN_ALL); + else + BTM_BleUpdateAdvFilterPolicy (AP_SCAN_CONN_WL); + + if (rt) + { + connectability = BTM_ReadConnectability (&window, &interval); + + if (listening != GATT_LISTEN_TO_NONE) + { + connectability |= BTM_BLE_CONNECTABLE; + } + else + { + if ((connectability & BTM_BLE_CONNECTABLE) == 0) + connectability &= ~BTM_BLE_CONNECTABLE; + } + /* turning on the adv now */ + btm_ble_set_connectability(connectability); + } + + return rt; + +} +#endif + + diff --git a/components/bt/bluedroid/stack/hcic/hciblecmds.c b/components/bt/bluedroid/stack/hcic/hciblecmds.c new file mode 100755 index 0000000000..c569013e13 --- /dev/null +++ b/components/bt/bluedroid/stack/hcic/hciblecmds.c @@ -0,0 +1,962 @@ +/****************************************************************************** + * + * Copyright (C) 1999-2012 Broadcom Corporation + * + * 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 function of the HCIC unit to format and send HCI + * commands. + * + ******************************************************************************/ + +#include "bt_target.h" +#include "gki.h" +#include "hcidefs.h" +#include "hcimsgs.h" +#include "hcidefs.h" +#include "btu.h" + +#include +#include + +#if (defined BLE_INCLUDED) && (BLE_INCLUDED == TRUE) + +BOOLEAN btsnd_hcic_ble_set_local_used_feat (UINT8 feat_set[8]) +{ + BT_HDR *p; + UINT8 *pp; + + if ((p = HCI_GET_CMD_BUF(HCIC_PARAM_SIZE_SET_USED_FEAT_CMD)) == NULL) + return (FALSE); + + pp = (UINT8 *)(p + 1); + + p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_SET_USED_FEAT_CMD; + p->offset = 0; + + UINT16_TO_STREAM (pp, HCI_BLE_WRITE_LOCAL_SPT_FEAT); + ARRAY_TO_STREAM (pp, feat_set, HCIC_PARAM_SIZE_SET_USED_FEAT_CMD); + + btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p); + return (TRUE); +} + +BOOLEAN btsnd_hcic_ble_set_random_addr (BD_ADDR random_bda) +{ + BT_HDR *p; + UINT8 *pp; + + if ((p = HCI_GET_CMD_BUF(HCIC_PARAM_SIZE_WRITE_RANDOM_ADDR_CMD)) == NULL) + return (FALSE); + + pp = (UINT8 *)(p + 1); + + p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_WRITE_RANDOM_ADDR_CMD; + p->offset = 0; + + UINT16_TO_STREAM (pp, HCI_BLE_WRITE_RANDOM_ADDR); + UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_WRITE_RANDOM_ADDR_CMD); + + BDADDR_TO_STREAM (pp, random_bda); + + btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p); + return (TRUE); +} + +BOOLEAN btsnd_hcic_ble_write_adv_params (UINT16 adv_int_min, UINT16 adv_int_max, + UINT8 adv_type, UINT8 addr_type_own, + UINT8 addr_type_dir, BD_ADDR direct_bda, + UINT8 channel_map, UINT8 adv_filter_policy) +{ + BT_HDR *p; + UINT8 *pp; + + if ((p = HCI_GET_CMD_BUF(HCIC_PARAM_SIZE_BLE_WRITE_ADV_PARAMS)) == NULL) + return (FALSE); + + pp = (UINT8 *)(p + 1); + + p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_BLE_WRITE_ADV_PARAMS ; + p->offset = 0; + + UINT16_TO_STREAM (pp, HCI_BLE_WRITE_ADV_PARAMS); + UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_BLE_WRITE_ADV_PARAMS ); + + UINT16_TO_STREAM (pp, adv_int_min); + UINT16_TO_STREAM (pp, adv_int_max); + UINT8_TO_STREAM (pp, adv_type); + UINT8_TO_STREAM (pp, addr_type_own); + UINT8_TO_STREAM (pp, addr_type_dir); + BDADDR_TO_STREAM (pp, direct_bda); + UINT8_TO_STREAM (pp, channel_map); + UINT8_TO_STREAM (pp, adv_filter_policy); + + btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p); + return (TRUE); +} +BOOLEAN btsnd_hcic_ble_read_adv_chnl_tx_power (void) +{ + BT_HDR *p; + UINT8 *pp; + + if ((p = HCI_GET_CMD_BUF(HCIC_PARAM_SIZE_READ_CMD)) == NULL) + return (FALSE); + + pp = (UINT8 *)(p + 1); + + p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_READ_CMD; + p->offset = 0; + + UINT16_TO_STREAM (pp, HCI_BLE_READ_ADV_CHNL_TX_POWER); + UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_READ_CMD); + + btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p); + return (TRUE); + +} + +BOOLEAN btsnd_hcic_ble_set_adv_data (UINT8 data_len, UINT8 *p_data) +{ + BT_HDR *p; + UINT8 *pp; + + for (int i = 0; i < data_len; i++) + { + LOG_ERROR("p_data[%d] = %x\n", i,p_data[i]); + } + + if ((p = HCI_GET_CMD_BUF(HCIC_PARAM_SIZE_BLE_WRITE_ADV_DATA + 1)) == NULL) + return (FALSE); + + pp = (UINT8 *)(p + 1); + + p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_BLE_WRITE_ADV_DATA + 1; + p->offset = 0; + + UINT16_TO_STREAM (pp, HCI_BLE_WRITE_ADV_DATA); + UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_BLE_WRITE_ADV_DATA + 1); + + memset(pp, 0, HCIC_PARAM_SIZE_BLE_WRITE_ADV_DATA); + + if (p_data != NULL && data_len > 0) + { + if (data_len > HCIC_PARAM_SIZE_BLE_WRITE_ADV_DATA) + data_len = HCIC_PARAM_SIZE_BLE_WRITE_ADV_DATA; + + UINT8_TO_STREAM (pp, data_len); + + ARRAY_TO_STREAM (pp, p_data, data_len); + } + btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p); + + return (TRUE); +} +BOOLEAN btsnd_hcic_ble_set_scan_rsp_data (UINT8 data_len, UINT8 *p_scan_rsp) +{ + BT_HDR *p; + UINT8 *pp; + + if ((p = HCI_GET_CMD_BUF(HCIC_PARAM_SIZE_BLE_WRITE_SCAN_RSP + 1)) == NULL) + return (FALSE); + + pp = (UINT8 *)(p + 1); + + p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_BLE_WRITE_SCAN_RSP + 1; + p->offset = 0; + + UINT16_TO_STREAM (pp, HCI_BLE_WRITE_SCAN_RSP_DATA); + UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_BLE_WRITE_SCAN_RSP + 1); + + memset(pp, 0, HCIC_PARAM_SIZE_BLE_WRITE_SCAN_RSP); + + if (p_scan_rsp != NULL && data_len > 0) + { + + if (data_len > HCIC_PARAM_SIZE_BLE_WRITE_SCAN_RSP ) + data_len = HCIC_PARAM_SIZE_BLE_WRITE_SCAN_RSP; + + UINT8_TO_STREAM (pp, data_len); + + ARRAY_TO_STREAM (pp, p_scan_rsp, data_len); + } + + btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p); + + return (TRUE); +} + +BOOLEAN btsnd_hcic_ble_set_adv_enable (UINT8 adv_enable) +{ + BT_HDR *p; + UINT8 *pp; + + if ((p = HCI_GET_CMD_BUF(HCIC_PARAM_SIZE_WRITE_ADV_ENABLE)) == NULL) + return (FALSE); + + pp = (UINT8 *)(p + 1); + + p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_WRITE_ADV_ENABLE; + p->offset = 0; + + UINT16_TO_STREAM (pp, HCI_BLE_WRITE_ADV_ENABLE); + UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_WRITE_ADV_ENABLE); + + UINT8_TO_STREAM (pp, adv_enable); + + btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p); + return (TRUE); +} +BOOLEAN btsnd_hcic_ble_set_scan_params (UINT8 scan_type, + UINT16 scan_int, UINT16 scan_win, + UINT8 addr_type_own, UINT8 scan_filter_policy) +{ + BT_HDR *p; + UINT8 *pp; + + if ((p = HCI_GET_CMD_BUF(HCIC_PARAM_SIZE_BLE_WRITE_SCAN_PARAM)) == NULL) + return (FALSE); + + pp = (UINT8 *)(p + 1); + + p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_BLE_WRITE_SCAN_PARAM; + p->offset = 0; + + UINT16_TO_STREAM (pp, HCI_BLE_WRITE_SCAN_PARAMS); + UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_BLE_WRITE_SCAN_PARAM); + + UINT8_TO_STREAM (pp, scan_type); + UINT16_TO_STREAM (pp, scan_int); + UINT16_TO_STREAM (pp, scan_win); + UINT8_TO_STREAM (pp, addr_type_own); + UINT8_TO_STREAM (pp, scan_filter_policy); + + btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p); + return (TRUE); +} + +BOOLEAN btsnd_hcic_ble_set_scan_enable (UINT8 scan_enable, UINT8 duplicate) +{ + BT_HDR *p; + UINT8 *pp; + + if ((p = HCI_GET_CMD_BUF(HCIC_PARAM_SIZE_BLE_WRITE_SCAN_ENABLE)) == NULL) + return (FALSE); + + pp = (UINT8 *)(p + 1); + + p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_BLE_WRITE_SCAN_ENABLE; + p->offset = 0; + + UINT16_TO_STREAM (pp, HCI_BLE_WRITE_SCAN_ENABLE); + UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_BLE_WRITE_SCAN_ENABLE); + + UINT8_TO_STREAM (pp, scan_enable); + UINT8_TO_STREAM (pp, duplicate); + + btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p); + return (TRUE); +} + +/* link layer connection management commands */ +BOOLEAN btsnd_hcic_ble_create_ll_conn (UINT16 scan_int, UINT16 scan_win, + UINT8 init_filter_policy, + UINT8 addr_type_peer, BD_ADDR bda_peer, + UINT8 addr_type_own, + UINT16 conn_int_min, UINT16 conn_int_max, + UINT16 conn_latency, UINT16 conn_timeout, + UINT16 min_ce_len, UINT16 max_ce_len) +{ + BT_HDR *p; + UINT8 *pp; + + if ((p = HCI_GET_CMD_BUF(HCIC_PARAM_SIZE_BLE_CREATE_LL_CONN)) == NULL) + return (FALSE); + + pp = (UINT8 *)(p + 1); + + p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_BLE_CREATE_LL_CONN; + p->offset = 0; + + UINT16_TO_STREAM (pp, HCI_BLE_CREATE_LL_CONN); + UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_BLE_CREATE_LL_CONN); + + UINT16_TO_STREAM (pp, scan_int); + UINT16_TO_STREAM (pp, scan_win); + UINT8_TO_STREAM (pp, init_filter_policy); + + UINT8_TO_STREAM (pp, addr_type_peer); + BDADDR_TO_STREAM (pp, bda_peer); + UINT8_TO_STREAM (pp, addr_type_own); + + UINT16_TO_STREAM (pp, conn_int_min); + UINT16_TO_STREAM (pp, conn_int_max); + UINT16_TO_STREAM (pp, conn_latency); + UINT16_TO_STREAM (pp, conn_timeout); + + UINT16_TO_STREAM (pp, min_ce_len); + UINT16_TO_STREAM (pp, max_ce_len); + + btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p); + return (TRUE); +} + +BOOLEAN btsnd_hcic_ble_create_conn_cancel (void) +{ + BT_HDR *p; + UINT8 *pp; + + if ((p = HCI_GET_CMD_BUF(HCIC_PARAM_SIZE_BLE_CREATE_CONN_CANCEL)) == NULL) + return (FALSE); + + pp = (UINT8 *)(p + 1); + + p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_BLE_CREATE_CONN_CANCEL; + p->offset = 0; + + UINT16_TO_STREAM (pp, HCI_BLE_CREATE_CONN_CANCEL); + UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_BLE_CREATE_CONN_CANCEL); + + btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p); + return (TRUE); +} + +BOOLEAN btsnd_hcic_ble_clear_white_list (void) +{ + BT_HDR *p; + UINT8 *pp; + + if ((p = HCI_GET_CMD_BUF(HCIC_PARAM_SIZE_CLEAR_WHITE_LIST)) == NULL) + return (FALSE); + + pp = (UINT8 *)(p + 1); + + p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_CLEAR_WHITE_LIST; + p->offset = 0; + + UINT16_TO_STREAM (pp, HCI_BLE_CLEAR_WHITE_LIST); + UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_CLEAR_WHITE_LIST); + + btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p); + return (TRUE); +} + +BOOLEAN btsnd_hcic_ble_add_white_list (UINT8 addr_type, BD_ADDR bda) +{ + BT_HDR *p; + UINT8 *pp; + + if ((p = HCI_GET_CMD_BUF(HCIC_PARAM_SIZE_ADD_WHITE_LIST)) == NULL) + return (FALSE); + + pp = (UINT8 *)(p + 1); + + p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_ADD_WHITE_LIST; + p->offset = 0; + + UINT16_TO_STREAM (pp, HCI_BLE_ADD_WHITE_LIST); + UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_ADD_WHITE_LIST); + + UINT8_TO_STREAM (pp, addr_type); + BDADDR_TO_STREAM (pp, bda); + + btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p); + return (TRUE); +} + +BOOLEAN btsnd_hcic_ble_remove_from_white_list (UINT8 addr_type, BD_ADDR bda) +{ + BT_HDR *p; + UINT8 *pp; + + if ((p = HCI_GET_CMD_BUF(HCIC_PARAM_SIZE_REMOVE_WHITE_LIST)) == NULL) + return (FALSE); + + pp = (UINT8 *)(p + 1); + + p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_REMOVE_WHITE_LIST; + p->offset = 0; + + UINT16_TO_STREAM (pp, HCI_BLE_REMOVE_WHITE_LIST); + UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_REMOVE_WHITE_LIST); + + UINT8_TO_STREAM (pp, addr_type); + BDADDR_TO_STREAM (pp, bda); + + btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p); + return (TRUE); +} + +BOOLEAN btsnd_hcic_ble_upd_ll_conn_params (UINT16 handle, + UINT16 conn_int_min, UINT16 conn_int_max, + UINT16 conn_latency, UINT16 conn_timeout, + UINT16 min_ce_len, UINT16 max_ce_len) +{ + BT_HDR *p; + UINT8 *pp; + + if ((p = HCI_GET_CMD_BUF(HCIC_PARAM_SIZE_BLE_UPD_LL_CONN_PARAMS)) == NULL) + return (FALSE); + + pp = (UINT8 *)(p + 1); + + p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_BLE_UPD_LL_CONN_PARAMS; + p->offset = 0; + + UINT16_TO_STREAM (pp, HCI_BLE_UPD_LL_CONN_PARAMS); + UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_BLE_UPD_LL_CONN_PARAMS); + + UINT16_TO_STREAM (pp, handle); + + UINT16_TO_STREAM (pp, conn_int_min); + UINT16_TO_STREAM (pp, conn_int_max); + UINT16_TO_STREAM (pp, conn_latency); + UINT16_TO_STREAM (pp, conn_timeout); + UINT16_TO_STREAM (pp, min_ce_len); + UINT16_TO_STREAM (pp, max_ce_len); + + btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p); + return (TRUE); +} + +BOOLEAN btsnd_hcic_ble_set_host_chnl_class (UINT8 chnl_map[HCIC_BLE_CHNL_MAP_SIZE]) +{ + BT_HDR *p; + UINT8 *pp; + + if ((p = HCI_GET_CMD_BUF(HCIC_PARAM_SIZE_SET_HOST_CHNL_CLASS)) == NULL) + return (FALSE); + + pp = (UINT8 *)(p + 1); + + p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_SET_HOST_CHNL_CLASS; + p->offset = 0; + + UINT16_TO_STREAM (pp, HCI_BLE_SET_HOST_CHNL_CLASS); + UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_SET_HOST_CHNL_CLASS); + + ARRAY_TO_STREAM (pp, chnl_map, HCIC_BLE_CHNL_MAP_SIZE); + + btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p); + return (TRUE); +} + +BOOLEAN btsnd_hcic_ble_read_chnl_map (UINT16 handle) +{ + BT_HDR *p; + UINT8 *pp; + + if ((p = HCI_GET_CMD_BUF(HCIC_PARAM_SIZE_READ_CHNL_MAP)) == NULL) + return (FALSE); + + pp = (UINT8 *)(p + 1); + + p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_READ_CHNL_MAP; + p->offset = 0; + + UINT16_TO_STREAM (pp, HCI_BLE_READ_CHNL_MAP); + UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_READ_CHNL_MAP); + + UINT16_TO_STREAM (pp, handle); + + btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p); + return (TRUE); +} + +BOOLEAN btsnd_hcic_ble_read_remote_feat (UINT16 handle) +{ + BT_HDR *p; + UINT8 *pp; + + if ((p = HCI_GET_CMD_BUF(HCIC_PARAM_SIZE_BLE_READ_REMOTE_FEAT)) == NULL) + return (FALSE); + + pp = (UINT8 *)(p + 1); + + p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_BLE_READ_REMOTE_FEAT; + p->offset = 0; + + UINT16_TO_STREAM (pp, HCI_BLE_READ_REMOTE_FEAT); + UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_BLE_READ_REMOTE_FEAT); + + UINT16_TO_STREAM (pp, handle); + + btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p); + return (TRUE); +} + +/* security management commands */ +BOOLEAN btsnd_hcic_ble_encrypt (UINT8 *key, UINT8 key_len, + UINT8 *plain_text, UINT8 pt_len, + void *p_cmd_cplt_cback) +{ + BT_HDR *p; + UINT8 *pp; + + if ((p = HCI_GET_CMD_BUF(sizeof(BT_HDR) + sizeof (void *) + + HCIC_PARAM_SIZE_BLE_ENCRYPT)) == NULL) + return (FALSE); + + pp = (UINT8 *)(p + 1); + + p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_BLE_ENCRYPT; + p->offset = sizeof(void *); + + *((void **)pp) = p_cmd_cplt_cback; /* Store command complete callback in buffer */ + pp += sizeof(void *); /* Skip over callback pointer */ + + + UINT16_TO_STREAM (pp, HCI_BLE_ENCRYPT); + UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_BLE_ENCRYPT); + + memset(pp, 0, HCIC_PARAM_SIZE_BLE_ENCRYPT); + + if (key_len > HCIC_BLE_ENCRYT_KEY_SIZE) key_len = HCIC_BLE_ENCRYT_KEY_SIZE; + if (pt_len > HCIC_BLE_ENCRYT_KEY_SIZE) pt_len = HCIC_BLE_ENCRYT_KEY_SIZE; + + ARRAY_TO_STREAM (pp, key, key_len); + pp += (HCIC_BLE_ENCRYT_KEY_SIZE - key_len); + ARRAY_TO_STREAM (pp, plain_text, pt_len); + + btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p); + return (TRUE); +} + +BOOLEAN btsnd_hcic_ble_rand (void *p_cmd_cplt_cback) +{ + BT_HDR *p; + UINT8 *pp; + + if ((p = HCI_GET_CMD_BUF(sizeof(BT_HDR) + sizeof (void *) + + HCIC_PARAM_SIZE_BLE_RAND)) == NULL) + return (FALSE); + + pp = (UINT8 *)(p + 1); + + p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_BLE_RAND; + p->offset = sizeof(void *); + + *((void **)pp) = p_cmd_cplt_cback; /* Store command complete callback in buffer */ + pp += sizeof(void *); /* Skip over callback pointer */ + + UINT16_TO_STREAM (pp, HCI_BLE_RAND); + UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_BLE_RAND); + + btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p); + return (TRUE); +} + +BOOLEAN btsnd_hcic_ble_start_enc (UINT16 handle, UINT8 rand[HCIC_BLE_RAND_DI_SIZE], + UINT16 ediv, UINT8 ltk[HCIC_BLE_ENCRYT_KEY_SIZE]) +{ + BT_HDR *p; + UINT8 *pp; + + if ((p = HCI_GET_CMD_BUF(HCIC_PARAM_SIZE_BLE_START_ENC)) == NULL) + return (FALSE); + + pp = (UINT8 *)(p + 1); + + p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_BLE_START_ENC; + p->offset = 0; + + UINT16_TO_STREAM (pp, HCI_BLE_START_ENC); + UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_BLE_START_ENC); + + UINT16_TO_STREAM (pp, handle); + ARRAY_TO_STREAM (pp, rand, HCIC_BLE_RAND_DI_SIZE); + UINT16_TO_STREAM (pp, ediv); + ARRAY_TO_STREAM (pp, ltk, HCIC_BLE_ENCRYT_KEY_SIZE); + + btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p); + return (TRUE); +} + +BOOLEAN btsnd_hcic_ble_ltk_req_reply (UINT16 handle, UINT8 ltk[HCIC_BLE_ENCRYT_KEY_SIZE]) +{ + BT_HDR *p; + UINT8 *pp; + + if ((p = HCI_GET_CMD_BUF(HCIC_PARAM_SIZE_LTK_REQ_REPLY)) == NULL) + return (FALSE); + + pp = (UINT8 *)(p + 1); + + p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_LTK_REQ_REPLY; + p->offset = 0; + + UINT16_TO_STREAM (pp, HCI_BLE_LTK_REQ_REPLY); + UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_LTK_REQ_REPLY); + + UINT16_TO_STREAM (pp, handle); + ARRAY_TO_STREAM (pp, ltk, HCIC_BLE_ENCRYT_KEY_SIZE); + + btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p); + return (TRUE); +} + +BOOLEAN btsnd_hcic_ble_ltk_req_neg_reply (UINT16 handle) +{ + BT_HDR *p; + UINT8 *pp; + + if ((p = HCI_GET_CMD_BUF(HCIC_PARAM_SIZE_LTK_REQ_NEG_REPLY)) == NULL) + return (FALSE); + + pp = (UINT8 *)(p + 1); + + p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_LTK_REQ_NEG_REPLY; + p->offset = 0; + + UINT16_TO_STREAM (pp, HCI_BLE_LTK_REQ_NEG_REPLY); + UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_LTK_REQ_NEG_REPLY); + + UINT16_TO_STREAM (pp, handle); + + btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p); + return (TRUE); +} + +BOOLEAN btsnd_hcic_ble_receiver_test(UINT8 rx_freq) +{ + BT_HDR *p; + UINT8 *pp; + + if ((p = HCI_GET_CMD_BUF(HCIC_PARAM_SIZE_WRITE_PARAM1)) == NULL) + return (FALSE); + + pp = (UINT8 *)(p + 1); + + p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_WRITE_PARAM1; + p->offset = 0; + + UINT16_TO_STREAM (pp, HCI_BLE_RECEIVER_TEST); + UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_WRITE_PARAM1); + + UINT8_TO_STREAM (pp, rx_freq); + + btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p); + return (TRUE); +} + +BOOLEAN btsnd_hcic_ble_transmitter_test(UINT8 tx_freq, UINT8 test_data_len, UINT8 payload) +{ + BT_HDR *p; + UINT8 *pp; + + if ((p = HCI_GET_CMD_BUF(HCIC_PARAM_SIZE_WRITE_PARAM3)) == NULL) + return (FALSE); + + pp = (UINT8 *)(p + 1); + + p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_WRITE_PARAM3; + p->offset = 0; + + UINT16_TO_STREAM (pp, HCI_BLE_TRANSMITTER_TEST); + UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_WRITE_PARAM3); + + UINT8_TO_STREAM (pp, tx_freq); + UINT8_TO_STREAM (pp, test_data_len); + UINT8_TO_STREAM (pp, payload); + + btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p); + return (TRUE); +} + +BOOLEAN btsnd_hcic_ble_test_end(void) +{ + BT_HDR *p; + UINT8 *pp; + + if ((p = HCI_GET_CMD_BUF(HCIC_PARAM_SIZE_READ_CMD)) == NULL) + return (FALSE); + + pp = (UINT8 *)(p + 1); + + p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_READ_CMD; + p->offset = 0; + + UINT16_TO_STREAM (pp, HCI_BLE_TEST_END); + UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_READ_CMD); + + btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p); + return (TRUE); +} + +BOOLEAN btsnd_hcic_ble_read_host_supported (void) +{ + BT_HDR *p; + UINT8 *pp; + + if ((p = HCI_GET_CMD_BUF(HCIC_PARAM_SIZE_READ_CMD)) == NULL) + return (FALSE); + + pp = (UINT8 *)(p + 1); + + p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_READ_CMD; + p->offset = 0; + + UINT16_TO_STREAM (pp, HCI_READ_LE_HOST_SUPPORT); + UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_READ_CMD); + + btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p); + return (TRUE); +} + +#if (defined BLE_LLT_INCLUDED) && (BLE_LLT_INCLUDED == TRUE) + +BOOLEAN btsnd_hcic_ble_rc_param_req_reply( UINT16 handle, + UINT16 conn_int_min, UINT16 conn_int_max, + UINT16 conn_latency, UINT16 conn_timeout, + UINT16 min_ce_len, UINT16 max_ce_len ) +{ + BT_HDR *p; + UINT8 *pp; + + if ((p = HCI_GET_CMD_BUF(HCIC_PARAM_SIZE_BLE_RC_PARAM_REQ_REPLY)) == NULL) + return (FALSE); + + pp = (UINT8 *)(p + 1); + + p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_BLE_RC_PARAM_REQ_REPLY; + p->offset = 0; + + UINT16_TO_STREAM (pp, HCI_BLE_RC_PARAM_REQ_REPLY); + UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_BLE_RC_PARAM_REQ_REPLY); + + UINT16_TO_STREAM (pp, handle); + UINT16_TO_STREAM (pp, conn_int_min); + UINT16_TO_STREAM (pp, conn_int_max); + UINT16_TO_STREAM (pp, conn_latency); + UINT16_TO_STREAM (pp, conn_timeout); + UINT16_TO_STREAM (pp, min_ce_len); + UINT16_TO_STREAM (pp, max_ce_len); + + btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p); + return (TRUE); +} + +BOOLEAN btsnd_hcic_ble_rc_param_req_neg_reply(UINT16 handle, UINT8 reason) +{ + BT_HDR *p; + UINT8 *pp; + + if ((p = HCI_GET_CMD_BUF(HCIC_PARAM_SIZE_BLE_RC_PARAM_REQ_NEG_REPLY)) == NULL) + return (FALSE); + + pp = (UINT8 *)(p + 1); + + p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_BLE_RC_PARAM_REQ_NEG_REPLY; + p->offset = 0; + + UINT16_TO_STREAM (pp, HCI_BLE_RC_PARAM_REQ_NEG_REPLY); + UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_BLE_RC_PARAM_REQ_NEG_REPLY); + + UINT16_TO_STREAM (pp, handle); + UINT8_TO_STREAM (pp, reason); + + btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p); + return (TRUE); +} +#endif + +BOOLEAN btsnd_hcic_ble_add_device_resolving_list (UINT8 addr_type_peer, BD_ADDR bda_peer, + UINT8 irk_peer[HCIC_BLE_IRK_SIZE], + UINT8 irk_local[HCIC_BLE_IRK_SIZE]) +{ + BT_HDR *p; + UINT8 *pp; + + if ((p = HCI_GET_CMD_BUF (HCIC_PARAM_SIZE_BLE_ADD_DEV_RESOLVING_LIST)) == NULL) + return (FALSE); + + pp = (UINT8 *)(p + 1); + + p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_BLE_ADD_DEV_RESOLVING_LIST; + p->offset = 0; + + UINT16_TO_STREAM (pp, HCI_BLE_ADD_DEV_RESOLVING_LIST); + UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_BLE_ADD_DEV_RESOLVING_LIST); + UINT8_TO_STREAM (pp, addr_type_peer); + BDADDR_TO_STREAM (pp, bda_peer); + ARRAY_TO_STREAM (pp, irk_peer, HCIC_BLE_ENCRYT_KEY_SIZE); + ARRAY_TO_STREAM (pp, irk_local, HCIC_BLE_ENCRYT_KEY_SIZE); + + btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p); + + return (TRUE); +} + +BOOLEAN btsnd_hcic_ble_rm_device_resolving_list (UINT8 addr_type_peer, BD_ADDR bda_peer) +{ + BT_HDR *p; + UINT8 *pp; + + if ((p = HCI_GET_CMD_BUF (HCIC_PARAM_SIZE_BLE_RM_DEV_RESOLVING_LIST)) == NULL) + return (FALSE); + + pp = (UINT8 *)(p + 1); + + p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_BLE_RM_DEV_RESOLVING_LIST; + p->offset = 0; + + UINT16_TO_STREAM (pp, HCI_BLE_RM_DEV_RESOLVING_LIST); + UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_BLE_RM_DEV_RESOLVING_LIST); + UINT8_TO_STREAM (pp, addr_type_peer); + BDADDR_TO_STREAM (pp, bda_peer); + + btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p); + + return (TRUE); +} + +BOOLEAN btsnd_hcic_ble_clear_resolving_list (void) +{ + BT_HDR *p; + UINT8 *pp; + + if ((p = HCI_GET_CMD_BUF (HCIC_PARAM_SIZE_BLE_CLEAR_RESOLVING_LIST)) == NULL) + return (FALSE); + + pp = (UINT8 *)(p + 1); + + p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_BLE_CLEAR_RESOLVING_LIST; + p->offset = 0; + + UINT16_TO_STREAM (pp, HCI_BLE_CLEAR_RESOLVING_LIST); + UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_BLE_CLEAR_RESOLVING_LIST); + + btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p); + + return (TRUE); +} + +BOOLEAN btsnd_hcic_ble_read_resolvable_addr_peer (UINT8 addr_type_peer, BD_ADDR bda_peer) +{ + BT_HDR *p; + UINT8 *pp; + + if ((p = HCI_GET_CMD_BUF (HCIC_PARAM_SIZE_BLE_READ_RESOLVABLE_ADDR_PEER)) == NULL) + return (FALSE); + + pp = (UINT8 *)(p + 1); + + p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_BLE_READ_RESOLVABLE_ADDR_PEER; + p->offset = 0; + + UINT16_TO_STREAM (pp, HCI_BLE_READ_RESOLVABLE_ADDR_PEER); + UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_BLE_READ_RESOLVABLE_ADDR_PEER); + UINT8_TO_STREAM (pp, addr_type_peer); + BDADDR_TO_STREAM (pp, bda_peer); + + btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p); + + return (TRUE); +} + +BOOLEAN btsnd_hcic_ble_read_resolvable_addr_local (UINT8 addr_type_peer, BD_ADDR bda_peer) +{ + BT_HDR *p; + UINT8 *pp; + + if ((p = HCI_GET_CMD_BUF (HCIC_PARAM_SIZE_BLE_READ_RESOLVABLE_ADDR_LOCAL)) == NULL) + return (FALSE); + + pp = (UINT8 *)(p + 1); + + p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_BLE_READ_RESOLVABLE_ADDR_LOCAL; + p->offset = 0; + + UINT16_TO_STREAM (pp, HCI_BLE_READ_RESOLVABLE_ADDR_LOCAL); + UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_BLE_READ_RESOLVABLE_ADDR_LOCAL); + UINT8_TO_STREAM (pp, addr_type_peer); + BDADDR_TO_STREAM (pp, bda_peer); + + btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p); + + return (TRUE); +} + +BOOLEAN btsnd_hcic_ble_set_addr_resolution_enable (UINT8 addr_resolution_enable) +{ + BT_HDR *p; + UINT8 *pp; + + if ((p = HCI_GET_CMD_BUF (HCIC_PARAM_SIZE_BLE_SET_ADDR_RESOLUTION_ENABLE)) == NULL) + return (FALSE); + + pp = (UINT8 *)(p + 1); + + p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_BLE_SET_ADDR_RESOLUTION_ENABLE; + p->offset = 0; + + UINT16_TO_STREAM (pp, HCI_BLE_SET_ADDR_RESOLUTION_ENABLE); + UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_BLE_SET_ADDR_RESOLUTION_ENABLE); + UINT8_TO_STREAM (pp, addr_resolution_enable); + + btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p); + + return (TRUE); +} + +BOOLEAN btsnd_hcic_ble_set_rand_priv_addr_timeout (UINT16 rpa_timout) +{ + BT_HDR *p; + UINT8 *pp; + + if ((p = HCI_GET_CMD_BUF (HCIC_PARAM_SIZE_BLE_SET_RAND_PRIV_ADDR_TIMOUT)) == NULL) + return (FALSE); + + pp = (UINT8 *)(p + 1); + + p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_BLE_SET_RAND_PRIV_ADDR_TIMOUT; + p->offset = 0; + + UINT16_TO_STREAM (pp, HCI_BLE_SET_RAND_PRIV_ADDR_TIMOUT); + UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_BLE_SET_RAND_PRIV_ADDR_TIMOUT); + UINT16_TO_STREAM (pp, rpa_timout); + + btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p); + + return (TRUE); +} + +BOOLEAN btsnd_hcic_ble_set_data_length(UINT16 conn_handle, UINT16 tx_octets, UINT16 tx_time) +{ + BT_HDR *p; + UINT8 *pp; + + if ((p = HCI_GET_CMD_BUF(HCIC_PARAM_SIZE_BLE_SET_DATA_LENGTH)) == NULL) + return FALSE; + + pp = p->data; + + p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_BLE_SET_DATA_LENGTH; + p->offset = 0; + + UINT16_TO_STREAM(pp, HCI_BLE_SET_DATA_LENGTH); + UINT8_TO_STREAM(pp, HCIC_PARAM_SIZE_BLE_SET_DATA_LENGTH); + + UINT16_TO_STREAM(pp, conn_handle); + UINT16_TO_STREAM(pp, tx_octets); + UINT16_TO_STREAM(pp, tx_time); + + btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p); + return TRUE; +} + +#endif + diff --git a/components/bt/bluedroid/stack/hcic/hcicmds.c b/components/bt/bluedroid/stack/hcic/hcicmds.c new file mode 100755 index 0000000000..4ea85ff9c3 --- /dev/null +++ b/components/bt/bluedroid/stack/hcic/hcicmds.c @@ -0,0 +1,1808 @@ +/****************************************************************************** + * + * Copyright (C) 1999-2012 Broadcom Corporation + * + * 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 function of the HCIC unit to format and send HCI + * commands. + * + ******************************************************************************/ + +#include "bt_target.h" +//#include "btcore/include/counter.h" +#include "gki.h" +#include "hcidefs.h" +#include "hcimsgs.h" +#include "hcidefs.h" +#include "btu.h" + +#include +#include + +#include "btm_int.h" /* Included for UIPC_* macro definitions */ + +BOOLEAN btsnd_hcic_inquiry(const LAP inq_lap, UINT8 duration, UINT8 response_cnt) +{ + BT_HDR *p; + UINT8 *pp; + + if ((p = HCI_GET_CMD_BUF(HCIC_PARAM_SIZE_INQUIRY)) == NULL) + return (FALSE); + + pp = (UINT8 *)(p + 1); + + p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_INQUIRY; + p->offset = 0; + + UINT16_TO_STREAM (pp, HCI_INQUIRY); + UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_INQUIRY); + + LAP_TO_STREAM (pp, inq_lap); + UINT8_TO_STREAM (pp, duration); + UINT8_TO_STREAM (pp, response_cnt); + + btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p); + return (TRUE); +} + +BOOLEAN btsnd_hcic_inq_cancel(void) +{ + BT_HDR *p; + UINT8 *pp; + + if ((p = HCI_GET_CMD_BUF(HCIC_PARAM_SIZE_INQ_CANCEL)) == NULL) + return (FALSE); + + pp = (UINT8 *)(p + 1); + + p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_INQ_CANCEL; + p->offset = 0; + UINT16_TO_STREAM (pp, HCI_INQUIRY_CANCEL); + UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_INQ_CANCEL); + + btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p); + return (TRUE); +} + +BOOLEAN btsnd_hcic_per_inq_mode (UINT16 max_period, UINT16 min_period, + const LAP inq_lap, UINT8 duration, UINT8 response_cnt) +{ + BT_HDR *p; + UINT8 *pp; + + if ((p = HCI_GET_CMD_BUF(HCIC_PARAM_SIZE_PER_INQ_MODE)) == NULL) + return (FALSE); + + pp = (UINT8 *)(p + 1); + + p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_PER_INQ_MODE; + p->offset = 0; + + UINT16_TO_STREAM (pp, HCI_PERIODIC_INQUIRY_MODE); + UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_PER_INQ_MODE); + + UINT16_TO_STREAM (pp, max_period); + UINT16_TO_STREAM (pp, min_period); + LAP_TO_STREAM (pp, inq_lap); + UINT8_TO_STREAM (pp, duration); + UINT8_TO_STREAM (pp, response_cnt); + + btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p); + return (TRUE); +} + +BOOLEAN btsnd_hcic_exit_per_inq (void) +{ + BT_HDR *p; + UINT8 *pp; + + if ((p = HCI_GET_CMD_BUF(HCIC_PARAM_SIZE_EXIT_PER_INQ)) == NULL) + return (FALSE); + + pp = (UINT8 *)(p + 1); + + p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_EXIT_PER_INQ; + p->offset = 0; + UINT16_TO_STREAM (pp, HCI_EXIT_PERIODIC_INQUIRY_MODE); + UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_EXIT_PER_INQ); + + btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p); + return (TRUE); +} + + +BOOLEAN btsnd_hcic_create_conn(BD_ADDR dest, UINT16 packet_types, + UINT8 page_scan_rep_mode, UINT8 page_scan_mode, + UINT16 clock_offset, UINT8 allow_switch) +{ + BT_HDR *p; + UINT8 *pp; + + if ((p = HCI_GET_CMD_BUF(HCIC_PARAM_SIZE_CREATE_CONN)) == NULL) + return (FALSE); + + pp = (UINT8 *)(p + 1); + +#ifndef BT_10A + p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_CREATE_CONN; +#else + p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_CREATE_CONN - 1; +#endif + p->offset = 0; + + UINT16_TO_STREAM (pp, HCI_CREATE_CONNECTION); +#ifndef BT_10A + UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_CREATE_CONN); +#else + UINT8_TO_STREAM (pp, (HCIC_PARAM_SIZE_CREATE_CONN - 1)); +#endif + BDADDR_TO_STREAM (pp, dest); + UINT16_TO_STREAM (pp, packet_types); + UINT8_TO_STREAM (pp, page_scan_rep_mode); + UINT8_TO_STREAM (pp, page_scan_mode); + UINT16_TO_STREAM (pp, clock_offset); +#if !defined (BT_10A) + UINT8_TO_STREAM (pp, allow_switch); +#endif + btm_acl_paging (p, dest); + return (TRUE); +} + +BOOLEAN btsnd_hcic_disconnect (UINT16 handle, UINT8 reason) +{ + BT_HDR *p; + UINT8 *pp; + + if ((p = HCI_GET_CMD_BUF(HCIC_PARAM_SIZE_DISCONNECT)) == NULL) + return (FALSE); + + pp = (UINT8 *)(p + 1); + + p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_DISCONNECT; + p->offset = 0; + + UINT16_TO_STREAM (pp, HCI_DISCONNECT); + UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_DISCONNECT); + UINT16_TO_STREAM (pp, handle); + UINT8_TO_STREAM (pp, reason); + + btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p); + return (TRUE); +} + +#if BTM_SCO_INCLUDED == TRUE +BOOLEAN btsnd_hcic_add_SCO_conn (UINT16 handle, UINT16 packet_types) +{ + BT_HDR *p; + UINT8 *pp; + + if ((p = HCI_GET_CMD_BUF(HCIC_PARAM_SIZE_ADD_SCO_CONN)) == NULL) + return (FALSE); + + pp = (UINT8 *)(p + 1); + + p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_ADD_SCO_CONN; + p->offset = 0; + + UINT16_TO_STREAM (pp, HCI_ADD_SCO_CONNECTION); + UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_ADD_SCO_CONN); + + UINT16_TO_STREAM (pp, handle); + UINT16_TO_STREAM (pp, packet_types); + + btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p); + return (TRUE); +} +#endif /* BTM_SCO_INCLUDED */ + +BOOLEAN btsnd_hcic_create_conn_cancel(BD_ADDR dest) +{ + BT_HDR *p; + UINT8 *pp; + + if ((p = HCI_GET_CMD_BUF(HCIC_PARAM_SIZE_CREATE_CONN_CANCEL)) == NULL) + return (FALSE); + + pp = (UINT8 *)(p + 1); + + p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_CREATE_CONN_CANCEL; + p->offset = 0; + + UINT16_TO_STREAM (pp, HCI_CREATE_CONNECTION_CANCEL); + UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_CREATE_CONN_CANCEL); + + BDADDR_TO_STREAM (pp, dest); + + btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p); + return (TRUE); +} + +BOOLEAN btsnd_hcic_accept_conn (BD_ADDR dest, UINT8 role) +{ + BT_HDR *p; + UINT8 *pp; + + if ((p = HCI_GET_CMD_BUF(HCIC_PARAM_SIZE_ACCEPT_CONN)) == NULL) + return (FALSE); + + pp = (UINT8 *)(p + 1); + + p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_ACCEPT_CONN; + p->offset = 0; + + UINT16_TO_STREAM (pp, HCI_ACCEPT_CONNECTION_REQUEST); + UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_ACCEPT_CONN); + BDADDR_TO_STREAM (pp, dest); + UINT8_TO_STREAM (pp, role); + + //counter_add("hci.conn.accept", 1); + + btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p); + return (TRUE); +} + +BOOLEAN btsnd_hcic_reject_conn (BD_ADDR dest, UINT8 reason) +{ + BT_HDR *p; + UINT8 *pp; + + if ((p = HCI_GET_CMD_BUF(HCIC_PARAM_SIZE_REJECT_CONN)) == NULL) + return (FALSE); + + pp = (UINT8 *)(p + 1); + + p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_REJECT_CONN; + p->offset = 0; + + UINT16_TO_STREAM (pp, HCI_REJECT_CONNECTION_REQUEST); + UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_REJECT_CONN); + + BDADDR_TO_STREAM (pp, dest); + UINT8_TO_STREAM (pp, reason); + + //counter_add("hci.conn.reject", 1); + + btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p); + return (TRUE); +} + +BOOLEAN btsnd_hcic_link_key_req_reply (BD_ADDR bd_addr, LINK_KEY link_key) +{ + BT_HDR *p; + UINT8 *pp; + + if ((p = HCI_GET_CMD_BUF(HCIC_PARAM_SIZE_LINK_KEY_REQ_REPLY)) == NULL) + return (FALSE); + + pp = (UINT8 *)(p + 1); + + p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_LINK_KEY_REQ_REPLY; + p->offset = 0; + + UINT16_TO_STREAM (pp, HCI_LINK_KEY_REQUEST_REPLY); + UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_LINK_KEY_REQ_REPLY); + + BDADDR_TO_STREAM (pp, bd_addr); + ARRAY16_TO_STREAM (pp, link_key); + + btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p); + return (TRUE); +} + +BOOLEAN btsnd_hcic_link_key_neg_reply (BD_ADDR bd_addr) +{ + BT_HDR *p; + UINT8 *pp; + + if ((p = HCI_GET_CMD_BUF(HCIC_PARAM_SIZE_LINK_KEY_NEG_REPLY)) == NULL) + return (FALSE); + + pp = (UINT8 *)(p + 1); + + p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_LINK_KEY_NEG_REPLY; + p->offset = 0; + + UINT16_TO_STREAM (pp, HCI_LINK_KEY_REQUEST_NEG_REPLY); + UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_LINK_KEY_NEG_REPLY); + + BDADDR_TO_STREAM (pp, bd_addr); + + btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p); + return (TRUE); +} + +BOOLEAN btsnd_hcic_pin_code_req_reply (BD_ADDR bd_addr, UINT8 pin_code_len, + PIN_CODE pin_code) +{ + BT_HDR *p; + UINT8 *pp; + int i; + + if ((p = HCI_GET_CMD_BUF(HCIC_PARAM_SIZE_PIN_CODE_REQ_REPLY)) == NULL) + return (FALSE); + + pp = (UINT8 *)(p + 1); + + p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_PIN_CODE_REQ_REPLY; + p->offset = 0; + + UINT16_TO_STREAM (pp, HCI_PIN_CODE_REQUEST_REPLY); + UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_PIN_CODE_REQ_REPLY); + + BDADDR_TO_STREAM (pp, bd_addr); + UINT8_TO_STREAM (pp, pin_code_len); + + for (i = 0; i < pin_code_len; i++) + *pp++ = *pin_code++; + + for (; i < PIN_CODE_LEN; i++) + *pp++ = 0; + + + btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p); + return (TRUE); +} + +BOOLEAN btsnd_hcic_pin_code_neg_reply (BD_ADDR bd_addr) +{ + BT_HDR *p; + UINT8 *pp; + + if ((p = HCI_GET_CMD_BUF(HCIC_PARAM_SIZE_PIN_CODE_NEG_REPLY)) == NULL) + return (FALSE); + + pp = (UINT8 *)(p + 1); + + p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_PIN_CODE_NEG_REPLY; + p->offset = 0; + + UINT16_TO_STREAM (pp, HCI_PIN_CODE_REQUEST_NEG_REPLY); + UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_PIN_CODE_NEG_REPLY); + + BDADDR_TO_STREAM (pp, bd_addr); + + btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p); + return (TRUE); +} + +BOOLEAN btsnd_hcic_change_conn_type (UINT16 handle, UINT16 packet_types) +{ + BT_HDR *p; + UINT8 *pp; + + if ((p = HCI_GET_CMD_BUF(HCIC_PARAM_SIZE_CHANGE_CONN_TYPE)) == NULL) + return (FALSE); + + pp = (UINT8 *)(p + 1); + + p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_CHANGE_CONN_TYPE; + p->offset = 0; + + UINT16_TO_STREAM (pp, HCI_CHANGE_CONN_PACKET_TYPE); + UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_CHANGE_CONN_TYPE); + + UINT16_TO_STREAM (pp, handle); + UINT16_TO_STREAM (pp, packet_types); + + btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p); + return (TRUE); +} + +BOOLEAN btsnd_hcic_auth_request (UINT16 handle) +{ + BT_HDR *p; + UINT8 *pp; + + if ((p = HCI_GET_CMD_BUF(HCIC_PARAM_SIZE_CMD_HANDLE)) == NULL) + return (FALSE); + + pp = (UINT8 *)(p + 1); + + p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_CMD_HANDLE; + p->offset = 0; + + UINT16_TO_STREAM (pp, HCI_AUTHENTICATION_REQUESTED); + UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_CMD_HANDLE); + + UINT16_TO_STREAM (pp, handle); + + btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p); + return (TRUE); +} + +BOOLEAN btsnd_hcic_set_conn_encrypt (UINT16 handle, BOOLEAN enable) +{ + BT_HDR *p; + UINT8 *pp; + + if ((p = HCI_GET_CMD_BUF(HCIC_PARAM_SIZE_SET_CONN_ENCRYPT)) == NULL) + return (FALSE); + + pp = (UINT8 *)(p + 1); + + p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_SET_CONN_ENCRYPT; + p->offset = 0; + + UINT16_TO_STREAM (pp, HCI_SET_CONN_ENCRYPTION); + UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_SET_CONN_ENCRYPT); + + UINT16_TO_STREAM (pp, handle); + UINT8_TO_STREAM (pp, enable); + + btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p); + return (TRUE); +} + +BOOLEAN btsnd_hcic_rmt_name_req (BD_ADDR bd_addr, UINT8 page_scan_rep_mode, + UINT8 page_scan_mode, UINT16 clock_offset) +{ + BT_HDR *p; + UINT8 *pp; + + if ((p = HCI_GET_CMD_BUF(HCIC_PARAM_SIZE_RMT_NAME_REQ)) == NULL) + return (FALSE); + + pp = (UINT8 *)(p + 1); + + p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_RMT_NAME_REQ; + p->offset = 0; + + UINT16_TO_STREAM (pp, HCI_RMT_NAME_REQUEST); + UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_RMT_NAME_REQ); + + BDADDR_TO_STREAM (pp, bd_addr); + UINT8_TO_STREAM (pp, page_scan_rep_mode); + UINT8_TO_STREAM (pp, page_scan_mode); + UINT16_TO_STREAM (pp, clock_offset); + + btm_acl_paging (p, bd_addr); + return (TRUE); +} + +BOOLEAN btsnd_hcic_rmt_name_req_cancel (BD_ADDR bd_addr) +{ + BT_HDR *p; + UINT8 *pp; + + if ((p = HCI_GET_CMD_BUF(HCIC_PARAM_SIZE_RMT_NAME_REQ_CANCEL)) == NULL) + return (FALSE); + + pp = (UINT8 *)(p + 1); + + p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_RMT_NAME_REQ_CANCEL; + p->offset = 0; + + UINT16_TO_STREAM (pp, HCI_RMT_NAME_REQUEST_CANCEL); + UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_RMT_NAME_REQ_CANCEL); + + BDADDR_TO_STREAM (pp, bd_addr); + + btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p); + return (TRUE); +} + +BOOLEAN btsnd_hcic_rmt_features_req (UINT16 handle) +{ + BT_HDR *p; + UINT8 *pp; + + if ((p = HCI_GET_CMD_BUF(HCIC_PARAM_SIZE_CMD_HANDLE)) == NULL) + return (FALSE); + + pp = (UINT8 *)(p + 1); + + p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_CMD_HANDLE; + p->offset = 0; + + UINT16_TO_STREAM (pp, HCI_READ_RMT_FEATURES); + UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_CMD_HANDLE); + + UINT16_TO_STREAM (pp, handle); + + btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p); + return (TRUE); +} + +BOOLEAN btsnd_hcic_rmt_ext_features (UINT16 handle, UINT8 page_num) +{ + BT_HDR *p; + UINT8 *pp; + + if ((p = HCI_GET_CMD_BUF(HCIC_PARAM_SIZE_RMT_EXT_FEATURES)) == NULL) + return (FALSE); + + pp = (UINT8 *)(p + 1); + + p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_RMT_EXT_FEATURES; + p->offset = 0; + + UINT16_TO_STREAM (pp, HCI_READ_RMT_EXT_FEATURES); + UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_RMT_EXT_FEATURES); + + UINT16_TO_STREAM (pp, handle); + UINT8_TO_STREAM (pp, page_num); + + btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p); + return (TRUE); +} + +BOOLEAN btsnd_hcic_rmt_ver_req (UINT16 handle) +{ + BT_HDR *p; + UINT8 *pp; + + if ((p = HCI_GET_CMD_BUF(HCIC_PARAM_SIZE_CMD_HANDLE)) == NULL) + return (FALSE); + + pp = (UINT8 *)(p + 1); + + p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_CMD_HANDLE; + p->offset = 0; + + UINT16_TO_STREAM (pp, HCI_READ_RMT_VERSION_INFO); + UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_CMD_HANDLE); + + UINT16_TO_STREAM (pp, handle); + + btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p); + return (TRUE); +} + +BOOLEAN btsnd_hcic_read_rmt_clk_offset (UINT16 handle) +{ + BT_HDR *p; + UINT8 *pp; + + if ((p = HCI_GET_CMD_BUF(HCIC_PARAM_SIZE_CMD_HANDLE)) == NULL) + return (FALSE); + + pp = (UINT8 *)(p + 1); + + p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_CMD_HANDLE; + p->offset = 0; + + UINT16_TO_STREAM (pp, HCI_READ_RMT_CLOCK_OFFSET); + UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_CMD_HANDLE); + + UINT16_TO_STREAM (pp, handle); + + btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p); + return (TRUE); +} + +BOOLEAN btsnd_hcic_read_lmp_handle (UINT16 handle) +{ + BT_HDR *p; + UINT8 *pp; + + if ((p = HCI_GET_CMD_BUF(HCIC_PARAM_SIZE_CMD_HANDLE)) == NULL) + return (FALSE); + + pp = (UINT8 *)(p + 1); + + p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_CMD_HANDLE; + p->offset = 0; + + UINT16_TO_STREAM (pp, HCI_READ_LMP_HANDLE); + UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_CMD_HANDLE); + + UINT16_TO_STREAM (pp, handle); + + btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p); + return (TRUE); +} + +BOOLEAN btsnd_hcic_setup_esco_conn (UINT16 handle, UINT32 tx_bw, + UINT32 rx_bw, UINT16 max_latency, UINT16 voice, + UINT8 retrans_effort, UINT16 packet_types) +{ + BT_HDR *p; + UINT8 *pp; + + if ((p = HCI_GET_CMD_BUF(HCIC_PARAM_SIZE_SETUP_ESCO)) == NULL) + return (FALSE); + + pp = (UINT8 *)(p + 1); + + p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_SETUP_ESCO; + p->offset = 0; + + UINT16_TO_STREAM (pp, HCI_SETUP_ESCO_CONNECTION); + UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_SETUP_ESCO); + + UINT16_TO_STREAM (pp, handle); + UINT32_TO_STREAM (pp, tx_bw); + UINT32_TO_STREAM (pp, rx_bw); + UINT16_TO_STREAM (pp, max_latency); + UINT16_TO_STREAM (pp, voice); + UINT8_TO_STREAM (pp, retrans_effort); + UINT16_TO_STREAM (pp, packet_types); + + btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p); + return (TRUE); +} + +BOOLEAN btsnd_hcic_accept_esco_conn (BD_ADDR bd_addr, UINT32 tx_bw, + UINT32 rx_bw, UINT16 max_latency, + UINT16 content_fmt, UINT8 retrans_effort, + UINT16 packet_types) +{ + BT_HDR *p; + UINT8 *pp; + + if ((p = HCI_GET_CMD_BUF(HCIC_PARAM_SIZE_ACCEPT_ESCO)) == NULL) + return (FALSE); + + pp = (UINT8 *)(p + 1); + + p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_ACCEPT_ESCO; + p->offset = 0; + + UINT16_TO_STREAM (pp, HCI_ACCEPT_ESCO_CONNECTION); + UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_ACCEPT_ESCO); + + BDADDR_TO_STREAM (pp, bd_addr); + UINT32_TO_STREAM (pp, tx_bw); + UINT32_TO_STREAM (pp, rx_bw); + UINT16_TO_STREAM (pp, max_latency); + UINT16_TO_STREAM (pp, content_fmt); + UINT8_TO_STREAM (pp, retrans_effort); + UINT16_TO_STREAM (pp, packet_types); + + btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p); + return (TRUE); +} + +BOOLEAN btsnd_hcic_reject_esco_conn (BD_ADDR bd_addr, UINT8 reason) +{ + BT_HDR *p; + UINT8 *pp; + + if ((p = HCI_GET_CMD_BUF(HCIC_PARAM_SIZE_REJECT_ESCO)) == NULL) + return (FALSE); + + pp = (UINT8 *)(p + 1); + + p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_REJECT_ESCO; + p->offset = 0; + + UINT16_TO_STREAM (pp, HCI_REJECT_ESCO_CONNECTION); + UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_REJECT_ESCO); + + BDADDR_TO_STREAM (pp, bd_addr); + UINT8_TO_STREAM (pp, reason); + + btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p); + return (TRUE); +} + +BOOLEAN btsnd_hcic_hold_mode (UINT16 handle, UINT16 max_hold_period, + UINT16 min_hold_period) +{ + BT_HDR *p; + UINT8 *pp; + + if ((p = HCI_GET_CMD_BUF(HCIC_PARAM_SIZE_HOLD_MODE)) == NULL) + return (FALSE); + + pp = (UINT8 *)(p + 1); + + p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_HOLD_MODE; + p->offset = 0; + + UINT16_TO_STREAM (pp, HCI_HOLD_MODE); + UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_HOLD_MODE); + + UINT16_TO_STREAM (pp, handle); + UINT16_TO_STREAM (pp, max_hold_period); + UINT16_TO_STREAM (pp, min_hold_period); + + btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p); + return (TRUE); +} + +BOOLEAN btsnd_hcic_sniff_mode (UINT16 handle, UINT16 max_sniff_period, + UINT16 min_sniff_period, UINT16 sniff_attempt, + UINT16 sniff_timeout) +{ + BT_HDR *p; + UINT8 *pp; + + if ((p = HCI_GET_CMD_BUF(HCIC_PARAM_SIZE_SNIFF_MODE)) == NULL) + return (FALSE); + + pp = (UINT8 *)(p + 1); + + p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_SNIFF_MODE; + p->offset = 0; + + UINT16_TO_STREAM (pp, HCI_SNIFF_MODE); + UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_SNIFF_MODE); + + UINT16_TO_STREAM (pp, handle); + UINT16_TO_STREAM (pp, max_sniff_period); + UINT16_TO_STREAM (pp, min_sniff_period); + UINT16_TO_STREAM (pp, sniff_attempt); + UINT16_TO_STREAM (pp, sniff_timeout); + + btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p); + return (TRUE); +} + +BOOLEAN btsnd_hcic_exit_sniff_mode (UINT16 handle) +{ + BT_HDR *p; + UINT8 *pp; + + if ((p = HCI_GET_CMD_BUF(HCIC_PARAM_SIZE_CMD_HANDLE)) == NULL) + return (FALSE); + + pp = (UINT8 *)(p + 1); + + p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_CMD_HANDLE; + p->offset = 0; + + UINT16_TO_STREAM (pp, HCI_EXIT_SNIFF_MODE); + UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_CMD_HANDLE); + + UINT16_TO_STREAM (pp, handle); + + btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p); + return TRUE; +} + +BOOLEAN btsnd_hcic_park_mode (UINT16 handle, UINT16 beacon_max_interval, + UINT16 beacon_min_interval) +{ + BT_HDR *p; + UINT8 *pp; + + if ((p = HCI_GET_CMD_BUF(HCIC_PARAM_SIZE_PARK_MODE)) == NULL) + return (FALSE); + + pp = (UINT8 *)(p + 1); + + p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_PARK_MODE; + p->offset = 0; + + UINT16_TO_STREAM (pp, HCI_PARK_MODE); + UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_PARK_MODE); + + UINT16_TO_STREAM (pp, handle); + UINT16_TO_STREAM (pp, beacon_max_interval); + UINT16_TO_STREAM (pp, beacon_min_interval); + + btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p); + return (TRUE); +} + +BOOLEAN btsnd_hcic_exit_park_mode (UINT16 handle) +{ + BT_HDR *p; + UINT8 *pp; + + if ((p = HCI_GET_CMD_BUF(HCIC_PARAM_SIZE_CMD_HANDLE)) == NULL) + return (FALSE); + + pp = (UINT8 *)(p + 1); + + p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_CMD_HANDLE; + p->offset = 0; + + UINT16_TO_STREAM (pp, HCI_EXIT_PARK_MODE); + UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_CMD_HANDLE); + + UINT16_TO_STREAM (pp, handle); + + btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p); + return TRUE; +} + +BOOLEAN btsnd_hcic_qos_setup (UINT16 handle, UINT8 flags, UINT8 service_type, + UINT32 token_rate, UINT32 peak, UINT32 latency, + UINT32 delay_var) +{ + BT_HDR *p; + UINT8 *pp; + + if ((p = HCI_GET_CMD_BUF(HCIC_PARAM_SIZE_QOS_SETUP)) == NULL) + return (FALSE); + + pp = (UINT8 *)(p + 1); + + p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_QOS_SETUP; + p->offset = 0; + + UINT16_TO_STREAM (pp, HCI_QOS_SETUP); + UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_QOS_SETUP); + + UINT16_TO_STREAM (pp, handle); + UINT8_TO_STREAM (pp, flags); + UINT8_TO_STREAM (pp, service_type); + UINT32_TO_STREAM (pp, token_rate); + UINT32_TO_STREAM (pp, peak); + UINT32_TO_STREAM (pp, latency); + UINT32_TO_STREAM (pp, delay_var); + + btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p); + return (TRUE); +} + +BOOLEAN btsnd_hcic_switch_role (BD_ADDR bd_addr, UINT8 role) +{ + BT_HDR *p; + UINT8 *pp; + + if ((p = HCI_GET_CMD_BUF(HCIC_PARAM_SIZE_SWITCH_ROLE)) == NULL) + return (FALSE); + + pp = (UINT8 *)(p + 1); + + p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_SWITCH_ROLE; + p->offset = 0; + + UINT16_TO_STREAM (pp, HCI_SWITCH_ROLE); + UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_SWITCH_ROLE); + + BDADDR_TO_STREAM (pp, bd_addr); + UINT8_TO_STREAM (pp, role); + + btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p); + return (TRUE); +} + +BOOLEAN btsnd_hcic_write_policy_set (UINT16 handle, UINT16 settings) +{ + BT_HDR *p; + UINT8 *pp; + + if ((p = HCI_GET_CMD_BUF(HCIC_PARAM_SIZE_WRITE_POLICY_SET)) == NULL) + return (FALSE); + + pp = (UINT8 *)(p + 1); + + p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_WRITE_POLICY_SET; + p->offset = 0; + UINT16_TO_STREAM (pp, HCI_WRITE_POLICY_SETTINGS); + UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_WRITE_POLICY_SET); + + UINT16_TO_STREAM (pp, handle); + UINT16_TO_STREAM (pp, settings); + + btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p); + return (TRUE); +} + +BOOLEAN btsnd_hcic_write_def_policy_set (UINT16 settings) +{ + BT_HDR *p; + UINT8 *pp; + + if ((p = HCI_GET_CMD_BUF(HCIC_PARAM_SIZE_WRITE_DEF_POLICY_SET)) == NULL) + return (FALSE); + + pp = (UINT8 *)(p + 1); + + p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_WRITE_DEF_POLICY_SET; + p->offset = 0; + UINT16_TO_STREAM (pp, HCI_WRITE_DEF_POLICY_SETTINGS); + UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_WRITE_DEF_POLICY_SET); + + UINT16_TO_STREAM (pp, settings); + + btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p); + return (TRUE); +} + +BOOLEAN btsnd_hcic_set_event_filter (UINT8 filt_type, UINT8 filt_cond_type, + UINT8 *filt_cond, UINT8 filt_cond_len) +{ + BT_HDR *p; + UINT8 *pp; + + /* Use buffer large enough to hold all sizes in this command */ + if ((p = HCI_GET_CMD_BUF(2 + filt_cond_len)) == NULL) + return (FALSE); + + pp = (UINT8 *)(p + 1); + + p->offset = 0; + + UINT16_TO_STREAM (pp, HCI_SET_EVENT_FILTER); + + if (filt_type) + { + p->len = (UINT16)(HCIC_PREAMBLE_SIZE + 2 + filt_cond_len); + UINT8_TO_STREAM (pp, (UINT8)(2 + filt_cond_len)); + + UINT8_TO_STREAM (pp, filt_type); + UINT8_TO_STREAM (pp, filt_cond_type); + + if (filt_cond_type == HCI_FILTER_COND_DEVICE_CLASS) + { + DEVCLASS_TO_STREAM (pp, filt_cond); + filt_cond += DEV_CLASS_LEN; + DEVCLASS_TO_STREAM (pp, filt_cond); + filt_cond += DEV_CLASS_LEN; + + filt_cond_len -= (2 * DEV_CLASS_LEN); + } + else if (filt_cond_type == HCI_FILTER_COND_BD_ADDR) + { + BDADDR_TO_STREAM (pp, filt_cond); + filt_cond += BD_ADDR_LEN; + + filt_cond_len -= BD_ADDR_LEN; + } + + if (filt_cond_len) + ARRAY_TO_STREAM (pp, filt_cond, filt_cond_len); + } + else + { + p->len = (UINT16)(HCIC_PREAMBLE_SIZE + 1); + UINT8_TO_STREAM (pp, 1); + + UINT8_TO_STREAM (pp, filt_type); + } + + btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p); + return (TRUE); +} + +BOOLEAN btsnd_hcic_write_pin_type (UINT8 type) +{ + BT_HDR *p; + UINT8 *pp; + + if ((p = HCI_GET_CMD_BUF(HCIC_PARAM_SIZE_WRITE_PARAM1)) == NULL) + return (FALSE); + + pp = (UINT8 *)(p + 1); + + p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_WRITE_PARAM1; + p->offset = 0; + + UINT16_TO_STREAM (pp, HCI_WRITE_PIN_TYPE); + UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_WRITE_PARAM1); + + UINT8_TO_STREAM (pp, type); + + btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p); + return (TRUE); +} + +BOOLEAN btsnd_hcic_delete_stored_key (BD_ADDR bd_addr, BOOLEAN delete_all_flag) +{ + BT_HDR *p; + UINT8 *pp; + + if ((p = HCI_GET_CMD_BUF(HCIC_PARAM_SIZE_DELETE_STORED_KEY)) == NULL) + return (FALSE); + + pp = (UINT8 *)(p + 1); + + p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_DELETE_STORED_KEY; + p->offset = 0; + + UINT16_TO_STREAM (pp, HCI_DELETE_STORED_LINK_KEY); + UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_DELETE_STORED_KEY); + + BDADDR_TO_STREAM (pp, bd_addr); + UINT8_TO_STREAM (pp, delete_all_flag); + + btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p); + return (TRUE); +} + +BOOLEAN btsnd_hcic_change_name (BD_NAME name) +{ + BT_HDR *p; + UINT8 *pp; + UINT16 len = strlen ((char *)name) + 1; + + if ((p = HCI_GET_CMD_BUF(HCIC_PARAM_SIZE_CHANGE_NAME)) == NULL) + return (FALSE); + + pp = (UINT8 *)(p + 1); + memset(pp, 0, HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_CHANGE_NAME); + + p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_CHANGE_NAME; + p->offset = 0; + + UINT16_TO_STREAM (pp, HCI_CHANGE_LOCAL_NAME); + UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_CHANGE_NAME); + + if (len > HCIC_PARAM_SIZE_CHANGE_NAME) + len = HCIC_PARAM_SIZE_CHANGE_NAME; + + ARRAY_TO_STREAM (pp, name, len); + + btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p); + return (TRUE); +} + +BOOLEAN btsnd_hcic_read_name (void) +{ + BT_HDR *p; + UINT8 *pp; + + if ((p = HCI_GET_CMD_BUF(HCIC_PARAM_SIZE_READ_CMD)) == NULL) + return (FALSE); + + pp = (UINT8 *)(p + 1); + + p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_READ_CMD; + p->offset = 0; + + UINT16_TO_STREAM (pp, HCI_READ_LOCAL_NAME); + UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_READ_CMD); + + btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p); + return (TRUE); +} + +BOOLEAN btsnd_hcic_write_page_tout (UINT16 timeout) +{ + BT_HDR *p; + UINT8 *pp; + + if ((p = HCI_GET_CMD_BUF(HCIC_PARAM_SIZE_WRITE_PARAM2)) == NULL) + return (FALSE); + + pp = (UINT8 *)(p + 1); + + p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_WRITE_PARAM2; + p->offset = 0; + + UINT16_TO_STREAM (pp, HCI_WRITE_PAGE_TOUT); + UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_WRITE_PARAM2); + + UINT16_TO_STREAM (pp, timeout); + + btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p); + return (TRUE); +} + +BOOLEAN btsnd_hcic_write_scan_enable (UINT8 flag) +{ + BT_HDR *p; + UINT8 *pp; + + if ((p = HCI_GET_CMD_BUF(HCIC_PARAM_SIZE_WRITE_PARAM1)) == NULL) + return (FALSE); + + pp = (UINT8 *)(p + 1); + + p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_WRITE_PARAM1; + p->offset = 0; + + UINT16_TO_STREAM (pp, HCI_WRITE_SCAN_ENABLE); + UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_WRITE_PARAM1); + + UINT8_TO_STREAM (pp, flag); + + btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p); + return (TRUE); +} + +BOOLEAN btsnd_hcic_write_pagescan_cfg(UINT16 interval, UINT16 window) +{ + BT_HDR *p; + UINT8 *pp; + + if ((p = HCI_GET_CMD_BUF(HCIC_PARAM_SIZE_WRITE_PAGESCAN_CFG)) == NULL) + return (FALSE); + + pp = (UINT8 *)(p + 1); + + p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_WRITE_PAGESCAN_CFG; + p->offset = 0; + + UINT16_TO_STREAM (pp, HCI_WRITE_PAGESCAN_CFG); + UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_WRITE_PAGESCAN_CFG); + + UINT16_TO_STREAM (pp, interval); + UINT16_TO_STREAM (pp, window); + + btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p); + return (TRUE); +} + +BOOLEAN btsnd_hcic_write_inqscan_cfg(UINT16 interval, UINT16 window) +{ + BT_HDR *p; + UINT8 *pp; + + if ((p = HCI_GET_CMD_BUF(HCIC_PARAM_SIZE_WRITE_INQSCAN_CFG)) == NULL) + return (FALSE); + + pp = (UINT8 *)(p + 1); + + p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_WRITE_INQSCAN_CFG; + p->offset = 0; + + UINT16_TO_STREAM (pp, HCI_WRITE_INQUIRYSCAN_CFG); + UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_WRITE_INQSCAN_CFG); + + UINT16_TO_STREAM (pp, interval); + UINT16_TO_STREAM (pp, window); + + btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p); + return (TRUE); +} + +BOOLEAN btsnd_hcic_write_auth_enable (UINT8 flag) +{ + BT_HDR *p; + UINT8 *pp; + + if ((p = HCI_GET_CMD_BUF(HCIC_PARAM_SIZE_WRITE_PARAM1)) == NULL) + return (FALSE); + + pp = (UINT8 *)(p + 1); + + p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_WRITE_PARAM1; + p->offset = 0; + + UINT16_TO_STREAM (pp, HCI_WRITE_AUTHENTICATION_ENABLE); + UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_WRITE_PARAM1); + + UINT8_TO_STREAM (pp, flag); + + btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p); + return (TRUE); +} + +BOOLEAN btsnd_hcic_write_dev_class(DEV_CLASS dev_class) +{ + BT_HDR *p; + UINT8 *pp; + + if ((p = HCI_GET_CMD_BUF(HCIC_PARAM_SIZE_WRITE_PARAM3)) == NULL) + return (FALSE); + + pp = (UINT8 *)(p + 1); + + p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_WRITE_PARAM3; + p->offset = 0; + + UINT16_TO_STREAM (pp, HCI_WRITE_CLASS_OF_DEVICE); + UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_WRITE_PARAM3); + + DEVCLASS_TO_STREAM (pp, dev_class); + + btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p); + return (TRUE); +} + +BOOLEAN btsnd_hcic_write_voice_settings(UINT16 flags) +{ + BT_HDR *p; + UINT8 *pp; + + if ((p = HCI_GET_CMD_BUF(HCIC_PARAM_SIZE_WRITE_PARAM2)) == NULL) + return (FALSE); + + pp = (UINT8 *)(p + 1); + + p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_WRITE_PARAM2; + p->offset = 0; + + UINT16_TO_STREAM (pp, HCI_WRITE_VOICE_SETTINGS); + UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_WRITE_PARAM2); + + UINT16_TO_STREAM (pp, flags); + + btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p); + return (TRUE); +} + +BOOLEAN btsnd_hcic_write_auto_flush_tout (UINT16 handle, UINT16 tout) +{ + BT_HDR *p; + UINT8 *pp; + + if ((p = HCI_GET_CMD_BUF(HCIC_PARAM_SIZE_WRITE_AUTO_FLUSH_TOUT)) == NULL) + return (FALSE); + + pp = (UINT8 *)(p + 1); + + p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_WRITE_AUTO_FLUSH_TOUT; + p->offset = 0; + + UINT16_TO_STREAM (pp, HCI_WRITE_AUTO_FLUSH_TOUT); + UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_WRITE_AUTO_FLUSH_TOUT); + + UINT16_TO_STREAM (pp, handle); + UINT16_TO_STREAM (pp, tout); + + btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p); + return (TRUE); +} + +BOOLEAN btsnd_hcic_read_tx_power (UINT16 handle, UINT8 type) +{ + BT_HDR *p; + UINT8 *pp; + + if ((p = HCI_GET_CMD_BUF(HCIC_PARAM_SIZE_READ_TX_POWER)) == NULL) + return (FALSE); + + pp = (UINT8 *)(p + 1); + + p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_READ_TX_POWER; + p->offset = 0; + + UINT16_TO_STREAM (pp, HCI_READ_TRANSMIT_POWER_LEVEL); + UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_READ_TX_POWER); + + UINT16_TO_STREAM (pp, handle); + UINT8_TO_STREAM (pp, type); + + btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p); + return (TRUE); +} + +BOOLEAN btsnd_hcic_host_num_xmitted_pkts (UINT8 num_handles, UINT16 *handle, + UINT16 *num_pkts) +{ + BT_HDR *p; + UINT8 *pp; + int j; + + if ((p = HCI_GET_CMD_BUF(1 + (num_handles * 4))) == NULL) + return (FALSE); + + pp = (UINT8 *)(p + 1); + + p->len = HCIC_PREAMBLE_SIZE + 1 + (num_handles * 4); + p->offset = 0; + + UINT16_TO_STREAM (pp, HCI_HOST_NUM_PACKETS_DONE); + UINT8_TO_STREAM (pp, p->len - HCIC_PREAMBLE_SIZE); + + UINT8_TO_STREAM (pp, num_handles); + + for (j = 0; j < num_handles; j++) + { + UINT16_TO_STREAM (pp, handle[j]); + UINT16_TO_STREAM (pp, num_pkts[j]); + } + + btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p); + return (TRUE); +} + +BOOLEAN btsnd_hcic_write_link_super_tout (UINT8 local_controller_id, UINT16 handle, UINT16 timeout) +{ + BT_HDR *p; + UINT8 *pp; + + if ((p = HCI_GET_CMD_BUF(HCIC_PARAM_SIZE_WRITE_LINK_SUPER_TOUT)) == NULL) + return (FALSE); + + pp = (UINT8 *)(p + 1); + + p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_WRITE_LINK_SUPER_TOUT; + p->offset = 0; + + UINT16_TO_STREAM (pp, HCI_WRITE_LINK_SUPER_TOUT); + UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_WRITE_LINK_SUPER_TOUT); + + UINT16_TO_STREAM (pp, handle); + UINT16_TO_STREAM (pp, timeout); + + btu_hcif_send_cmd (local_controller_id, p); + return (TRUE); +} + +BOOLEAN btsnd_hcic_write_cur_iac_lap (UINT8 num_cur_iac, LAP * const iac_lap) +{ + BT_HDR *p; + UINT8 *pp; + int i; + + if ((p = HCI_GET_CMD_BUF(1 + (LAP_LEN * num_cur_iac))) == NULL) + return (FALSE); + + pp = (UINT8 *)(p + 1); + + p->len = HCIC_PREAMBLE_SIZE + 1 + (LAP_LEN * num_cur_iac); + p->offset = 0; + + UINT16_TO_STREAM (pp, HCI_WRITE_CURRENT_IAC_LAP); + UINT8_TO_STREAM (pp, p->len - HCIC_PREAMBLE_SIZE); + + UINT8_TO_STREAM (pp, num_cur_iac); + + for (i = 0; i < num_cur_iac; i++) + LAP_TO_STREAM (pp, iac_lap[i]); + + btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p); + return (TRUE); +} + +/****************************************** +** Lisbon Features +*******************************************/ +#if BTM_SSR_INCLUDED == TRUE + +BOOLEAN btsnd_hcic_sniff_sub_rate(UINT16 handle, UINT16 max_lat, + UINT16 min_remote_lat, UINT16 min_local_lat) +{ + BT_HDR *p; + UINT8 *pp; + + if ((p = HCI_GET_CMD_BUF(HCIC_PARAM_SIZE_SNIFF_SUB_RATE)) == NULL) + return (FALSE); + + pp = (UINT8 *)(p + 1); + + p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_SNIFF_SUB_RATE; + p->offset = 0; + + UINT16_TO_STREAM (pp, HCI_SNIFF_SUB_RATE); + UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_SNIFF_SUB_RATE); + + UINT16_TO_STREAM (pp, handle); + UINT16_TO_STREAM (pp, max_lat); + UINT16_TO_STREAM (pp, min_remote_lat); + UINT16_TO_STREAM (pp, min_local_lat); + + btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p); + return (TRUE); +} +#endif /* BTM_SSR_INCLUDED */ + +/**** Extended Inquiry Response Commands ****/ +void btsnd_hcic_write_ext_inquiry_response (void *buffer, UINT8 fec_req) +{ + BT_HDR *p = (BT_HDR *)buffer; + UINT8 *pp = (UINT8 *)(p + 1); + + p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_EXT_INQ_RESP; + p->offset = 0; + + UINT16_TO_STREAM (pp, HCI_WRITE_EXT_INQ_RESPONSE); + UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_EXT_INQ_RESP); + + UINT8_TO_STREAM (pp, fec_req); + + btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p); +} + +BOOLEAN btsnd_hcic_io_cap_req_reply (BD_ADDR bd_addr, UINT8 capability, + UINT8 oob_present, UINT8 auth_req) +{ + BT_HDR *p; + UINT8 *pp; + + if ((p = HCI_GET_CMD_BUF(HCIC_PARAM_SIZE_IO_CAP_RESP)) == NULL) + return (FALSE); + + pp = (UINT8 *)(p + 1); + + p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_IO_CAP_RESP; + p->offset = 0; + + UINT16_TO_STREAM (pp, HCI_IO_CAPABILITY_REQUEST_REPLY); + UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_IO_CAP_RESP); + + BDADDR_TO_STREAM (pp, bd_addr); + UINT8_TO_STREAM (pp, capability); + UINT8_TO_STREAM (pp, oob_present); + UINT8_TO_STREAM (pp, auth_req); + + btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p); + return (TRUE); +} + +BOOLEAN btsnd_hcic_io_cap_req_neg_reply (BD_ADDR bd_addr, UINT8 err_code) +{ + BT_HDR *p; + UINT8 *pp; + + if ((p = HCI_GET_CMD_BUF(HCIC_PARAM_SIZE_IO_CAP_NEG_REPLY)) == NULL) + return (FALSE); + + pp = (UINT8 *)(p + 1); + + p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_IO_CAP_NEG_REPLY; + p->offset = 0; + + UINT16_TO_STREAM (pp, HCI_IO_CAP_REQ_NEG_REPLY); + UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_IO_CAP_NEG_REPLY); + + BDADDR_TO_STREAM (pp, bd_addr); + UINT8_TO_STREAM (pp, err_code); + + btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p); + return (TRUE); +} + +BOOLEAN btsnd_hcic_read_local_oob_data (void) +{ + BT_HDR *p; + UINT8 *pp; + + if ((p = HCI_GET_CMD_BUF(HCIC_PARAM_SIZE_R_LOCAL_OOB)) == NULL) + return (FALSE); + + pp = (UINT8 *)(p + 1); + + p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_R_LOCAL_OOB; + p->offset = 0; + + UINT16_TO_STREAM (pp, HCI_READ_LOCAL_OOB_DATA); + UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_R_LOCAL_OOB); + + btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p); + return (TRUE); +} + +BOOLEAN btsnd_hcic_user_conf_reply (BD_ADDR bd_addr, BOOLEAN is_yes) +{ + BT_HDR *p; + UINT8 *pp; + + if ((p = HCI_GET_CMD_BUF(HCIC_PARAM_SIZE_UCONF_REPLY)) == NULL) + return (FALSE); + + pp = (UINT8 *)(p + 1); + + p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_UCONF_REPLY; + p->offset = 0; + + if (!is_yes) + { + /* Negative reply */ + UINT16_TO_STREAM (pp, HCI_USER_CONF_VALUE_NEG_REPLY); + } + else + { + /* Confirmation */ + UINT16_TO_STREAM (pp, HCI_USER_CONF_REQUEST_REPLY); + } + + UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_UCONF_REPLY); + + BDADDR_TO_STREAM (pp, bd_addr); + + btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p); + return (TRUE); +} + +BOOLEAN btsnd_hcic_user_passkey_reply (BD_ADDR bd_addr, UINT32 value) +{ + BT_HDR *p; + UINT8 *pp; + + if ((p = HCI_GET_CMD_BUF(HCIC_PARAM_SIZE_U_PKEY_REPLY)) == NULL) + return (FALSE); + + pp = (UINT8 *)(p + 1); + + p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_U_PKEY_REPLY; + p->offset = 0; + + UINT16_TO_STREAM (pp, HCI_USER_PASSKEY_REQ_REPLY); + UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_U_PKEY_REPLY); + + BDADDR_TO_STREAM (pp, bd_addr); + UINT32_TO_STREAM (pp, value); + + btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p); + return (TRUE); +} + +BOOLEAN btsnd_hcic_user_passkey_neg_reply (BD_ADDR bd_addr) +{ + BT_HDR *p; + UINT8 *pp; + + if ((p = HCI_GET_CMD_BUF(HCIC_PARAM_SIZE_U_PKEY_NEG_REPLY)) == NULL) + return (FALSE); + + pp = (UINT8 *)(p + 1); + + p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_U_PKEY_NEG_REPLY; + p->offset = 0; + + UINT16_TO_STREAM (pp, HCI_USER_PASSKEY_REQ_NEG_REPLY); + UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_U_PKEY_NEG_REPLY); + + BDADDR_TO_STREAM (pp, bd_addr); + + btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p); + return (TRUE); +} + +BOOLEAN btsnd_hcic_rem_oob_reply (BD_ADDR bd_addr, UINT8 *p_c, UINT8 *p_r) +{ + BT_HDR *p; + UINT8 *pp; + + if ((p = HCI_GET_CMD_BUF(HCIC_PARAM_SIZE_REM_OOB_REPLY)) == NULL) + return (FALSE); + + pp = (UINT8 *)(p + 1); + + p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_REM_OOB_REPLY; + p->offset = 0; + + UINT16_TO_STREAM (pp, HCI_REM_OOB_DATA_REQ_REPLY); + UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_REM_OOB_REPLY); + + BDADDR_TO_STREAM (pp, bd_addr); + ARRAY16_TO_STREAM (pp, p_c); + ARRAY16_TO_STREAM (pp, p_r); + + btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p); + return (TRUE); +} + +BOOLEAN btsnd_hcic_rem_oob_neg_reply (BD_ADDR bd_addr) +{ + BT_HDR *p; + UINT8 *pp; + + if ((p = HCI_GET_CMD_BUF(HCIC_PARAM_SIZE_REM_OOB_NEG_REPLY)) == NULL) + return (FALSE); + + pp = (UINT8 *)(p + 1); + + p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_REM_OOB_NEG_REPLY; + p->offset = 0; + + UINT16_TO_STREAM (pp, HCI_REM_OOB_DATA_REQ_NEG_REPLY); + UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_REM_OOB_NEG_REPLY); + + BDADDR_TO_STREAM (pp, bd_addr); + + btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p); + return (TRUE); +} + + +BOOLEAN btsnd_hcic_read_inq_tx_power (void) +{ + BT_HDR *p; + UINT8 *pp; + + if ((p = HCI_GET_CMD_BUF(HCIC_PARAM_SIZE_R_TX_POWER)) == NULL) + return (FALSE); + + pp = (UINT8 *)(p + 1); + + p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_R_TX_POWER; + p->offset = 0; + + UINT16_TO_STREAM (pp, HCI_READ_INQ_TX_POWER_LEVEL); + UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_R_TX_POWER); + + btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p); + return (TRUE); +} + +BOOLEAN btsnd_hcic_send_keypress_notif (BD_ADDR bd_addr, UINT8 notif) +{ + BT_HDR *p; + UINT8 *pp; + + if ((p = HCI_GET_CMD_BUF(HCIC_PARAM_SIZE_SEND_KEYPRESS_NOTIF)) == NULL) + return (FALSE); + + pp = (UINT8 *)(p + 1); + + p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_SEND_KEYPRESS_NOTIF; + p->offset = 0; + + UINT16_TO_STREAM (pp, HCI_SEND_KEYPRESS_NOTIF); + UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_SEND_KEYPRESS_NOTIF); + + BDADDR_TO_STREAM (pp, bd_addr); + UINT8_TO_STREAM (pp, notif); + + btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p); + return (TRUE); +} + +/**** end of Simple Pairing Commands ****/ + +#if L2CAP_NON_FLUSHABLE_PB_INCLUDED == TRUE +BOOLEAN btsnd_hcic_enhanced_flush (UINT16 handle, UINT8 packet_type) +{ + BT_HDR *p; + UINT8 *pp; + + if ((p = HCI_GET_CMD_BUF(HCIC_PARAM_SIZE_ENHANCED_FLUSH)) == NULL) + return (FALSE); + + pp = (UINT8 *)(p + 1); + + p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_ENHANCED_FLUSH; + p->offset = 0; + UINT16_TO_STREAM (pp, HCI_ENHANCED_FLUSH); + UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_ENHANCED_FLUSH); + + UINT16_TO_STREAM (pp, handle); + UINT8_TO_STREAM (pp, packet_type); + + btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p); + return (TRUE); +} +#endif + +/************************* +** End of Lisbon Commands +**************************/ + +BOOLEAN btsnd_hcic_get_link_quality (UINT16 handle) +{ + BT_HDR *p; + UINT8 *pp; + + if ((p = HCI_GET_CMD_BUF(HCIC_PARAM_SIZE_CMD_HANDLE)) == NULL) + return (FALSE); + + pp = (UINT8 *)(p + 1); + + p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_CMD_HANDLE; + p->offset = 0; + + UINT16_TO_STREAM (pp, HCI_GET_LINK_QUALITY); + UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_CMD_HANDLE); + + UINT16_TO_STREAM (pp, handle); + + btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p); + return (TRUE); +} + +BOOLEAN btsnd_hcic_read_rssi (UINT16 handle) +{ + BT_HDR *p; + UINT8 *pp; + + if ((p = HCI_GET_CMD_BUF(HCIC_PARAM_SIZE_CMD_HANDLE)) == NULL) + return (FALSE); + + pp = (UINT8 *)(p + 1); + + p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_CMD_HANDLE; + p->offset = 0; + + UINT16_TO_STREAM (pp, HCI_READ_RSSI); + UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_CMD_HANDLE); + + UINT16_TO_STREAM (pp, handle); + + btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p); + return (TRUE); +} + +BOOLEAN btsnd_hcic_enable_test_mode (void) +{ + BT_HDR *p; + UINT8 *pp; + + if ((p = HCI_GET_CMD_BUF(HCIC_PARAM_SIZE_READ_CMD)) == NULL) + return (FALSE); + + pp = (UINT8 *)(p + 1); + + p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_READ_CMD; + p->offset = 0; + + UINT16_TO_STREAM (pp, HCI_ENABLE_DEV_UNDER_TEST_MODE); + UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_READ_CMD); + + btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p); + return (TRUE); +} + +BOOLEAN btsnd_hcic_write_inqscan_type (UINT8 type) +{ + BT_HDR *p; + UINT8 *pp; + + if ((p = HCI_GET_CMD_BUF(HCIC_PARAM_SIZE_WRITE_PARAM1)) == NULL) + return (FALSE); + + pp = (UINT8 *)(p + 1); + + p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_WRITE_PARAM1; + p->offset = 0; + + UINT16_TO_STREAM (pp, HCI_WRITE_INQSCAN_TYPE); + UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_WRITE_PARAM1); + + UINT8_TO_STREAM (pp, type); + + btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p); + return (TRUE); +} + +BOOLEAN btsnd_hcic_write_inquiry_mode (UINT8 mode) +{ + BT_HDR *p; + UINT8 *pp; + + if ((p = HCI_GET_CMD_BUF(HCIC_PARAM_SIZE_WRITE_PARAM1)) == NULL) + return (FALSE); + + pp = (UINT8 *)(p + 1); + + p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_WRITE_PARAM1; + p->offset = 0; + + UINT16_TO_STREAM (pp, HCI_WRITE_INQUIRY_MODE); + UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_WRITE_PARAM1); + + UINT8_TO_STREAM (pp, mode); + + btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p); + return (TRUE); +} + +BOOLEAN btsnd_hcic_write_pagescan_type (UINT8 type) +{ + BT_HDR *p; + UINT8 *pp; + + if ((p = HCI_GET_CMD_BUF(HCIC_PARAM_SIZE_WRITE_PARAM1)) == NULL) + return (FALSE); + + pp = (UINT8 *)(p + 1); + + p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_WRITE_PARAM1; + p->offset = 0; + + UINT16_TO_STREAM (pp, HCI_WRITE_PAGESCAN_TYPE); + UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_WRITE_PARAM1); + + UINT8_TO_STREAM (pp, type); + + btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p); + return (TRUE); +} + +/* Must have room to store BT_HDR + max VSC length + callback pointer */ +#if (HCI_CMD_POOL_BUF_SIZE < 268) +#error "HCI_CMD_POOL_BUF_SIZE must be larger than 268" +#endif + +void btsnd_hcic_vendor_spec_cmd (void *buffer, UINT16 opcode, UINT8 len, + UINT8 *p_data, void *p_cmd_cplt_cback) +{ + BT_HDR *p = (BT_HDR *)buffer; + UINT8 *pp = (UINT8 *)(p + 1); + + p->len = HCIC_PREAMBLE_SIZE + len; + p->offset = sizeof(void *); + + *((void **)pp) = p_cmd_cplt_cback; /* Store command complete callback in buffer */ + pp += sizeof(void *); /* Skip over callback pointer */ + + UINT16_TO_STREAM (pp, HCI_GRP_VENDOR_SPECIFIC | opcode); + UINT8_TO_STREAM (pp, len); + ARRAY_TO_STREAM (pp, p_data, len); + + btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p); +} diff --git a/components/bt/bluedroid/stack/include/aes.h b/components/bt/bluedroid/stack/include/aes.h new file mode 100755 index 0000000000..add242e0a5 --- /dev/null +++ b/components/bt/bluedroid/stack/include/aes.h @@ -0,0 +1,162 @@ +/* + --------------------------------------------------------------------------- + Copyright (c) 1998-2008, Brian Gladman, Worcester, UK. All rights reserved. + + LICENSE TERMS + + The redistribution and use of this software (with or without changes) + is allowed without the payment of fees or royalties provided that: + + 1. source code distributions include the above copyright notice, this + list of conditions and the following disclaimer; + + 2. binary distributions include the above copyright notice, this list + of conditions and the following disclaimer in their documentation; + + 3. the name of the copyright holder is not used to endorse products + built using this software without specific written permission. + + DISCLAIMER + + This software is provided 'as is' with no explicit or implied warranties + in respect of its properties, including, but not limited to, correctness + and/or fitness for purpose. + --------------------------------------------------------------------------- + Issue 09/09/2006 + + This is an AES implementation that uses only 8-bit byte operations on the + cipher state. + */ + +#ifndef AES_H +#define AES_H + +#if 1 +# define AES_ENC_PREKEYED /* AES encryption with a precomputed key schedule */ +#endif +#if 1 +# define AES_DEC_PREKEYED /* AES decryption with a precomputed key schedule */ +#endif +#if 1 +# define AES_ENC_128_OTFK /* AES encryption with 'on the fly' 128 bit keying */ +#endif +#if 1 +# define AES_DEC_128_OTFK /* AES decryption with 'on the fly' 128 bit keying */ +#endif +#if 1 +# define AES_ENC_256_OTFK /* AES encryption with 'on the fly' 256 bit keying */ +#endif +#if 1 +# define AES_DEC_256_OTFK /* AES decryption with 'on the fly' 256 bit keying */ +#endif + +#define N_ROW 4 +#define N_COL 4 +#define N_BLOCK (N_ROW * N_COL) +#define N_MAX_ROUNDS 14 + +typedef unsigned char uint_8t; + +typedef uint_8t return_type; + +/* Warning: The key length for 256 bit keys overflows a byte + (see comment below) +*/ + +typedef uint_8t length_type; + +typedef struct +{ uint_8t ksch[(N_MAX_ROUNDS + 1) * N_BLOCK]; + uint_8t rnd; +} aes_context; + +/* The following calls are for a precomputed key schedule + + NOTE: If the length_type used for the key length is an + unsigned 8-bit character, a key length of 256 bits must + be entered as a length in bytes (valid inputs are hence + 128, 192, 16, 24 and 32). +*/ + +#if defined( AES_ENC_PREKEYED ) || defined( AES_DEC_PREKEYED ) + +return_type aes_set_key( const unsigned char key[], + length_type keylen, + aes_context ctx[1] ); +#endif + +#if defined( AES_ENC_PREKEYED ) + +return_type bluedroid_aes_encrypt( const unsigned char in[N_BLOCK], + unsigned char out[N_BLOCK], + const aes_context ctx[1] ); + +return_type aes_cbc_encrypt( const unsigned char *in, + unsigned char *out, + int n_block, + unsigned char iv[N_BLOCK], + const aes_context ctx[1] ); +#endif + +#if defined( AES_DEC_PREKEYED ) + +return_type bluedroid_aes_decrypt( const unsigned char in[N_BLOCK], + unsigned char out[N_BLOCK], + const aes_context ctx[1] ); + +return_type aes_cbc_decrypt( const unsigned char *in, + unsigned char *out, + int n_block, + unsigned char iv[N_BLOCK], + const aes_context ctx[1] ); +#endif + +/* The following calls are for 'on the fly' keying. In this case the + encryption and decryption keys are different. + + The encryption subroutines take a key in an array of bytes in + key[L] where L is 16, 24 or 32 bytes for key lengths of 128, + 192, and 256 bits respectively. They then encrypts the input + data, in[] with this key and put the reult in the output array + out[]. In addition, the second key array, o_key[L], is used + to output the key that is needed by the decryption subroutine + to reverse the encryption operation. The two key arrays can + be the same array but in this case the original key will be + overwritten. + + In the same way, the decryption subroutines output keys that + can be used to reverse their effect when used for encryption. + + Only 128 and 256 bit keys are supported in these 'on the fly' + modes. +*/ + +#if defined( AES_ENC_128_OTFK ) +void bluedroid_aes_encrypt_128( const unsigned char in[N_BLOCK], + unsigned char out[N_BLOCK], + const unsigned char key[N_BLOCK], + uint_8t o_key[N_BLOCK] ); +#endif + +#if defined( AES_DEC_128_OTFK ) +void bluedroid_aes_decrypt_128( const unsigned char in[N_BLOCK], + unsigned char out[N_BLOCK], + const unsigned char key[N_BLOCK], + unsigned char o_key[N_BLOCK] ); +#endif + +#if defined( AES_ENC_256_OTFK ) +void bluedroid_aes_encrypt_256( const unsigned char in[N_BLOCK], + unsigned char out[N_BLOCK], + const unsigned char key[2 * N_BLOCK], + unsigned char o_key[2 * N_BLOCK] ); +#endif + +#if defined( AES_DEC_256_OTFK ) +void bluedroid_aes_decrypt_256( const unsigned char in[N_BLOCK], + unsigned char out[N_BLOCK], + const unsigned char key[2 * N_BLOCK], + unsigned char o_key[2 * N_BLOCK] ); +#endif + +#endif diff --git a/components/bt/bluedroid/stack/include/avct_api.h b/components/bt/bluedroid/stack/include/avct_api.h new file mode 100755 index 0000000000..c2713fdb47 --- /dev/null +++ b/components/bt/bluedroid/stack/include/avct_api.h @@ -0,0 +1,279 @@ +/****************************************************************************** + * + * Copyright (C) 2003-2012 Broadcom Corporation + * + * 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 interface file contains the interface to the Audio Video Control + * Transport Protocol (AVCTP). + * + ******************************************************************************/ +#ifndef AVCT_API_H +#define AVCT_API_H + +#include "bt_types.h" +#include "bt_target.h" + +/***************************************************************************** +** Constants +*****************************************************************************/ + +/* API function return value result codes. */ +#define AVCT_SUCCESS 0 /* Function successful */ +#define AVCT_NO_RESOURCES 1 /* Not enough resources */ +#define AVCT_BAD_HANDLE 2 /* Bad handle */ +#define AVCT_PID_IN_USE 3 /* PID already in use */ +#define AVCT_NOT_OPEN 4 /* Connection not open */ + +/* PSM for AVCT. */ +#define AVCT_PSM 0x0017 +#define AVCT_BR_PSM 0x001B + +/* Protocol revision numbers */ +#define AVCT_REV_1_0 0x0100 +#define AVCT_REV_1_2 0x0102 +#define AVCT_REV_1_3 0x0103 +#define AVCT_REV_1_4 0x0104 + +/* the layer_specific settings */ +#define AVCT_DATA_CTRL 0x0001 /* for the control channel */ +#define AVCT_DATA_BROWSE 0x0002 /* for the browsing channel */ +#define AVCT_DATA_PARTIAL 0x0100 /* Only have room for a partial message */ + +#define AVCT_MIN_CONTROL_MTU 48 /* Per the AVRC spec, minimum MTU for the control channel */ +#define AVCT_MIN_BROWSE_MTU 335 /* Per the AVRC spec, minimum MTU for the browsing channel */ + +/* Message offset. The number of bytes needed by the protocol stack for the +** protocol headers of an AVCTP message packet. +*/ +#define AVCT_MSG_OFFSET 15 +#define AVCT_BROWSE_OFFSET 17 /* the default offset for browsing channel */ + +/* Connection role. */ +#define AVCT_INT 0 /* Initiator connection */ +#define AVCT_ACP 1 /* Acceptor connection */ + +/* Control role. */ +#define AVCT_TARGET 1 /* target */ +#define AVCT_CONTROL 2 /* controller */ +#define AVCT_PASSIVE 4 /* If conflict, allow the other side to succeed */ + +/* Command/Response indicator. */ +#define AVCT_CMD 0 /* Command message */ +#define AVCT_RSP 2 /* Response message */ +#define AVCT_REJ 3 /* Message rejected */ + +/* Control callback events. */ +#define AVCT_CONNECT_CFM_EVT 0 /* Connection confirm */ +#define AVCT_CONNECT_IND_EVT 1 /* Connection indication */ +#define AVCT_DISCONNECT_CFM_EVT 2 /* Disconnect confirm */ +#define AVCT_DISCONNECT_IND_EVT 3 /* Disconnect indication */ +#define AVCT_CONG_IND_EVT 4 /* Congestion indication */ +#define AVCT_UNCONG_IND_EVT 5 /* Uncongestion indication */ +#define AVCT_BROWSE_CONN_CFM_EVT 6 /* Browse Connection confirm */ +#define AVCT_BROWSE_CONN_IND_EVT 7 /* Browse Connection indication */ +#define AVCT_BROWSE_DISCONN_CFM_EVT 8 /* Browse Disconnect confirm */ +#define AVCT_BROWSE_DISCONN_IND_EVT 9 /* Browse Disconnect indication */ +#define AVCT_BROWSE_CONG_IND_EVT 10 /* Congestion indication */ +#define AVCT_BROWSE_UNCONG_IND_EVT 11 /* Uncongestion indication */ + + +/* General purpose failure result code for callback events. */ +#define AVCT_RESULT_FAIL 5 + +/***************************************************************************** +** Type Definitions +*****************************************************************************/ + +/* Control callback function. */ +typedef void (tAVCT_CTRL_CBACK)(UINT8 handle, UINT8 event, UINT16 result, + BD_ADDR peer_addr); + +/* Message callback function */ +/* p_pkt->layer_specific is AVCT_DATA_CTRL or AVCT_DATA_BROWSE */ +typedef void (tAVCT_MSG_CBACK)(UINT8 handle, UINT8 label, UINT8 cr, + BT_HDR *p_pkt); + +/* Structure used by AVCT_CreateConn. */ +typedef struct { + tAVCT_CTRL_CBACK *p_ctrl_cback; /* Control callback */ + tAVCT_MSG_CBACK *p_msg_cback; /* Message callback */ + UINT16 pid; /* Profile ID */ + UINT8 role; /* Initiator/acceptor role */ + UINT8 control; /* Control role (Control/Target) */ +} tAVCT_CC; + +/***************************************************************************** +** External Function Declarations +*****************************************************************************/ +#ifdef __cplusplus +extern "C" +{ +#endif + +/******************************************************************************* +** +** Function AVCT_Register +** +** Description This is the system level registration function for the +** AVCTP protocol. This function initializes AVCTP and +** prepares the protocol stack for its use. This function +** must be called once by the system or platform using AVCTP +** before the other functions of the API an be used. +** +** +** Returns void +** +*******************************************************************************/ +extern void AVCT_Register(UINT16 mtu, UINT16 mtu_br, UINT8 sec_mask); + +/******************************************************************************* +** +** Function AVCT_Deregister +** +** Description This function is called to deregister use AVCTP protocol. +** It is called when AVCTP is no longer being used by any +** application in the system. Before this function can be +** called, all connections must be removed with +** AVCT_RemoveConn(). +** +** +** Returns void +** +*******************************************************************************/ +extern void AVCT_Deregister(void); + +/******************************************************************************* +** +** Function AVCT_CreateConn +** +** Description Create an AVCTP connection. There are two types of +** connections, initiator and acceptor, as determined by +** the p_cc->role parameter. When this function is called to +** create an initiator connection, an AVCTP connection to +** the peer device is initiated if one does not already exist. +** If an acceptor connection is created, the connection waits +** passively for an incoming AVCTP connection from a peer device. +** +** +** Returns AVCT_SUCCESS if successful, otherwise error. +** +*******************************************************************************/ +extern UINT16 AVCT_CreateConn(UINT8 *p_handle, tAVCT_CC *p_cc, + BD_ADDR peer_addr); + +/******************************************************************************* +** +** Function AVCT_RemoveConn +** +** Description Remove an AVCTP connection. This function is called when +** the application is no longer using a connection. If this +** is the last connection to a peer the L2CAP channel for AVCTP +** will be closed. +** +** +** Returns AVCT_SUCCESS if successful, otherwise error. +** +*******************************************************************************/ +extern UINT16 AVCT_RemoveConn(UINT8 handle); + +/******************************************************************************* +** +** Function AVCT_CreateBrowse +** +** Description Create an AVCTP connection. There are two types of +** connections, initiator and acceptor, as determined by +** the p_cc->role parameter. When this function is called to +** create an initiator connection, an AVCTP connection to +** the peer device is initiated if one does not already exist. +** If an acceptor connection is created, the connection waits +** passively for an incoming AVCTP connection from a peer device. +** +** +** Returns AVCT_SUCCESS if successful, otherwise error. +** +*******************************************************************************/ +extern UINT16 AVCT_CreateBrowse(UINT8 handle, UINT8 role); + +/******************************************************************************* +** +** Function AVCT_RemoveBrowse +** +** Description Remove an AVCTP connection. This function is called when +** the application is no longer using a connection. If this +** is the last connection to a peer the L2CAP channel for AVCTP +** will be closed. +** +** +** Returns AVCT_SUCCESS if successful, otherwise error. +** +*******************************************************************************/ +extern UINT16 AVCT_RemoveBrowse(UINT8 handle); + +/******************************************************************************* +** +** Function AVCT_GetBrowseMtu +** +** Description Get the peer_mtu for the AVCTP Browse channel of the given +** connection. +** +** Returns the peer browsing channel MTU. +** +*******************************************************************************/ +extern UINT16 AVCT_GetBrowseMtu (UINT8 handle); + +/******************************************************************************* +** +** Function AVCT_GetPeerMtu +** +** Description Get the peer_mtu for the AVCTP channel of the given +** connection. +** +** Returns the peer MTU size. +** +*******************************************************************************/ +extern UINT16 AVCT_GetPeerMtu (UINT8 handle); + +/******************************************************************************* +** +** Function AVCT_MsgReq +** +** Description Send an AVCTP message to a peer device. In calling +** AVCT_MsgReq(), the application should keep track of the +** congestion state of AVCTP as communicated with events +** AVCT_CONG_IND_EVT and AVCT_UNCONG_IND_EVT. If the +** application calls AVCT_MsgReq() when AVCTP is congested +** the message may be discarded. The application may make its +** first call to AVCT_MsgReq() after it receives an +** AVCT_CONNECT_CFM_EVT or AVCT_CONNECT_IND_EVT on control channel or +** AVCT_BROWSE_CONN_CFM_EVT or AVCT_BROWSE_CONN_IND_EVT on browsing channel. +** +** p_msg->layer_specific must be set to +** AVCT_DATA_CTRL for control channel traffic; +** AVCT_DATA_BROWSE for for browse channel traffic. +** +** Returns AVCT_SUCCESS if successful, otherwise error. +** +*******************************************************************************/ +extern UINT16 AVCT_MsgReq(UINT8 handle, UINT8 label, UINT8 cr, BT_HDR *p_msg); + +#ifdef __cplusplus +} +#endif + + +#endif /* AVCT_API_H */ diff --git a/components/bt/bluedroid/stack/include/avdt_api.h b/components/bt/bluedroid/stack/include/avdt_api.h new file mode 100755 index 0000000000..41f8a12ded --- /dev/null +++ b/components/bt/bluedroid/stack/include/avdt_api.h @@ -0,0 +1,988 @@ +/****************************************************************************** + * + * Copyright (C) 2002-2012 Broadcom Corporation + * + * 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 interface file contains the interface to the Audio Video + * Distribution Transport Protocol (AVDTP). + * + ******************************************************************************/ +#ifndef AVDT_API_H +#define AVDT_API_H + +#include "bt_types.h" +#include "bt_target.h" + +/***************************************************************************** +** Constants +*****************************************************************************/ +#ifndef AVDT_VERSION +#define AVDT_VERSION 0x0102 +#endif +#define AVDT_VERSION_SYNC 0x0103 + +/* API function return value result codes. */ +#define AVDT_SUCCESS 0 /* Function successful */ +#define AVDT_BAD_PARAMS 1 /* Invalid parameters */ +#define AVDT_NO_RESOURCES 2 /* Not enough resources */ +#define AVDT_BAD_HANDLE 3 /* Bad handle */ +#define AVDT_BUSY 4 /* A procedure is already in progress */ +#define AVDT_WRITE_FAIL 5 /* Write failed */ + +/* The index to access the codec type in codec_info[]. */ +#define AVDT_CODEC_TYPE_INDEX 2 + +/* The size in bytes of a Adaptation Layer header. */ +#define AVDT_AL_HDR_SIZE 3 + +/* The size in bytes of a media packet header. */ +#define AVDT_MEDIA_HDR_SIZE 12 + +/* AVDTP 7.5.3 Adaptation Layer Fragmentation + * original length of the un-fragmented transport packet should be specified by + * two bytes length field of Adaptation Layer Header */ +#define AVDT_MAX_MEDIA_SIZE (0xFFFF - AVDT_MEDIA_HDR_SIZE) + +/* The handle is used when reporting MULTI_AV specific events */ +#define AVDT_MULTI_AV_HANDLE 0xFF + +/* The number of bytes needed by the protocol stack for the protocol headers +** of a media packet. This is the size of the media packet header, the +** L2CAP packet header and HCI header. +*/ +#define AVDT_MEDIA_OFFSET 23 + +/* The marker bit is used by the application to mark significant events such +** as frame boundaries in the data stream. This constant is used to check or +** set the marker bit in the m_pt parameter of an AVDT_WriteReq() +** or AVDT_DATA_IND_EVT. +*/ +#define AVDT_MARKER_SET 0x80 + +/* SEP Type. This indicates the stream endpoint type. */ +#define AVDT_TSEP_SRC 0 /* Source SEP */ +#define AVDT_TSEP_SNK 1 /* Sink SEP */ + +/* initiator/acceptor role for adaption */ +#define AVDT_INT 0 /* initiator */ +#define AVDT_ACP 1 /* acceptor */ + +/* Media Type. This indicates the media type of the stream endpoint. */ +#define AVDT_MEDIA_AUDIO 0 /* Audio SEP */ +#define AVDT_MEDIA_VIDEO 1 /* Video SEP */ +#define AVDT_MEDIA_MULTI 2 /* Multimedia SEP */ + +/* for reporting packets */ +#define AVDT_RTCP_PT_SR 200 /* the packet type - SR (Sender Report) */ +#define AVDT_RTCP_PT_RR 201 /* the packet type - RR (Receiver Report) */ +#define AVDT_RTCP_PT_SDES 202 /* the packet type - SDES (Source Description) */ +typedef UINT8 AVDT_REPORT_TYPE; + +#define AVDT_RTCP_SDES_CNAME 1 /* SDES item CNAME */ +#ifndef AVDT_MAX_CNAME_SIZE +#define AVDT_MAX_CNAME_SIZE 28 +#endif + +/* Protocol service capabilities. This indicates the protocol service +** capabilities of a stream endpoint. This value is a mask. +** Multiple values can be combined with a bitwise OR. +*/ +#define AVDT_PSC_TRANS (1<<1) /* Media transport */ +#define AVDT_PSC_REPORT (1<<2) /* Reporting */ +#define AVDT_PSC_RECOV (1<<3) /* Recovery */ +#define AVDT_PSC_HDRCMP (1<<5) /* Header compression */ +#define AVDT_PSC_MUX (1<<6) /* Multiplexing */ +#define AVDT_PSC_DELAY_RPT (1<<8) /* Delay Report */ + +/* Recovery type. This indicates the recovery type. */ +#define AVDT_RECOV_RFC2733 1 /* RFC2733 recovery */ + +/* Header compression capabilities. This indicates the header compression +** capabilities. This value is a mask. Multiple values can be combined +** with a bitwise OR. +*/ +#define AVDT_HDRCMP_MEDIA (1<<5) /* Available for media packets */ +#define AVDT_HDRCMP_RECOV (1<<6) /* Available for recovery packets */ +#define AVDT_HDRCMP_BACKCH (1<<7) /* Back channel supported */ + +/* Multiplexing capabilities mask. */ +#define AVDT_MUX_FRAG (1<<7) /* Allow Adaptation Layer Fragmentation */ + +/* Application service category. This indicates the application +** service category. +*/ +#define AVDT_ASC_PROTECT 4 /* Content protection */ +#define AVDT_ASC_CODEC 7 /* Codec */ + +/* Error codes. The following are error codes defined in the AVDTP and GAVDP +** specifications. These error codes communicate protocol errors between +** AVDTP and the application. More detailed descriptions of the error codes +** and their appropriate use can be found in the AVDTP and GAVDP specifications. +** These error codes are unrelated to the result values returned by the +** AVDTP API functions. +*/ +#define AVDT_ERR_HEADER 0x01 /* Bad packet header format */ +#define AVDT_ERR_LENGTH 0x11 /* Bad packet length */ +#define AVDT_ERR_SEID 0x12 /* Invalid SEID */ +#define AVDT_ERR_IN_USE 0x13 /* The SEP is in use */ +#define AVDT_ERR_NOT_IN_USE 0x14 /* The SEP is not in use */ +#define AVDT_ERR_CATEGORY 0x17 /* Bad service category */ +#define AVDT_ERR_PAYLOAD 0x18 /* Bad payload format */ +#define AVDT_ERR_NSC 0x19 /* Requested command not supported */ +#define AVDT_ERR_INVALID_CAP 0x1A /* Reconfigure attempted invalid capabilities */ +#define AVDT_ERR_RECOV_TYPE 0x22 /* Requested recovery type not defined */ +#define AVDT_ERR_MEDIA_TRANS 0x23 /* Media transport capability not correct */ +#define AVDT_ERR_RECOV_FMT 0x25 /* Recovery service capability not correct */ +#define AVDT_ERR_ROHC_FMT 0x26 /* Header compression service capability not correct */ +#define AVDT_ERR_CP_FMT 0x27 /* Content protection service capability not correct */ +#define AVDT_ERR_MUX_FMT 0x28 /* Multiplexing service capability not correct */ +#define AVDT_ERR_UNSUP_CFG 0x29 /* Configuration not supported */ +#define AVDT_ERR_BAD_STATE 0x31 /* Message cannot be processed in this state */ +#define AVDT_ERR_REPORT_FMT 0x65 /* Report service capability not correct */ +#define AVDT_ERR_SERVICE 0x80 /* Invalid service category */ +#define AVDT_ERR_RESOURCE 0x81 /* Insufficient resources */ +#define AVDT_ERR_INVALID_MCT 0xC1 /* Invalid Media Codec Type */ +#define AVDT_ERR_UNSUP_MCT 0xC2 /* Unsupported Media Codec Type */ +#define AVDT_ERR_INVALID_LEVEL 0xC3 /* Invalid Level */ +#define AVDT_ERR_UNSUP_LEVEL 0xC4 /* Unsupported Level */ +#define AVDT_ERR_INVALID_CP 0xE0 /* Invalid Content Protection Type */ +#define AVDT_ERR_INVALID_FORMAT 0xE1 /* Invalid Content Protection format */ + +/* Additional error codes. This indicates error codes used by AVDTP +** in addition to the ones defined in the specifications. +*/ +#define AVDT_ERR_CONNECT 0x07 /* Connection failed. */ +#define AVDT_ERR_TIMEOUT 0x08 /* Response timeout. */ + +/* Control callback events. */ +#define AVDT_DISCOVER_CFM_EVT 0 /* Discover confirm */ +#define AVDT_GETCAP_CFM_EVT 1 /* Get capabilities confirm */ +#define AVDT_OPEN_CFM_EVT 2 /* Open confirm */ +#define AVDT_OPEN_IND_EVT 3 /* Open indication */ +#define AVDT_CONFIG_IND_EVT 4 /* Configuration indication */ +#define AVDT_START_CFM_EVT 5 /* Start confirm */ +#define AVDT_START_IND_EVT 6 /* Start indication */ +#define AVDT_SUSPEND_CFM_EVT 7 /* Suspend confirm */ +#define AVDT_SUSPEND_IND_EVT 8 /* Suspend indication */ +#define AVDT_CLOSE_CFM_EVT 9 /* Close confirm */ +#define AVDT_CLOSE_IND_EVT 10 /* Close indication */ +#define AVDT_RECONFIG_CFM_EVT 11 /* Reconfiguration confirm */ +#define AVDT_RECONFIG_IND_EVT 12 /* Reconfiguration indication */ +#define AVDT_SECURITY_CFM_EVT 13 /* Security confirm */ +#define AVDT_SECURITY_IND_EVT 14 /* Security indication */ +#define AVDT_WRITE_CFM_EVT 15 /* Write confirm */ +#define AVDT_CONNECT_IND_EVT 16 /* Signaling channel connected */ +#define AVDT_DISCONNECT_IND_EVT 17 /* Signaling channel disconnected */ +#define AVDT_REPORT_CONN_EVT 18 /* Reporting channel connected */ +#define AVDT_REPORT_DISCONN_EVT 19 /* Reporting channel disconnected */ +#define AVDT_DELAY_REPORT_EVT 20 /* Delay report received */ +#define AVDT_DELAY_REPORT_CFM_EVT 21 /* Delay report response received */ + +#define AVDT_MAX_EVT (AVDT_DELAY_REPORT_CFM_EVT) + +/* PSM for AVDT */ +#define AVDT_PSM 0x0019 + +/* Nonsupported protocol command messages. This value is used in tAVDT_CS */ +#define AVDT_NSC_SUSPEND 0x01 /* Suspend command not supported */ +#define AVDT_NSC_RECONFIG 0x02 /* Reconfigure command not supported */ +#define AVDT_NSC_SECURITY 0x04 /* Security command not supported */ + +/***************************************************************************** +** Type Definitions +*****************************************************************************/ + +typedef struct +{ + UINT32 ntp_sec; /* NTP time: seconds relative to 0h UTC on 1 January 1900 */ + UINT32 ntp_frac; /* NTP time: the fractional part */ + UINT32 rtp_time; /* timestamp in RTP header */ + UINT32 pkt_count; /* sender's packet count: since starting transmission + * up until the time this SR packet was generated. */ + UINT32 octet_count; /* sender's octet count: same comment */ +} tAVDT_SENDER_INFO; + +typedef struct +{ + UINT8 frag_lost; /* fraction lost since last RR */ + UINT32 packet_lost; /* cumulative number of packets lost since the beginning */ + UINT32 seq_num_rcvd; /* extended highest sequence number received */ + UINT32 jitter; /* interarrival jitter */ + UINT32 lsr; /* last SR timestamp */ + UINT32 dlsr; /* delay since last SR */ +} tAVDT_REPORT_BLK; + +typedef union +{ + tAVDT_SENDER_INFO sr; + tAVDT_REPORT_BLK rr; + UINT8 cname[AVDT_MAX_CNAME_SIZE + 1]; +} tAVDT_REPORT_DATA; + +/* This structure contains parameters which are set at registration. */ +typedef struct { + UINT16 ctrl_mtu; /* L2CAP MTU of the AVDTP signaling channel */ + UINT8 ret_tout; /* AVDTP signaling retransmission timeout */ + UINT8 sig_tout; /* AVDTP signaling message timeout */ + UINT8 idle_tout; /* AVDTP idle signaling channel timeout */ + UINT8 sec_mask; /* Security mask for BTM_SetSecurityLevel() */ +} tAVDT_REG; + +/* This structure contains the SEP information. This information is +** transferred during the discovery procedure. +*/ +typedef struct { + BOOLEAN in_use; /* TRUE if stream is currently in use */ + UINT8 seid; /* Stream endpoint identifier */ + UINT8 media_type; /* Media type */ + UINT8 tsep; /* SEP type */ +} tAVDT_SEP_INFO; + +/* This structure contains the SEP configuration. */ +typedef struct { + UINT8 codec_info[AVDT_CODEC_SIZE]; /* Codec capabilities array */ + UINT8 protect_info[AVDT_PROTECT_SIZE]; /* Content protection capabilities */ + UINT8 num_codec; /* Number of media codec information elements */ + UINT8 num_protect; /* Number of content protection information elements */ + UINT16 psc_mask; /* Protocol service capabilities mask */ + UINT8 recov_type; /* Recovery type */ + UINT8 recov_mrws; /* Maximum recovery window size */ + UINT8 recov_mnmp; /* Recovery maximum number of media packets */ + UINT8 hdrcmp_mask; /* Header compression capabilities */ +#if AVDT_MULTIPLEXING == TRUE + UINT8 mux_mask; /* Multiplexing capabilities. AVDT_MUX_XXX bits can be combined with a bitwise OR */ + UINT8 mux_tsid_media; /* TSID for media transport session */ + UINT8 mux_tcid_media; /* TCID for media transport session */ + UINT8 mux_tsid_report; /* TSID for reporting transport session */ + UINT8 mux_tcid_report; /* TCID for reporting transport session */ + UINT8 mux_tsid_recov; /* TSID for recovery transport session */ + UINT8 mux_tcid_recov; /* TCID for recovery transport session */ +#endif +} tAVDT_CFG; + +/* Header structure for callback event parameters. */ +typedef struct { + UINT8 err_code; /* Zero if operation succeeded; nonzero if operation failed */ + UINT8 err_param; /* Error parameter included for some events */ + UINT8 label; /* Transaction label */ + UINT8 seid; /* For internal use only */ + UINT8 sig_id; /* For internal use only */ + UINT8 ccb_idx; /* For internal use only */ +} tAVDT_EVT_HDR; + +/* This data structure is associated with the AVDT_GETCAP_CFM_EVT, +** AVDT_RECONFIG_IND_EVT, and AVDT_RECONFIG_CFM_EVT. +*/ +typedef struct { + tAVDT_EVT_HDR hdr; /* Event header */ + tAVDT_CFG *p_cfg; /* Pointer to configuration for this SEP */ +} tAVDT_CONFIG; + +/* This data structure is associated with the AVDT_CONFIG_IND_EVT. */ +typedef struct { + tAVDT_EVT_HDR hdr; /* Event header */ + tAVDT_CFG *p_cfg; /* Pointer to configuration for this SEP */ + UINT8 int_seid; /* Stream endpoint ID of stream initiating the operation */ +} tAVDT_SETCONFIG; + +/* This data structure is associated with the AVDT_OPEN_IND_EVT and AVDT_OPEN_CFM_EVT. */ +typedef struct { + tAVDT_EVT_HDR hdr; /* Event header */ + UINT16 peer_mtu; /* Transport channel L2CAP MTU of the peer */ + UINT16 lcid; /* L2CAP LCID for media channel */ +} tAVDT_OPEN; + +/* This data structure is associated with the AVDT_SECURITY_IND_EVT +** and AVDT_SECURITY_CFM_EVT. +*/ +typedef struct { + tAVDT_EVT_HDR hdr; /* Event header */ + UINT8 *p_data; /* Pointer to security data */ + UINT16 len; /* Length in bytes of the security data */ +} tAVDT_SECURITY; + +/* This data structure is associated with the AVDT_DISCOVER_CFM_EVT. */ +typedef struct { + tAVDT_EVT_HDR hdr; /* Event header */ + tAVDT_SEP_INFO *p_sep_info; /* Pointer to SEP information */ + UINT8 num_seps; /* Number of stream endpoints */ +} tAVDT_DISCOVER; + +/* This data structure is associated with the AVDT_DELAY_REPORT_EVT. */ +typedef struct { + tAVDT_EVT_HDR hdr; /* Event header */ + UINT16 delay; /* Delay value */ +} tAVDT_DELAY_RPT; + +/* Union of all control callback event data structures */ +typedef union { + tAVDT_EVT_HDR hdr; + tAVDT_DISCOVER discover_cfm; + tAVDT_CONFIG getcap_cfm; + tAVDT_OPEN open_cfm; + tAVDT_OPEN open_ind; + tAVDT_SETCONFIG config_ind; + tAVDT_EVT_HDR start_cfm; + tAVDT_EVT_HDR suspend_cfm; + tAVDT_EVT_HDR close_cfm; + tAVDT_CONFIG reconfig_cfm; + tAVDT_CONFIG reconfig_ind; + tAVDT_SECURITY security_cfm; + tAVDT_SECURITY security_ind; + tAVDT_EVT_HDR connect_ind; + tAVDT_EVT_HDR disconnect_ind; + tAVDT_EVT_HDR report_conn; + tAVDT_DELAY_RPT delay_rpt_cmd; +} tAVDT_CTRL; + +/* This is the control callback function. This function passes control events +** to the application. This function is required for all registered stream +** endpoints and for the AVDT_DiscoverReq() and AVDT_GetCapReq() functions. +** +*/ +typedef void (tAVDT_CTRL_CBACK)(UINT8 handle, BD_ADDR bd_addr, UINT8 event, + tAVDT_CTRL *p_data); + +/* This is the data callback function. It is executed when AVDTP has a media +** packet ready for the application. This function is required for SNK +** endpoints and not applicable for SRC endpoints. +*/ +typedef void (tAVDT_DATA_CBACK)(UINT8 handle, BT_HDR *p_pkt, UINT32 time_stamp, + UINT8 m_pt); + +#if AVDT_MULTIPLEXING == TRUE +/* This is the second version of the data callback function. This version uses +** application buffer assigned by AVDT_SetMediaBuf. Caller can assign different +** buffer during callback or can leave the current buffer for further using. +** This callback is called when AVDTP has a media packet ready for the application. +** This function is required for SNK endpoints and not applicable for SRC endpoints. +*/ +typedef void (tAVDT_MEDIA_CBACK)(UINT8 handle, UINT8 *p_payload, UINT32 payload_len, + UINT32 time_stamp, UINT16 seq_num, UINT8 m_pt, UINT8 marker); +#endif + +#if AVDT_REPORTING == TRUE +/* This is the report callback function. It is executed when AVDTP has a reporting +** packet ready for the application. This function is required for streams +** created with AVDT_PSC_REPORT. +*/ +typedef void (tAVDT_REPORT_CBACK)(UINT8 handle, AVDT_REPORT_TYPE type, + tAVDT_REPORT_DATA *p_data); +#endif + +typedef UINT16 (tAVDT_GETCAP_REQ) (BD_ADDR bd_addr, UINT8 seid, tAVDT_CFG *p_cfg, tAVDT_CTRL_CBACK *p_cback); + +/* This structure contains information required when a stream is created. +** It is passed to the AVDT_CreateStream() function. +*/ +typedef struct { + tAVDT_CFG cfg; /* SEP configuration */ + tAVDT_CTRL_CBACK *p_ctrl_cback; /* Control callback function */ + tAVDT_DATA_CBACK *p_data_cback; /* Data callback function */ +#if AVDT_MULTIPLEXING == TRUE + tAVDT_MEDIA_CBACK *p_media_cback; /* Media callback function. It will be called only if p_data_cback is NULL */ +#endif +#if AVDT_REPORTING == TRUE + tAVDT_REPORT_CBACK *p_report_cback;/* Report callback function. */ +#endif + UINT16 mtu; /* The L2CAP MTU of the transport channel */ + UINT16 flush_to; /* The L2CAP flush timeout of the transport channel */ + UINT8 tsep; /* SEP type */ + UINT8 media_type; /* Media type */ + UINT16 nsc_mask; /* Nonsupported protocol command messages */ +} tAVDT_CS; + +/* AVDT data option mask is used in the write request */ +#define AVDT_DATA_OPT_NONE 0x00 /* No option still add RTP header */ +#define AVDT_DATA_OPT_NO_RTP (0x01 << 0) /* Skip adding RTP header */ + +typedef UINT8 tAVDT_DATA_OPT_MASK; + + + +/***************************************************************************** +** External Function Declarations +*****************************************************************************/ +#ifdef __cplusplus +extern "C" +{ +#endif + +/******************************************************************************* +** +** Function AVDT_Register +** +** Description This is the system level registration function for the +** AVDTP protocol. This function initializes AVDTP and +** prepares the protocol stack for its use. This function +** must be called once by the system or platform using AVDTP +** before the other functions of the API an be used. +** +** +** Returns void +** +*******************************************************************************/ +extern void AVDT_Register(tAVDT_REG *p_reg, tAVDT_CTRL_CBACK *p_cback); + +/******************************************************************************* +** +** Function AVDT_Deregister +** +** Description This function is called to deregister use AVDTP protocol. +** It is called when AVDTP is no longer being used by any +** application in the system. Before this function can be +** called, all streams must be removed with AVDT_RemoveStream(). +** +** +** Returns void +** +*******************************************************************************/ +extern void AVDT_Deregister(void); + + +/******************************************************************************* +** +** Function AVDT_SINK_Activate +** +** Description Activate SEP of A2DP Sink. In Use parameter is adjusted. +** In Use will be made false in case of activation. A2DP SRC +** will receive in_use as false and can open A2DP Sink +** connection +** +** Returns void +** +*******************************************************************************/ +extern void AVDT_SINK_Activate(void); + +/******************************************************************************* +** +** Function AVDT_SINK_Deactivate +** +** Description Deactivate SEP of A2DP Sink. In Use parameter is adjusted. +** In Use will be made TRUE in case of activation. A2DP SRC +** will receive in_use as true and will not open A2DP Sink +** connection +** +** Returns void. +** +*******************************************************************************/ +extern void AVDT_SINK_Deactivate(void); + +/******************************************************************************* +** +** Function AVDT_AbortReq +** +** Description Trigger Abort request to pass AVDTP Abort related mandatory +** PTS Test case. +** +** Returns void. +** +*******************************************************************************/ +extern void AVDT_AbortReq(UINT8 handle); + +/******************************************************************************* +** +** Function AVDT_CreateStream +** +** Description Create a stream endpoint. After a stream endpoint is +** created an application can initiate a connection between +** this endpoint and an endpoint on a peer device. In +** addition, a peer device can discover, get the capabilities, +** and connect to this endpoint. +** +** +** Returns AVDT_SUCCESS if successful, otherwise error. +** +*******************************************************************************/ +extern UINT16 AVDT_CreateStream(UINT8 *p_handle, tAVDT_CS *p_cs); + +/******************************************************************************* +** +** Function AVDT_RemoveStream +** +** Description Remove a stream endpoint. This function is called when +** the application is no longer using a stream endpoint. +** If this function is called when the endpoint is connected +** the connection is closed and then the stream endpoint +** is removed. +** +** +** Returns AVDT_SUCCESS if successful, otherwise error. +** +*******************************************************************************/ +extern UINT16 AVDT_RemoveStream(UINT8 handle); + +/******************************************************************************* +** +** Function AVDT_DiscoverReq +** +** Description This function initiates a connection to the AVDTP service +** on the peer device, if not already present, and discovers +** the stream endpoints on the peer device. (Please note +** that AVDTP discovery is unrelated to SDP discovery). +** This function can be called at any time regardless of whether +** there is an AVDTP connection to the peer device. +** +** When discovery is complete, an AVDT_DISCOVER_CFM_EVT +** is sent to the application via its callback function. +** The application must not call AVDT_GetCapReq() or +** AVDT_DiscoverReq() again to the same device until +** discovery is complete. +** +** The memory addressed by sep_info is allocated by the +** application. This memory is written to by AVDTP as part +** of the discovery procedure. This memory must remain +** accessible until the application receives the +** AVDT_DISCOVER_CFM_EVT. +** +** Returns AVDT_SUCCESS if successful, otherwise error. +** +*******************************************************************************/ +extern UINT16 AVDT_DiscoverReq(BD_ADDR bd_addr, tAVDT_SEP_INFO *p_sep_info, + UINT8 max_seps, tAVDT_CTRL_CBACK *p_cback); + + +/******************************************************************************* +** +** Function AVDT_GetCapReq +** +** Description This function initiates a connection to the AVDTP service +** on the peer device, if not already present, and gets the +** capabilities of a stream endpoint on the peer device. +** This function can be called at any time regardless of +** whether there is an AVDTP connection to the peer device. +** +** When the procedure is complete, an AVDT_GETCAP_CFM_EVT is +** sent to the application via its callback function. The +** application must not call AVDT_GetCapReq() or +** AVDT_DiscoverReq() again until the procedure is complete. +** +** The memory pointed to by p_cfg is allocated by the +** application. This memory is written to by AVDTP as part +** of the get capabilities procedure. This memory must +** remain accessible until the application receives +** the AVDT_GETCAP_CFM_EVT. +** +** Returns AVDT_SUCCESS if successful, otherwise error. +** +*******************************************************************************/ +extern UINT16 AVDT_GetCapReq(BD_ADDR bd_addr, UINT8 seid, tAVDT_CFG *p_cfg, + tAVDT_CTRL_CBACK *p_cback); + +/******************************************************************************* +** +** Function AVDT_GetAllCapReq +** +** Description This function initiates a connection to the AVDTP service +** on the peer device, if not already present, and gets the +** capabilities of a stream endpoint on the peer device. +** This function can be called at any time regardless of +** whether there is an AVDTP connection to the peer device. +** +** When the procedure is complete, an AVDT_GETCAP_CFM_EVT is +** sent to the application via its callback function. The +** application must not call AVDT_GetCapReq() or +** AVDT_DiscoverReq() again until the procedure is complete. +** +** The memory pointed to by p_cfg is allocated by the +** application. This memory is written to by AVDTP as part +** of the get capabilities procedure. This memory must +** remain accessible until the application receives +** the AVDT_GETCAP_CFM_EVT. +** +** Returns AVDT_SUCCESS if successful, otherwise error. +** +*******************************************************************************/ +extern UINT16 AVDT_GetAllCapReq(BD_ADDR bd_addr, UINT8 seid, tAVDT_CFG *p_cfg, + tAVDT_CTRL_CBACK *p_cback); + +/******************************************************************************* +** +** Function AVDT_DelayReport +** +** Description This functions sends a Delay Report to the peer device +** that is associated with a particular SEID. +** This function is called by SNK device. +** +** Returns AVDT_SUCCESS if successful, otherwise error. +** +*******************************************************************************/ +extern UINT16 AVDT_DelayReport(UINT8 handle, UINT8 seid, UINT16 delay); + +/******************************************************************************* +** +** Function AVDT_OpenReq +** +** Description This function initiates a connection to the AVDTP service +** on the peer device, if not already present, and connects +** to a stream endpoint on a peer device. When the connection +** is completed, an AVDT_OPEN_CFM_EVT is sent to the +** application via the control callback function for this handle. +** +** Returns AVDT_SUCCESS if successful, otherwise error. +** +*******************************************************************************/ +extern UINT16 AVDT_OpenReq(UINT8 handle, BD_ADDR bd_addr, UINT8 seid, + tAVDT_CFG *p_cfg); + + +/******************************************************************************* +** +** Function AVDT_ConfigRsp +** +** Description Respond to a configure request from the peer device. This +** function must be called if the application receives an +** AVDT_CONFIG_IND_EVT through its control callback. +** +** +** Returns AVDT_SUCCESS if successful, otherwise error. +** +*******************************************************************************/ +extern UINT16 AVDT_ConfigRsp(UINT8 handle, UINT8 label, UINT8 error_code, + UINT8 category); + +/******************************************************************************* +** +** Function AVDT_StartReq +** +** Description Start one or more stream endpoints. This initiates the +** transfer of media packets for the streams. All stream +** endpoints must previously be opened. When the streams +** are started, an AVDT_START_CFM_EVT is sent to the +** application via the control callback function for each stream. +** +** +** Returns AVDT_SUCCESS if successful, otherwise error. +** +*******************************************************************************/ +extern UINT16 AVDT_StartReq(UINT8 *p_handles, UINT8 num_handles); + +/******************************************************************************* +** +** Function AVDT_SuspendReq +** +** Description Suspend one or more stream endpoints. This suspends the +** transfer of media packets for the streams. All stream +** endpoints must previously be open and started. When the +** streams are suspended, an AVDT_SUSPEND_CFM_EVT is sent to +** the application via the control callback function for +** each stream. +** +** +** Returns AVDT_SUCCESS if successful, otherwise error. +** +*******************************************************************************/ +extern UINT16 AVDT_SuspendReq(UINT8 *p_handles, UINT8 num_handles); + +/******************************************************************************* +** +** Function AVDT_CloseReq +** +** Description Close a stream endpoint. This stops the transfer of media +** packets and closes the transport channel associated with +** this stream endpoint. When the stream is closed, an +** AVDT_CLOSE_CFM_EVT is sent to the application via the +** control callback function for this handle. +** +** +** Returns AVDT_SUCCESS if successful, otherwise error. +** +*******************************************************************************/ +extern UINT16 AVDT_CloseReq(UINT8 handle); + +/******************************************************************************* +** +** Function AVDT_ReconfigReq +** +** Description Reconfigure a stream endpoint. This allows the application +** to change the codec or content protection capabilities of +** a stream endpoint after it has been opened. This function +** can only be called if the stream is opened but not started +** or if the stream has been suspended. When the procedure +** is completed, an AVDT_RECONFIG_CFM_EVT is sent to the +** application via the control callback function for this handle. +** +** +** Returns AVDT_SUCCESS if successful, otherwise error. +** +*******************************************************************************/ +extern UINT16 AVDT_ReconfigReq(UINT8 handle, tAVDT_CFG *p_cfg); + +/******************************************************************************* +** +** Function AVDT_ReconfigRsp +** +** Description Respond to a reconfigure request from the peer device. +** This function must be called if the application receives +** an AVDT_RECONFIG_IND_EVT through its control callback. +** +** +** Returns AVDT_SUCCESS if successful, otherwise error. +** +*******************************************************************************/ +extern UINT16 AVDT_ReconfigRsp(UINT8 handle, UINT8 label, UINT8 error_code, + UINT8 category); + +/******************************************************************************* +** +** Function AVDT_SecurityReq +** +** Description Send a security request to the peer device. When the +** security procedure is completed, an AVDT_SECURITY_CFM_EVT +** is sent to the application via the control callback function +** for this handle. (Please note that AVDTP security procedures +** are unrelated to Bluetooth link level security.) +** +** +** Returns AVDT_SUCCESS if successful, otherwise error. +** +*******************************************************************************/ +extern UINT16 AVDT_SecurityReq(UINT8 handle, UINT8 *p_data, UINT16 len); + +/******************************************************************************* +** +** Function AVDT_SecurityRsp +** +** Description Respond to a security request from the peer device. +** This function must be called if the application receives +** an AVDT_SECURITY_IND_EVT through its control callback. +** (Please note that AVDTP security procedures are unrelated +** to Bluetooth link level security.) +** +** +** Returns AVDT_SUCCESS if successful, otherwise error. +** +*******************************************************************************/ +extern UINT16 AVDT_SecurityRsp(UINT8 handle, UINT8 label, UINT8 error_code, + UINT8 *p_data, UINT16 len); + +/******************************************************************************* +** +** Function AVDT_WriteReq +** +** Description Send a media packet to the peer device. The stream must +** be started before this function is called. Also, this +** function can only be called if the stream is a SRC. +** +** When AVDTP has sent the media packet and is ready for the +** next packet, an AVDT_WRITE_CFM_EVT is sent to the +** application via the control callback. The application must +** wait for the AVDT_WRITE_CFM_EVT before it makes the next +** call to AVDT_WriteReq(). If the applications calls +** AVDT_WriteReq() before it receives the event the packet +** will not be sent. The application may make its first call +** to AVDT_WriteReq() after it receives an AVDT_START_CFM_EVT +** or AVDT_START_IND_EVT. +** +** The application passes the packet using the BT_HDR structure. +** This structure is described in section 2.1. The offset +** field must be equal to or greater than AVDT_MEDIA_OFFSET. +** This allows enough space in the buffer for the L2CAP and +** AVDTP headers. +** +** The memory pointed to by p_pkt must be a GKI buffer +** allocated by the application. This buffer will be freed +** by the protocol stack; the application must not free +** this buffer. +** +** +** Returns AVDT_SUCCESS if successful, otherwise error. +** +*******************************************************************************/ +extern UINT16 AVDT_WriteReq(UINT8 handle, BT_HDR *p_pkt, UINT32 time_stamp, + UINT8 m_pt); +/******************************************************************************* +** +** Function AVDT_WriteReqOpt +** +** Description Send a media packet to the peer device. The stream must +** be started before this function is called. Also, this +** function can only be called if the stream is a SRC +** +** When AVDTP has sent the media packet and is ready for the +** next packet, an AVDT_WRITE_CFM_EVT is sent to the +** application via the control callback. The application must +** wait for the AVDT_WRITE_CFM_EVT before it makes the next +** call to AVDT_WriteReq(). If the applications calls +** AVDT_WriteReq() before it receives the event the packet +** will not be sent. The application may make its first call +** to AVDT_WriteReq() after it receives an AVDT_START_CFM_EVT +** or AVDT_START_IND_EVT. +** +** The application passes the packet using the BT_HDR structure +** This structure is described in section 2.1. The offset +** field must be equal to or greater than AVDT_MEDIA_OFFSET +** (if NO_RTP is specified, L2CAP_MIN_OFFSET can be used) +** This allows enough space in the buffer for the L2CAP and +** AVDTP headers. +** +** The memory pointed to by p_pkt must be a GKI buffer +** allocated by the application. This buffer will be freed +** by the protocol stack; the application must not free +** this buffer. +** +** The opt parameter allows passing specific options like: +** - NO_RTP : do not add the RTP header to buffer +** +** Returns AVDT_SUCCESS if successful, otherwise error. +** +*******************************************************************************/ +extern UINT16 AVDT_WriteReqOpt(UINT8 handle, BT_HDR *p_pkt, UINT32 time_stamp, + UINT8 m_pt, tAVDT_DATA_OPT_MASK opt); + +/******************************************************************************* +** +** Function AVDT_ConnectReq +** +** Description This function initiates an AVDTP signaling connection +** to the peer device. When the connection is completed, an +** AVDT_CONNECT_IND_EVT is sent to the application via its +** control callback function. If the connection attempt fails +** an AVDT_DISCONNECT_IND_EVT is sent. The security mask +** parameter overrides the outgoing security mask set in +** AVDT_Register(). +** +** Returns AVDT_SUCCESS if successful, otherwise error. +** +*******************************************************************************/ +extern UINT16 AVDT_ConnectReq(BD_ADDR bd_addr, UINT8 sec_mask, + tAVDT_CTRL_CBACK *p_cback); + +/******************************************************************************* +** +** Function AVDT_DisconnectReq +** +** Description This function disconnect an AVDTP signaling connection +** to the peer device. When disconnected an +** AVDT_DISCONNECT_IND_EVT is sent to the application via its +** control callback function. +** +** Returns AVDT_SUCCESS if successful, otherwise error. +** +*******************************************************************************/ +extern UINT16 AVDT_DisconnectReq(BD_ADDR bd_addr, tAVDT_CTRL_CBACK *p_cback); + +/******************************************************************************* +** +** Function AVDT_GetL2CapChannel +** +** Description Get the L2CAP CID used by the handle. +** +** Returns CID if successful, otherwise 0. +** +*******************************************************************************/ +extern UINT16 AVDT_GetL2CapChannel(UINT8 handle); + +/******************************************************************************* +** +** Function AVDT_GetSignalChannel +** +** Description Get the L2CAP CID used by the signal channel of the given handle. +** +** Returns CID if successful, otherwise 0. +** +*******************************************************************************/ +extern UINT16 AVDT_GetSignalChannel(UINT8 handle, BD_ADDR bd_addr); + +/******************************************************************************* +** +** Function AVDT_WriteDataReq +** +** Description Send a media packet to the peer device. The stream must +** be started before this function is called. Also, this +** function can only be called if the stream is a SRC. +** +** When AVDTP has sent the media packet and is ready for the +** next packet, an AVDT_WRITE_CFM_EVT is sent to the +** application via the control callback. The application must +** wait for the AVDT_WRITE_CFM_EVT before it makes the next +** call to AVDT_WriteDataReq(). If the applications calls +** AVDT_WriteDataReq() before it receives the event the packet +** will not be sent. The application may make its first call +** to AVDT_WriteDataReq() after it receives an +** AVDT_START_CFM_EVT or AVDT_START_IND_EVT. +** +** Returns AVDT_SUCCESS if successful, otherwise error. +** +*******************************************************************************/ +extern UINT16 AVDT_WriteDataReq(UINT8 handle, UINT8 *p_data, UINT32 data_len, + UINT32 time_stamp, UINT8 m_pt, UINT8 marker); + +/******************************************************************************* +** +** Function AVDT_SetMediaBuf +** +** Description Assigns buffer for media packets or forbids using of assigned +** buffer if argument p_buf is NULL. This function can only +** be called if the stream is a SNK. +** +** AVDTP uses this buffer to reassemble fragmented media packets. +** When AVDTP receives a complete media packet, it calls the +** p_media_cback assigned by AVDT_CreateStream(). +** This function can be called during callback to assign a +** different buffer for next media packet or can leave the current +** buffer for next packet. +** +** Returns AVDT_SUCCESS if successful, otherwise error. +** +*******************************************************************************/ +extern UINT16 AVDT_SetMediaBuf(UINT8 handle, UINT8 *p_buf, UINT32 buf_len); + +/******************************************************************************* +** +** Function AVDT_SendReport +** +** Description +** +** +** +** Returns +** +*******************************************************************************/ +extern UINT16 AVDT_SendReport(UINT8 handle, AVDT_REPORT_TYPE type, + tAVDT_REPORT_DATA *p_data); + +/****************************************************************************** +** +** Function AVDT_SetTraceLevel +** +** Description Sets the trace level for AVDT. If 0xff is passed, the +** current trace level is returned. +** +** Input Parameters: +** new_level: The level to set the AVDT tracing to: +** 0xff-returns the current setting. +** 0-turns off tracing. +** >= 1-Errors. +** >= 2-Warnings. +** >= 3-APIs. +** >= 4-Events. +** >= 5-Debug. +** +** Returns The new trace level or current trace level if +** the input parameter is 0xff. +** +******************************************************************************/ +extern UINT8 AVDT_SetTraceLevel (UINT8 new_level); + +#ifdef __cplusplus +} +#endif + + +#endif /* AVDT_API_H */ diff --git a/components/bt/bluedroid/stack/include/avdt_defs.h b/components/bt/bluedroid/stack/include/avdt_defs.h new file mode 100755 index 0000000000..b6dbbc4f55 --- /dev/null +++ b/components/bt/bluedroid/stack/include/avdt_defs.h @@ -0,0 +1,203 @@ +/****************************************************************************** + * + * Copyright (C) 2002-2012 Broadcom Corporation + * + * 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 contains constants definitions and other information from the AVDTP + * specification. This file is intended for use internal to AVDT only. + * + ******************************************************************************/ +#ifndef AVDT_DEFS_H +#define AVDT_DEFS_H + +/***************************************************************************** +** constants +*****************************************************************************/ + +/* signalling packet type */ +#define AVDT_PKT_TYPE_SINGLE 0 /* single packet */ +#define AVDT_PKT_TYPE_START 1 /* start packet */ +#define AVDT_PKT_TYPE_CONT 2 /* continue packet */ +#define AVDT_PKT_TYPE_END 3 /* end packet */ + +/* signalling message type */ +#define AVDT_MSG_TYPE_CMD 0 /* command */ +#define AVDT_MSG_TYPE_GRJ 1 /* general reject */ +#define AVDT_MSG_TYPE_RSP 2 /* response accept */ +#define AVDT_MSG_TYPE_REJ 3 /* response reject */ + +/* signalling messages */ +#define AVDT_SIG_DISCOVER 1 /* discover */ +#define AVDT_SIG_GETCAP 2 /* get capabilities */ +#define AVDT_SIG_SETCONFIG 3 /* set configuration */ +#define AVDT_SIG_GETCONFIG 4 /* get configuration */ +#define AVDT_SIG_RECONFIG 5 /* reconfigure */ +#define AVDT_SIG_OPEN 6 /* open */ +#define AVDT_SIG_START 7 /* start */ +#define AVDT_SIG_CLOSE 8 /* close */ +#define AVDT_SIG_SUSPEND 9 /* suspend */ +#define AVDT_SIG_ABORT 10 /* abort */ +#define AVDT_SIG_SECURITY 11 /* security control */ +#define AVDT_SIG_GET_ALLCAP 12 /* get all capabilities */ +#define AVDT_SIG_DELAY_RPT 13 /* delay report */ + +/* maximum signal value */ +#define AVDT_SIG_MAX AVDT_SIG_DELAY_RPT + +/* used for general reject */ +#define AVDT_SIG_NONE 0 + +/* some maximum and minimum sizes of signalling messages */ +#define AVDT_DISCOVER_REQ_MIN 1 +#define AVDT_DISCOVER_REQ_MAX 124 + +/* service category information element field values */ +#define AVDT_CAT_TRANS 1 /* Media Transport */ +#define AVDT_CAT_REPORT 2 /* Reporting */ +#define AVDT_CAT_RECOV 3 /* Recovery */ +#define AVDT_CAT_PROTECT 4 /* Content Protection */ +#define AVDT_CAT_HDRCMP 5 /* Header Compression */ +#define AVDT_CAT_MUX 6 /* Multiplexing */ +#define AVDT_CAT_CODEC 7 /* Media Codec */ +#define AVDT_CAT_DELAY_RPT 8 /* Delay Reporting */ +#define AVDT_CAT_MAX_CUR AVDT_CAT_DELAY_RPT + +/* min/max lengths of service category information elements */ +#define AVDT_LEN_TRANS_MIN 0 +#define AVDT_LEN_REPORT_MIN 0 +#define AVDT_LEN_RECOV_MIN 3 +#define AVDT_LEN_PROTECT_MIN 2 +#define AVDT_LEN_HDRCMP_MIN 1 +#define AVDT_LEN_MUX_MIN 3 +#define AVDT_LEN_CODEC_MIN 2 +#define AVDT_LEN_DELAY_RPT_MIN 0 + +#define AVDT_LEN_TRANS_MAX 0 +#define AVDT_LEN_REPORT_MAX 0 +#define AVDT_LEN_RECOV_MAX 3 +#define AVDT_LEN_PROTECT_MAX 255 +#define AVDT_LEN_HDRCMP_MAX 1 +#define AVDT_LEN_MUX_MAX 7 +#define AVDT_LEN_CODEC_MAX 255 +#define AVDT_LEN_DELAY_RPT_MAX 0 + +/* minimum possible size of configuration or capabilities data */ +#define AVDT_LEN_CFG_MIN 2 + +/* minimum and maximum lengths for different message types */ +#define AVDT_LEN_SINGLE 1 +#define AVDT_LEN_SETCONFIG_MIN 2 +#define AVDT_LEN_RECONFIG_MIN 1 +#define AVDT_LEN_MULTI_MIN 1 +#define AVDT_LEN_SECURITY_MIN 1 +#define AVDT_LEN_DELAY_RPT 3 + +/* header lengths for different packet types */ +#define AVDT_LEN_TYPE_SINGLE 2 /* single packet */ +#define AVDT_LEN_TYPE_START 3 /* start packet */ +#define AVDT_LEN_TYPE_CONT 1 /* continue packet */ +#define AVDT_LEN_TYPE_END 1 /* end packet */ + +/* length of general reject message */ +#define AVDT_LEN_GEN_REJ 2 + +/* recovery service capabilities information elements */ +#define AVDT_RECOV_MRWS_MIN 0x01 /* min value for maximum recovery window */ +#define AVDT_RECOV_MRWS_MAX 0x18 /* max value for maximum recovery window */ +#define AVDT_RECOV_MNMP_MIN 0x01 /* min value for maximum number of media packets */ +#define AVDT_RECOV_MNMP_MAX 0x18 /* max value for maximum number of media packets */ + +/* SEID value range */ +#define AVDT_SEID_MIN 0x01 +#define AVDT_SEID_MAX 0x3E + +/* first byte of media packet header */ +#define AVDT_MEDIA_OCTET1 0x80 + +/* for adaptation layer header */ +#define AVDT_ALH_LCODE_MASK 0x03 /* coding of length field */ +#define AVDT_ALH_LCODE_NONE 0x00 /* No length field present. Take length from l2cap */ +#define AVDT_ALH_LCODE_16BIT 0x01 /* 16bit length field */ +#define AVDT_ALH_LCODE_9BITM0 0x02 /* 9 bit length field, MSB = 0, 8 LSBs in 1 octet following */ +#define AVDT_ALH_LCODE_9BITM1 0x03 /* 9 bit length field, MSB = 1, 8 LSBs in 1 octet following */ + +#define AVDT_ALH_FRAG_MASK 0x04 /* set this for continuation packet */ + +/***************************************************************************** +** message parsing and building macros +*****************************************************************************/ + +#define AVDT_MSG_PRS_HDR(p, lbl, pkt, msg) \ + lbl = *(p) >> 4; \ + pkt = (*(p) >> 2) & 0x03; \ + msg = *(p)++ & 0x03; + +#define AVDT_MSG_PRS_DISC(p, seid, in_use, type, tsep) \ + seid = *(p) >> 2; \ + in_use = (*(p)++ >> 1) & 0x01; \ + type = *(p) >> 4; \ + tsep = (*(p)++ >> 3) & 0x01; + +#define AVDT_MSG_PRS_SIG(p, sig) \ + sig = *(p)++ & 0x3F; + +#define AVDT_MSG_PRS_SEID(p, seid) \ + seid = *(p)++ >> 2; + +#define AVDT_MSG_PRS_PKT_TYPE(p, pkt) \ + pkt = (*(p) >> 2) & 0x03; + +#define AVDT_MSG_PRS_OCTET1(p, o_v, o_p, o_x, o_cc) \ + o_v = *(p) >> 6; \ + o_p = (*(p) >> 5) & 0x01; \ + o_x = (*(p) >> 4) & 0x01; \ + o_cc = *(p)++ & 0x0F; + +#define AVDT_MSG_PRS_RPT_OCTET1(p, o_v, o_p, o_cc) \ + o_v = *(p) >> 6; \ + o_p = (*(p) >> 5) & 0x01; \ + o_cc = *(p)++ & 0x1F; + +#define AVDT_MSG_PRS_M_PT(p, m_pt, marker) \ + marker = *(p) >> 7; \ + m_pt = *(p)++ & 0x7F; + +#define AVDT_MSG_BLD_HDR(p, lbl, pkt, msg) \ + *(p)++ = (UINT8) ((lbl) << 4) | ((pkt) << 2) | (msg); + +#define AVDT_MSG_BLD_DISC(p, seid, in_use, type, tsep) \ + *(p)++ = (UINT8) (((seid) << 2) | ((in_use) << 1)); \ + *(p)++ = (UINT8) (((type) << 4) | ((tsep) << 3)); + +#define AVDT_MSG_BLD_SIG(p, sig) \ + *(p)++ = (UINT8) (sig); + +#define AVDT_MSG_BLD_SEID(p, seid) \ + *(p)++ = (UINT8) ((seid) << 2); + +#define AVDT_MSG_BLD_ERR(p, err) \ + *(p)++ = (UINT8) (err); + +#define AVDT_MSG_BLD_PARAM(p, param) \ + *(p)++ = (UINT8) (param); + +#define AVDT_MSG_BLD_NOSP(p, nosp) \ + *(p)++ = (UINT8) (nosp); + +#endif /* AVDT_DEFS_H */ + diff --git a/components/bt/bluedroid/stack/include/avdt_int.h b/components/bt/bluedroid/stack/include/avdt_int.h new file mode 100755 index 0000000000..fb1b31360c --- /dev/null +++ b/components/bt/bluedroid/stack/include/avdt_int.h @@ -0,0 +1,742 @@ +/****************************************************************************** + * + * Copyright (C) 2002-2012 Broadcom Corporation + * + * 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 interfaces which are internal to AVDTP. + * + ******************************************************************************/ +#ifndef AVDT_INT_H +#define AVDT_INT_H + +#include "gki.h" +#include "avdt_api.h" +#include "avdtc_api.h" +#include "avdt_defs.h" +#include "l2c_api.h" +#include "btm_api.h" + +#ifndef AVDT_DEBUG +#define AVDT_DEBUG FALSE +#endif + +/***************************************************************************** +** constants +*****************************************************************************/ + +/* channel types */ +enum { + AVDT_CHAN_SIG, /* signaling channel */ + AVDT_CHAN_MEDIA, /* media channel */ +#if AVDT_REPORTING == TRUE + AVDT_CHAN_REPORT, /* reporting channel */ +#endif + AVDT_CHAN_NUM_TYPES +}; + +/* protocol service capabilities of this AVDTP implementation */ +/* for now multiplexing will be used only for fragmentation */ +#if ((AVDT_MULTIPLEXING == TRUE) && (AVDT_REPORTING == TRUE)) +#define AVDT_PSC (AVDT_PSC_TRANS | AVDT_PSC_MUX | AVDT_PSC_REPORT | AVDT_PSC_DELAY_RPT) +#define AVDT_LEG_PSC (AVDT_PSC_TRANS | AVDT_PSC_MUX | AVDT_PSC_REPORT) +#else /* AVDT_MULTIPLEXING && AVDT_REPORTING */ + +#if (AVDT_MULTIPLEXING == TRUE) +#define AVDT_PSC (AVDT_PSC_TRANS | AVDT_PSC_MUX | AVDT_PSC_DELAY_RPT) +#define AVDT_LEG_PSC (AVDT_PSC_TRANS | AVDT_PSC_MUX) +#else /* AVDT_MULTIPLEXING */ + +#if (AVDT_REPORTING == TRUE) +#define AVDT_PSC (AVDT_PSC_TRANS | AVDT_PSC_REPORT | AVDT_PSC_DELAY_RPT) +#define AVDT_LEG_PSC (AVDT_PSC_TRANS | AVDT_PSC_REPORT) +#else /* AVDT_REPORTING */ +#define AVDT_PSC (AVDT_PSC_TRANS | AVDT_PSC_DELAY_RPT) +#define AVDT_LEG_PSC (AVDT_PSC_TRANS) +#endif /* AVDT_REPORTING */ + +#endif /* AVDT_MULTIPLEXING */ + +#endif /* AVDT_MULTIPLEXING && AVDT_REPORTING */ + +/* initiator/acceptor signaling roles */ +#define AVDT_CLOSE_ACP 0 +#define AVDT_CLOSE_INT 1 +#define AVDT_OPEN_ACP 2 +#define AVDT_OPEN_INT 3 + +/* states for avdt_scb_verify */ +#define AVDT_VERIFY_OPEN 0 +#define AVDT_VERIFY_STREAMING 1 +#define AVDT_VERIFY_SUSPEND 2 +#define AVDT_VERIFY_START 3 + +/* to distinguish CCB events from SCB events */ +#define AVDT_CCB_MKR 0x80 + +/* offset where AVDTP signaling message header starts in message */ +#define AVDT_HDR_OFFSET (L2CAP_MIN_OFFSET + AVDT_NUM_SEPS) + +/* offset where AVDTP signaling message content starts; +** use the size of a start header since it's the largest possible +** layout of signaling message in a buffer is: +** +** | BT_HDR | SCB handles | L2CAP + HCI header | AVDTP header | data ... | +** +** Note that we "hide" the scb handles at the top of the message buffer. +*/ +#define AVDT_MSG_OFFSET (L2CAP_MIN_OFFSET + AVDT_NUM_SEPS + AVDT_LEN_TYPE_START) + +/* scb transport channel connect timeout value */ +#define AVDT_SCB_TC_CONN_TOUT 10 + +/* scb transport channel disconnect timeout value */ +#define AVDT_SCB_TC_DISC_TOUT 10 + +/* maximum number of command retransmissions */ +#ifndef AVDT_RET_MAX +#define AVDT_RET_MAX 1 +#endif + + +/* ccb state machine states */ +enum { + AVDT_CCB_IDLE_ST, + AVDT_CCB_OPENING_ST, + AVDT_CCB_OPEN_ST, + AVDT_CCB_CLOSING_ST +}; + +/* state machine action enumeration list */ +enum { + AVDT_CCB_CHAN_OPEN, + AVDT_CCB_CHAN_CLOSE, + AVDT_CCB_CHK_CLOSE, + AVDT_CCB_HDL_DISCOVER_CMD, + AVDT_CCB_HDL_DISCOVER_RSP, + AVDT_CCB_HDL_GETCAP_CMD, + AVDT_CCB_HDL_GETCAP_RSP, + AVDT_CCB_HDL_START_CMD, + AVDT_CCB_HDL_START_RSP, + AVDT_CCB_HDL_SUSPEND_CMD, + AVDT_CCB_HDL_SUSPEND_RSP, + AVDT_CCB_SND_DISCOVER_CMD, + AVDT_CCB_SND_DISCOVER_RSP, + AVDT_CCB_SND_GETCAP_CMD, + AVDT_CCB_SND_GETCAP_RSP, + AVDT_CCB_SND_START_CMD, + AVDT_CCB_SND_START_RSP, + AVDT_CCB_SND_SUSPEND_CMD, + AVDT_CCB_SND_SUSPEND_RSP, + AVDT_CCB_CLEAR_CMDS, + AVDT_CCB_CMD_FAIL, + AVDT_CCB_FREE_CMD, + AVDT_CCB_CONG_STATE, + AVDT_CCB_RET_CMD, + AVDT_CCB_SND_CMD, + AVDT_CCB_SND_MSG, + AVDT_CCB_SET_RECONN, + AVDT_CCB_CLR_RECONN, + AVDT_CCB_CHK_RECONN, + AVDT_CCB_CHK_TIMER, + AVDT_CCB_SET_CONN, + AVDT_CCB_SET_DISCONN, + AVDT_CCB_DO_DISCONN, + AVDT_CCB_LL_CLOSED, + AVDT_CCB_LL_OPENED, + AVDT_CCB_DEALLOC, + AVDT_CCB_NUM_ACTIONS +}; + +#define AVDT_CCB_IGNORE AVDT_CCB_NUM_ACTIONS + +/* ccb state machine events */ +enum { + AVDT_CCB_API_DISCOVER_REQ_EVT, + AVDT_CCB_API_GETCAP_REQ_EVT, + AVDT_CCB_API_START_REQ_EVT, + AVDT_CCB_API_SUSPEND_REQ_EVT, + AVDT_CCB_API_DISCOVER_RSP_EVT, + AVDT_CCB_API_GETCAP_RSP_EVT, + AVDT_CCB_API_START_RSP_EVT, + AVDT_CCB_API_SUSPEND_RSP_EVT, + AVDT_CCB_API_CONNECT_REQ_EVT, + AVDT_CCB_API_DISCONNECT_REQ_EVT, + AVDT_CCB_MSG_DISCOVER_CMD_EVT, + AVDT_CCB_MSG_GETCAP_CMD_EVT, + AVDT_CCB_MSG_START_CMD_EVT, + AVDT_CCB_MSG_SUSPEND_CMD_EVT, + AVDT_CCB_MSG_DISCOVER_RSP_EVT, + AVDT_CCB_MSG_GETCAP_RSP_EVT, + AVDT_CCB_MSG_START_RSP_EVT, + AVDT_CCB_MSG_SUSPEND_RSP_EVT, + AVDT_CCB_RCVRSP_EVT, + AVDT_CCB_SENDMSG_EVT, + AVDT_CCB_RET_TOUT_EVT, + AVDT_CCB_RSP_TOUT_EVT, + AVDT_CCB_IDLE_TOUT_EVT, + AVDT_CCB_UL_OPEN_EVT, + AVDT_CCB_UL_CLOSE_EVT, + AVDT_CCB_LL_OPEN_EVT, + AVDT_CCB_LL_CLOSE_EVT, + AVDT_CCB_LL_CONG_EVT +}; + + +/* scb state machine states; these state values are private to this module so +** the scb state cannot be read or set by actions functions +*/ +enum { + AVDT_SCB_IDLE_ST, + AVDT_SCB_CONF_ST, + AVDT_SCB_OPENING_ST, + AVDT_SCB_OPEN_ST, + AVDT_SCB_STREAM_ST, + AVDT_SCB_CLOSING_ST +}; + +/* state machine action enumeration list */ +enum { + AVDT_SCB_HDL_ABORT_CMD, + AVDT_SCB_HDL_ABORT_RSP, + AVDT_SCB_HDL_CLOSE_CMD, + AVDT_SCB_HDL_CLOSE_RSP, + AVDT_SCB_HDL_GETCONFIG_CMD, + AVDT_SCB_HDL_GETCONFIG_RSP, + AVDT_SCB_HDL_OPEN_CMD, + AVDT_SCB_HDL_OPEN_REJ, + AVDT_SCB_HDL_OPEN_RSP, + AVDT_SCB_HDL_PKT, + AVDT_SCB_DROP_PKT, + AVDT_SCB_HDL_RECONFIG_CMD, + AVDT_SCB_HDL_RECONFIG_RSP, + AVDT_SCB_HDL_SECURITY_CMD, + AVDT_SCB_HDL_SECURITY_RSP, + AVDT_SCB_HDL_SETCONFIG_CMD, + AVDT_SCB_HDL_SETCONFIG_REJ, + AVDT_SCB_HDL_SETCONFIG_RSP, + AVDT_SCB_HDL_START_CMD, + AVDT_SCB_HDL_START_RSP, + AVDT_SCB_HDL_SUSPEND_CMD, + AVDT_SCB_HDL_SUSPEND_RSP, + AVDT_SCB_HDL_TC_CLOSE, +#if AVDT_REPORTING == TRUE + AVDT_SCB_HDL_TC_CLOSE_STO, +#endif + AVDT_SCB_HDL_TC_OPEN, +#if AVDT_REPORTING == TRUE + AVDT_SCB_HDL_TC_OPEN_STO, +#endif + AVDT_SCB_SND_DELAY_RPT_REQ, + AVDT_SCB_HDL_DELAY_RPT_CMD, + AVDT_SCB_HDL_DELAY_RPT_RSP, + AVDT_SCB_HDL_WRITE_REQ, + AVDT_SCB_SND_ABORT_REQ, + AVDT_SCB_SND_ABORT_RSP, + AVDT_SCB_SND_CLOSE_REQ, + AVDT_SCB_SND_STREAM_CLOSE, + AVDT_SCB_SND_CLOSE_RSP, + AVDT_SCB_SND_GETCONFIG_REQ, + AVDT_SCB_SND_GETCONFIG_RSP, + AVDT_SCB_SND_OPEN_REQ, + AVDT_SCB_SND_OPEN_RSP, + AVDT_SCB_SND_RECONFIG_REQ, + AVDT_SCB_SND_RECONFIG_RSP, + AVDT_SCB_SND_SECURITY_REQ, + AVDT_SCB_SND_SECURITY_RSP, + AVDT_SCB_SND_SETCONFIG_REQ, + AVDT_SCB_SND_SETCONFIG_REJ, + AVDT_SCB_SND_SETCONFIG_RSP, + AVDT_SCB_SND_TC_CLOSE, + AVDT_SCB_CB_ERR, + AVDT_SCB_CONG_STATE, + AVDT_SCB_REJ_STATE, + AVDT_SCB_REJ_IN_USE, + AVDT_SCB_REJ_NOT_IN_USE, + AVDT_SCB_SET_REMOVE, + AVDT_SCB_FREE_PKT, + AVDT_SCB_CLR_PKT, + AVDT_SCB_CHK_SND_PKT, + AVDT_SCB_TC_TIMER, + AVDT_SCB_CLR_VARS, + AVDT_SCB_DEALLOC, + AVDT_SCB_NUM_ACTIONS +}; + +#define AVDT_SCB_IGNORE AVDT_SCB_NUM_ACTIONS + +/* scb state machine events */ +enum { + AVDT_SCB_API_REMOVE_EVT, + AVDT_SCB_API_WRITE_REQ_EVT, + AVDT_SCB_API_GETCONFIG_REQ_EVT, + AVDT_SCB_API_DELAY_RPT_REQ_EVT, + AVDT_SCB_API_SETCONFIG_REQ_EVT, + AVDT_SCB_API_OPEN_REQ_EVT, + AVDT_SCB_API_CLOSE_REQ_EVT, + AVDT_SCB_API_RECONFIG_REQ_EVT, + AVDT_SCB_API_SECURITY_REQ_EVT, + AVDT_SCB_API_ABORT_REQ_EVT, + AVDT_SCB_API_GETCONFIG_RSP_EVT, + AVDT_SCB_API_SETCONFIG_RSP_EVT, + AVDT_SCB_API_SETCONFIG_REJ_EVT, + AVDT_SCB_API_OPEN_RSP_EVT, + AVDT_SCB_API_CLOSE_RSP_EVT, + AVDT_SCB_API_RECONFIG_RSP_EVT, + AVDT_SCB_API_SECURITY_RSP_EVT, + AVDT_SCB_API_ABORT_RSP_EVT, + AVDT_SCB_MSG_SETCONFIG_CMD_EVT, + AVDT_SCB_MSG_GETCONFIG_CMD_EVT, + AVDT_SCB_MSG_OPEN_CMD_EVT, + AVDT_SCB_MSG_START_CMD_EVT, + AVDT_SCB_MSG_SUSPEND_CMD_EVT, + AVDT_SCB_MSG_CLOSE_CMD_EVT, + AVDT_SCB_MSG_ABORT_CMD_EVT, + AVDT_SCB_MSG_RECONFIG_CMD_EVT, + AVDT_SCB_MSG_SECURITY_CMD_EVT, + AVDT_SCB_MSG_DELAY_RPT_CMD_EVT, + AVDT_SCB_MSG_DELAY_RPT_RSP_EVT, + AVDT_SCB_MSG_SETCONFIG_RSP_EVT, + AVDT_SCB_MSG_GETCONFIG_RSP_EVT, + AVDT_SCB_MSG_OPEN_RSP_EVT, + AVDT_SCB_MSG_START_RSP_EVT, + AVDT_SCB_MSG_SUSPEND_RSP_EVT, + AVDT_SCB_MSG_CLOSE_RSP_EVT, + AVDT_SCB_MSG_ABORT_RSP_EVT, + AVDT_SCB_MSG_RECONFIG_RSP_EVT, + AVDT_SCB_MSG_SECURITY_RSP_EVT, + AVDT_SCB_MSG_SETCONFIG_REJ_EVT, + AVDT_SCB_MSG_OPEN_REJ_EVT, + AVDT_SCB_MSG_START_REJ_EVT, + AVDT_SCB_MSG_SUSPEND_REJ_EVT, + AVDT_SCB_TC_TOUT_EVT, + AVDT_SCB_TC_OPEN_EVT, + AVDT_SCB_TC_CLOSE_EVT, + AVDT_SCB_TC_CONG_EVT, + AVDT_SCB_TC_DATA_EVT, + AVDT_SCB_CC_CLOSE_EVT +}; + +/* adaption layer number of stream routing table entries */ +#if AVDT_REPORTING == TRUE +/* 2 channels(1 media, 1 report) for each SEP and one for signalling */ +#define AVDT_NUM_RT_TBL ((AVDT_NUM_SEPS<<1) + 1) +#else +#define AVDT_NUM_RT_TBL (AVDT_NUM_SEPS + 1) +#endif + +/* adaption layer number of transport channel table entries - moved to target.h +#define AVDT_NUM_TC_TBL (AVDT_NUM_SEPS + AVDT_NUM_LINKS) */ + +/* "states" used in transport channel table */ +#define AVDT_AD_ST_UNUSED 0 /* Unused - unallocated */ +#define AVDT_AD_ST_IDLE 1 /* No connection */ +#define AVDT_AD_ST_ACP 2 /* Waiting to accept a connection */ +#define AVDT_AD_ST_INT 3 /* Initiating a connection */ +#define AVDT_AD_ST_CONN 4 /* Waiting for connection confirm */ +#define AVDT_AD_ST_CFG 5 /* Waiting for configuration complete */ +#define AVDT_AD_ST_OPEN 6 /* Channel opened */ +#define AVDT_AD_ST_SEC_INT 7 /* Security process as INT */ +#define AVDT_AD_ST_SEC_ACP 8 /* Security process as ACP */ + +/* Configuration flags. tAVDT_TC_TBL.cfg_flags */ +#define AVDT_L2C_CFG_IND_DONE (1<<0) +#define AVDT_L2C_CFG_CFM_DONE (1<<1) +#define AVDT_L2C_CFG_CONN_INT (1<<2) +#define AVDT_L2C_CFG_CONN_ACP (1<<3) + + +/* result code for avdt_ad_write_req() (L2CA_DataWrite()) */ +#define AVDT_AD_FAILED L2CAP_DW_FAILED /* FALSE */ +#define AVDT_AD_SUCCESS L2CAP_DW_SUCCESS /* TRUE */ +#define AVDT_AD_CONGESTED L2CAP_DW_CONGESTED /* 2 */ + +/***************************************************************************** +** data types +*****************************************************************************/ + +/* msg union of all message parameter types */ +typedef union { + tAVDT_EVT_HDR hdr; + tAVDT_EVT_HDR single; + tAVDT_SETCONFIG config_cmd; + tAVDT_CONFIG reconfig_cmd; + tAVDT_MULTI multi; + tAVDT_SECURITY security_cmd; + tAVDT_DISCOVER discover_rsp; + tAVDT_CONFIG svccap; + tAVDT_SECURITY security_rsp; + tAVDT_DELAY_RPT delay_rpt_cmd; +} tAVDT_MSG; + +/* data type for AVDT_CCB_API_DISCOVER_REQ_EVT */ +typedef struct { + tAVDT_CTRL_CBACK *p_cback; + tAVDT_SEP_INFO *p_sep_info; + UINT8 num_seps; +} tAVDT_CCB_API_DISCOVER; + +/* data type for AVDT_CCB_API_GETCAP_REQ_EVT */ +typedef struct { + tAVDT_EVT_HDR single; + tAVDT_CTRL_CBACK *p_cback; + tAVDT_CFG *p_cfg; +} tAVDT_CCB_API_GETCAP; + +/* data type for AVDT_CCB_API_CONNECT_REQ_EVT */ +typedef struct { + tAVDT_CTRL_CBACK *p_cback; + UINT8 sec_mask; +} tAVDT_CCB_API_CONNECT; + +/* data type for AVDT_CCB_API_DISCONNECT_REQ_EVT */ +typedef struct { + tAVDT_CTRL_CBACK *p_cback; +} tAVDT_CCB_API_DISCONNECT; + +/* union associated with ccb state machine events */ +typedef union { + tAVDT_CCB_API_DISCOVER discover; + tAVDT_CCB_API_GETCAP getcap; + tAVDT_CCB_API_CONNECT connect; + tAVDT_CCB_API_DISCONNECT disconnect; + tAVDT_MSG msg; + BOOLEAN llcong; + UINT8 err_code; +} tAVDT_CCB_EVT; + +/* channel control block type */ +typedef struct { + BD_ADDR peer_addr; /* BD address of peer */ + TIMER_LIST_ENT timer_entry; /* CCB timer list entry */ + BUFFER_Q cmd_q; /* Queue for outgoing command messages */ + BUFFER_Q rsp_q; /* Queue for outgoing response and reject messages */ + tAVDT_CTRL_CBACK *proc_cback; /* Procedure callback function */ + tAVDT_CTRL_CBACK *p_conn_cback; /* Connection/disconnection callback function */ + void *p_proc_data; /* Pointer to data storage for procedure */ + BT_HDR *p_curr_cmd; /* Current command being sent awaiting response */ + BT_HDR *p_curr_msg; /* Current message being sent */ + BT_HDR *p_rx_msg; /* Current message being received */ + BOOLEAN allocated; /* Whether ccb is allocated */ + UINT8 state; /* The CCB state machine state */ + BOOLEAN ll_opened; /* TRUE if LL is opened */ + BOOLEAN proc_busy; /* TRUE when a discover or get capabilities procedure in progress */ + UINT8 proc_param; /* Procedure parameter; either SEID for get capabilities or number of SEPS for discover */ + BOOLEAN cong; /* Whether signaling channel is congested */ + UINT8 label; /* Message header "label" (sequence number) */ + BOOLEAN reconn; /* If TRUE, reinitiate connection after transitioning from CLOSING to IDLE state */ + UINT8 ret_count; /* Command retransmission count */ +} tAVDT_CCB; + +/* type for action functions */ +typedef void (*tAVDT_CCB_ACTION)(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data); + +/* type for AVDT_SCB_API_WRITE_REQ_EVT */ +typedef struct { + BT_HDR *p_buf; + UINT32 time_stamp; +#if AVDT_MULTIPLEXING == TRUE + BUFFER_Q frag_q; /* Queue for outgoing media fragments. p_buf should be 0 */ + UINT8 *p_data; + UINT32 data_len; +#endif + UINT8 m_pt; + tAVDT_DATA_OPT_MASK opt; +} tAVDT_SCB_APIWRITE; + +/* type for AVDT_SCB_TC_CLOSE_EVT */ +typedef struct { + UINT8 old_tc_state; /* channel state before closed */ + UINT8 tcid; /* TCID */ + UINT8 type; /* channel type */ +} tAVDT_SCB_TC_CLOSE; + +/* type for scb event data */ +typedef union { + tAVDT_MSG msg; + tAVDT_SCB_APIWRITE apiwrite; + tAVDT_DELAY_RPT apidelay; + tAVDT_OPEN open; + tAVDT_SCB_TC_CLOSE close; + BOOLEAN llcong; + BT_HDR *p_pkt; +} tAVDT_SCB_EVT; + +/* stream control block type */ +typedef struct { + tAVDT_CS cs; /* stream creation struct */ + tAVDT_CFG curr_cfg; /* current configuration */ + tAVDT_CFG req_cfg; /* requested configuration */ + TIMER_LIST_ENT timer_entry; /* timer entry */ + BT_HDR *p_pkt; /* packet waiting to be sent */ + tAVDT_CCB *p_ccb; /* ccb associated with this scb */ + UINT16 media_seq; /* media packet sequence number */ + BOOLEAN allocated; /* whether scb is allocated or unused */ + BOOLEAN in_use; /* whether stream being used by peer */ + BOOLEAN sink_activated; /* A2DP Sink activated/de-activated from Application */ + UINT8 role; /* initiator/acceptor role in current procedure */ + BOOLEAN remove; /* whether CB is marked for removal */ + UINT8 state; /* state machine state */ + UINT8 peer_seid; /* SEID of peer stream */ + UINT8 curr_evt; /* current event; set only by state machine */ + BOOLEAN cong; /* Whether media transport channel is congested */ + UINT8 close_code; /* Error code received in close response */ +#if AVDT_MULTIPLEXING == TRUE + BUFFER_Q frag_q; /* Queue for outgoing media fragments */ + UINT32 frag_off; /* length of already received media fragments */ + UINT32 frag_org_len; /* original length before fragmentation of receiving media packet */ + UINT8 *p_next_frag; /* next fragment to send */ + UINT8 *p_media_buf; /* buffer for media packet assigned by AVDT_SetMediaBuf */ + UINT32 media_buf_len; /* length of buffer for media packet assigned by AVDT_SetMediaBuf */ +#endif +} tAVDT_SCB; + +/* type for action functions */ +typedef void (*tAVDT_SCB_ACTION)(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data); + +/* adaption layer type for transport channel table */ +typedef struct { + UINT16 peer_mtu; /* L2CAP mtu of the peer device */ + UINT16 my_mtu; /* Our MTU for this channel */ + UINT16 my_flush_to; /* Our flush timeout for this channel */ + UINT16 lcid; + UINT8 tcid; /* transport channel id */ + UINT8 ccb_idx; /* channel control block associated with this tc */ + UINT8 state; /* transport channel state */ + UINT8 cfg_flags; /* L2CAP configuration flags */ + UINT8 id; +} tAVDT_TC_TBL; + +/* adaption layer type for stream routing table */ +typedef struct { + UINT16 lcid; /* L2CAP LCID of the associated transport channel */ + UINT8 scb_hdl; /* stream control block associated with this tc */ +} tAVDT_RT_TBL; + + +/* adaption layer control block */ +typedef struct { + tAVDT_RT_TBL rt_tbl[AVDT_NUM_LINKS][AVDT_NUM_RT_TBL]; + tAVDT_TC_TBL tc_tbl[AVDT_NUM_TC_TBL]; + UINT8 lcid_tbl[MAX_L2CAP_CHANNELS]; /* map LCID to tc_tbl index */ +} tAVDT_AD; + +/* Control block for AVDT */ +typedef struct { + tAVDT_REG rcb; /* registration control block */ + tAVDT_CCB ccb[AVDT_NUM_LINKS]; /* channel control blocks */ + tAVDT_SCB scb[AVDT_NUM_SEPS]; /* stream control blocks */ + tAVDT_AD ad; /* adaption layer control block */ + tAVDTC_CTRL_CBACK *p_conf_cback; /* conformance callback function */ + tAVDT_CCB_ACTION *p_ccb_act; /* pointer to CCB action functions */ + tAVDT_SCB_ACTION *p_scb_act; /* pointer to SCB action functions */ + tAVDT_CTRL_CBACK *p_conn_cback; /* connection callback function */ + UINT8 trace_level; /* trace level */ +} tAVDT_CB; + + +/***************************************************************************** +** function declarations +*****************************************************************************/ + +/* CCB function declarations */ +extern void avdt_ccb_init(void); +extern void avdt_ccb_event(tAVDT_CCB *p_ccb, UINT8 event, tAVDT_CCB_EVT *p_data); +extern tAVDT_CCB *avdt_ccb_by_bd(BD_ADDR bd_addr); +extern tAVDT_CCB *avdt_ccb_alloc(BD_ADDR bd_addr); +extern void avdt_ccb_dealloc(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data); +extern UINT8 avdt_ccb_to_idx(tAVDT_CCB *p_ccb); +extern tAVDT_CCB *avdt_ccb_by_idx(UINT8 idx); + +/* CCB action functions */ +extern void avdt_ccb_chan_open(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data); +extern void avdt_ccb_chan_close(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data); +extern void avdt_ccb_chk_close(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data); +extern void avdt_ccb_hdl_discover_cmd(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data); +extern void avdt_ccb_hdl_discover_rsp(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data); +extern void avdt_ccb_hdl_getcap_cmd(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data); +extern void avdt_ccb_hdl_getcap_rsp(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data); +extern void avdt_ccb_hdl_start_cmd(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data); +extern void avdt_ccb_hdl_start_rsp(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data); +extern void avdt_ccb_hdl_suspend_cmd(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data); +extern void avdt_ccb_hdl_suspend_rsp(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data); +extern void avdt_ccb_snd_discover_cmd(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data); +extern void avdt_ccb_snd_discover_rsp(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data); +extern void avdt_ccb_snd_getcap_cmd(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data); +extern void avdt_ccb_snd_getcap_rsp(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data); +extern void avdt_ccb_snd_start_cmd(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data); +extern void avdt_ccb_snd_start_rsp(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data); +extern void avdt_ccb_snd_suspend_cmd(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data); +extern void avdt_ccb_snd_suspend_rsp(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data); +extern void avdt_ccb_clear_cmds(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data); +extern void avdt_ccb_cmd_fail(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data); +extern void avdt_ccb_free_cmd(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data); +extern void avdt_ccb_cong_state(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data); +extern void avdt_ccb_ret_cmd(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data); +extern void avdt_ccb_snd_cmd(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data); +extern void avdt_ccb_snd_msg(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data); +extern void avdt_ccb_set_reconn(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data); +extern void avdt_ccb_clr_reconn(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data); +extern void avdt_ccb_chk_reconn(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data); +extern void avdt_ccb_chk_timer(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data); +extern void avdt_ccb_set_conn(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data); +extern void avdt_ccb_set_disconn(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data); +extern void avdt_ccb_do_disconn(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data); +extern void avdt_ccb_ll_closed(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data); +extern void avdt_ccb_ll_opened(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data); + +/* SCB function prototypes */ +extern void avdt_scb_event(tAVDT_SCB *p_scb, UINT8 event, tAVDT_SCB_EVT *p_data); +extern void avdt_scb_init(void); +extern tAVDT_SCB *avdt_scb_alloc(tAVDT_CS *p_cs); +extern void avdt_scb_dealloc(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data); +extern UINT8 avdt_scb_to_hdl(tAVDT_SCB *p_scb); +extern tAVDT_SCB *avdt_scb_by_hdl(UINT8 hdl); +extern UINT8 avdt_scb_verify(tAVDT_CCB *p_ccb, UINT8 state, UINT8 *p_seid, UINT16 num_seid, UINT8 *p_err_code); +extern void avdt_scb_peer_seid_list(tAVDT_MULTI *p_multi); +extern UINT32 avdt_scb_gen_ssrc(tAVDT_SCB *p_scb); + +/* SCB action functions */ +extern void avdt_scb_hdl_abort_cmd(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data); +extern void avdt_scb_hdl_abort_rsp(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data); +extern void avdt_scb_hdl_close_cmd(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data); +extern void avdt_scb_hdl_close_rsp(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data); +extern void avdt_scb_hdl_getconfig_cmd(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data); +extern void avdt_scb_hdl_getconfig_rsp(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data); +extern void avdt_scb_hdl_open_cmd(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data); +extern void avdt_scb_hdl_open_rej(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data); +extern void avdt_scb_hdl_open_rsp(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data); +extern void avdt_scb_hdl_pkt(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data); +extern void avdt_scb_drop_pkt(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data); +extern void avdt_scb_hdl_reconfig_cmd(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data); +extern void avdt_scb_hdl_reconfig_rsp(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data); +extern void avdt_scb_hdl_security_cmd(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data); +extern void avdt_scb_hdl_security_rsp(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data); +extern void avdt_scb_hdl_setconfig_cmd(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data); +extern void avdt_scb_hdl_setconfig_rej(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data); +extern void avdt_scb_hdl_setconfig_rsp(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data); +extern void avdt_scb_hdl_start_cmd(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data); +extern void avdt_scb_hdl_start_rsp(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data); +extern void avdt_scb_hdl_suspend_cmd(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data); +extern void avdt_scb_hdl_suspend_rsp(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data); +extern void avdt_scb_snd_delay_rpt_req(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data); +extern void avdt_scb_hdl_delay_rpt_cmd(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data); +extern void avdt_scb_hdl_delay_rpt_rsp(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data); +extern void avdt_scb_hdl_tc_close(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data); +extern void avdt_scb_hdl_tc_open(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data); +extern void avdt_scb_hdl_tc_close_sto(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data); +extern void avdt_scb_hdl_tc_open_sto(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data); +extern void avdt_scb_hdl_write_req(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data); +extern void avdt_scb_snd_abort_req(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data); +extern void avdt_scb_snd_abort_rsp(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data); +extern void avdt_scb_snd_close_req(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data); +extern void avdt_scb_snd_stream_close(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data); +extern void avdt_scb_snd_close_rsp(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data); +extern void avdt_scb_snd_getconfig_req(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data); +extern void avdt_scb_snd_getconfig_rsp(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data); +extern void avdt_scb_snd_open_req(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data); +extern void avdt_scb_snd_open_rsp(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data); +extern void avdt_scb_snd_reconfig_req(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data); +extern void avdt_scb_snd_reconfig_rsp(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data); +extern void avdt_scb_snd_security_req(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data); +extern void avdt_scb_snd_security_rsp(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data); +extern void avdt_scb_snd_setconfig_req(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data); +extern void avdt_scb_snd_setconfig_rej(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data); +extern void avdt_scb_snd_setconfig_rsp(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data); +extern void avdt_scb_snd_tc_close(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data); +extern void avdt_scb_cb_err(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data); +extern void avdt_scb_cong_state(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data); +extern void avdt_scb_rej_state(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data); +extern void avdt_scb_rej_in_use(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data); +extern void avdt_scb_rej_not_in_use(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data); +extern void avdt_scb_set_remove(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data); +extern void avdt_scb_free_pkt(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data); +extern void avdt_scb_chk_snd_pkt(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data); +extern void avdt_scb_clr_pkt(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data); +extern void avdt_scb_tc_timer(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data); +extern void avdt_scb_clr_vars(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data); +extern void avdt_scb_queue_frags(tAVDT_SCB *p_scb, UINT8 **pp_data, UINT32 *p_data_len, BUFFER_Q *pq); + +/* msg function declarations */ +extern BOOLEAN avdt_msg_send(tAVDT_CCB *p_ccb, BT_HDR *p_msg); +extern void avdt_msg_send_cmd(tAVDT_CCB *p_ccb, void *p_scb, UINT8 sig_id, tAVDT_MSG *p_params); +extern void avdt_msg_send_rsp(tAVDT_CCB *p_ccb, UINT8 sig_id, tAVDT_MSG *p_params); +extern void avdt_msg_send_rej(tAVDT_CCB *p_ccb, UINT8 sig_id, tAVDT_MSG *p_params); +extern void avdt_msg_send_grej(tAVDT_CCB *p_ccb, UINT8 sig_id, tAVDT_MSG *p_params); +extern void avdt_msg_ind(tAVDT_CCB *p_ccb, BT_HDR *p_buf); + +/* adaption layer function declarations */ +extern void avdt_ad_init(void); +extern UINT8 avdt_ad_type_to_tcid(UINT8 type, tAVDT_SCB *p_scb); +extern tAVDT_TC_TBL *avdt_ad_tc_tbl_by_st(UINT8 type, tAVDT_CCB *p_ccb, UINT8 state); +extern tAVDT_TC_TBL *avdt_ad_tc_tbl_by_lcid(UINT16 lcid); +extern tAVDT_TC_TBL *avdt_ad_tc_tbl_alloc(tAVDT_CCB *p_ccb); +extern UINT8 avdt_ad_tc_tbl_to_idx(tAVDT_TC_TBL *p_tbl); +extern void avdt_ad_tc_close_ind(tAVDT_TC_TBL *p_tbl, UINT16 reason); +extern void avdt_ad_tc_open_ind(tAVDT_TC_TBL *p_tbl); +extern void avdt_ad_tc_cong_ind(tAVDT_TC_TBL *p_tbl, BOOLEAN is_congested); +extern void avdt_ad_tc_data_ind(tAVDT_TC_TBL *p_tbl, BT_HDR *p_buf); +extern tAVDT_TC_TBL *avdt_ad_tc_tbl_by_type(UINT8 type, tAVDT_CCB *p_ccb, tAVDT_SCB *p_scb); +extern UINT8 avdt_ad_write_req(UINT8 type, tAVDT_CCB *p_ccb, tAVDT_SCB *p_scb, BT_HDR *p_buf); +extern void avdt_ad_open_req(UINT8 type, tAVDT_CCB *p_ccb, tAVDT_SCB *p_scb, UINT8 role); +extern void avdt_ad_close_req(UINT8 type, tAVDT_CCB *p_ccb, tAVDT_SCB *p_scb); + +extern void avdt_process_timeout(TIMER_LIST_ENT *p_tle); + +/***************************************************************************** +** macros +*****************************************************************************/ + +/* we store the scb and the label in the layer_specific field of the +** current cmd +*/ +#define AVDT_BLD_LAYERSPEC(ls, msg, label) \ + ls = (((label) << 4) | (msg)) + +#define AVDT_LAYERSPEC_LABEL(ls) ((UINT8)((ls) >> 4)) + +#define AVDT_LAYERSPEC_MSG(ls) ((UINT8)((ls) & 0x000F)) + +/***************************************************************************** +** global data +*****************************************************************************/ +#ifdef __cplusplus +extern "C" +{ +#endif + +/****************************************************************************** +** Main Control Block +*******************************************************************************/ +#if AVDT_DYNAMIC_MEMORY == FALSE +extern tAVDT_CB avdt_cb; +#else +extern tAVDT_CB *avdt_cb_ptr; +#define avdt_cb (*avdt_cb_ptr) +#endif + + +/* L2CAP callback registration structure */ +extern const tL2CAP_APPL_INFO avdt_l2c_appl; + +/* reject message event lookup table */ +extern const UINT8 avdt_msg_rej_2_evt[]; +#ifdef __cplusplus +} +#endif + +#endif /* AVDT_INT_H */ diff --git a/components/bt/bluedroid/stack/include/avdtc_api.h b/components/bt/bluedroid/stack/include/avdtc_api.h new file mode 100755 index 0000000000..96b20e77bf --- /dev/null +++ b/components/bt/bluedroid/stack/include/avdtc_api.h @@ -0,0 +1,230 @@ +/****************************************************************************** + * + * Copyright (C) 2002-2012 Broadcom Corporation + * + * 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 interface file contains the interface AVDTP conformance API. These + * additional API functions and callback events are provided for + * conformance testing purposes only. They are not intended to be used by + * an application. + * + ******************************************************************************/ +#ifndef AVDT_CAPI_H +#define AVDT_CAPI_H + +#include "avdt_api.h" + +/* start AVDTC events here to distinguish from AVDT events */ +#define AVDTC_EVT_BEGIN 0x80 + +#define AVDTC_DISCOVER_IND_EVT (0 + AVDTC_EVT_BEGIN) /* Discover indication */ +#define AVDTC_GETCAP_IND_EVT (1 + AVDTC_EVT_BEGIN) /* Get capabilities indication */ +#define AVDTC_SETCONFIG_CFM_EVT (2 + AVDTC_EVT_BEGIN) /* Set configuration confirm */ +#define AVDTC_GETCONFIG_IND_EVT (3 + AVDTC_EVT_BEGIN) /* Get configuration indication */ +#define AVDTC_GETCONFIG_CFM_EVT (4 + AVDTC_EVT_BEGIN) /* Get configuration confirm */ +#define AVDTC_OPEN_IND_EVT (5 + AVDTC_EVT_BEGIN) /* Open indication */ +#define AVDTC_START_IND_EVT (6 + AVDTC_EVT_BEGIN) /* Start indication */ +#define AVDTC_CLOSE_IND_EVT (7 + AVDTC_EVT_BEGIN) /* Close indication */ +#define AVDTC_SUSPEND_IND_EVT (8 + AVDTC_EVT_BEGIN) /* Suspend indication */ +#define AVDTC_ABORT_IND_EVT (9 + AVDTC_EVT_BEGIN) /* Abort indication */ +#define AVDTC_ABORT_CFM_EVT (10 + AVDTC_EVT_BEGIN) /* Abort confirm */ + +typedef struct { + tAVDT_EVT_HDR hdr; /* Event header */ + UINT8 seid_list[AVDT_NUM_SEPS]; /* Array of SEID values */ + UINT8 num_seps; /* Number of values in array */ +} tAVDT_MULTI; + +/* Union of all control callback event data structures */ +typedef union { + tAVDT_EVT_HDR hdr; + tAVDT_CONFIG getconfig_cfm; + tAVDT_MULTI start_ind; + tAVDT_MULTI suspend_ind; +} tAVDTC_CTRL; + +typedef void tAVDTC_CTRL_CBACK(UINT8 handle, BD_ADDR bd_addr, UINT8 event, tAVDTC_CTRL *p_data); + +#ifdef __cplusplus +extern "C" +{ +#endif + +/******************************************************************************* +** +** Function AVDTC_Init +** +** Description This function is called to begin using the conformance API. +** It must be called after AVDT_Register() and before any +** other API or conformance API functions are called. +** +** Returns void +** +*******************************************************************************/ +extern void AVDTC_Init(tAVDTC_CTRL_CBACK *p_cback); + +/******************************************************************************* +** +** Function AVDTC_DiscoverRsp +** +** Description Send a discover response. +** +** Returns void +** +*******************************************************************************/ +extern void AVDTC_DiscoverRsp(BD_ADDR bd_addr, UINT8 label, + tAVDT_SEP_INFO sep_info[], UINT8 num_seps); + +/******************************************************************************* +** +** Function AVDTC_GetCapRsp +** +** Description Send a get capabilities response. +** +** Returns void +** +*******************************************************************************/ +extern void AVDTC_GetCapRsp(BD_ADDR bd_addr, UINT8 label, tAVDT_CFG *p_cap); + +/******************************************************************************* +** +** Function AVDTC_GetAllCapRsp +** +** Description Send a get all capabilities response. +** +** Returns void +** +*******************************************************************************/ +extern void AVDTC_GetAllCapRsp(BD_ADDR bd_addr, UINT8 label, tAVDT_CFG *p_cap); + +/******************************************************************************* +** +** Function AVDTC_GetConfigReq +** +** Description Send a get configuration request. +** +** Returns void +** +*******************************************************************************/ +extern void AVDTC_GetConfigReq(UINT8 handle); + +/******************************************************************************* +** +** Function AVDTC_GetConfigRsp +** +** Description Send a get configuration response. +** +** Returns void +** +*******************************************************************************/ +extern void AVDTC_GetConfigRsp(UINT8 handle, UINT8 label, tAVDT_CFG *p_cfg); + +/******************************************************************************* +** +** Function AVDTC_OpenReq +** +** Description Send an open request. +** +** Returns void +** +*******************************************************************************/ +extern void AVDTC_OpenReq(UINT8 handle); + +/******************************************************************************* +** +** Function AVDTC_OpenRsp +** +** Description Send an open response. +** +** Returns void +** +*******************************************************************************/ +extern void AVDTC_OpenRsp(UINT8 handle, UINT8 label); + +/******************************************************************************* +** +** Function AVDTC_StartRsp +** +** Description Send a start response. +** +** Returns void +** +*******************************************************************************/ +extern void AVDTC_StartRsp(UINT8 *p_handles, UINT8 num_handles, UINT8 label); + +/******************************************************************************* +** +** Function AVDTC_CloseRsp +** +** Description Send a close response. +** +** Returns void +** +*******************************************************************************/ +extern void AVDTC_CloseRsp(UINT8 handle, UINT8 label); + +/******************************************************************************* +** +** Function AVDTC_SuspendRsp +** +** Description Send a suspend response. +** +** Returns void +** +*******************************************************************************/ +extern void AVDTC_SuspendRsp(UINT8 *p_handles, UINT8 num_handles, UINT8 label); + +/******************************************************************************* +** +** Function AVDTC_AbortReq +** +** Description Send an abort request. +** +** Returns void +** +*******************************************************************************/ +extern void AVDTC_AbortReq(UINT8 handle); + +/******************************************************************************* +** +** Function AVDTC_AbortRsp +** +** Description Send an abort response. +** +** Returns void +** +*******************************************************************************/ +extern void AVDTC_AbortRsp(UINT8 handle, UINT8 label); + +/******************************************************************************* +** +** Function AVDTC_Rej +** +** Description Send a reject message. +** +** Returns void +** +*******************************************************************************/ +extern void AVDTC_Rej(UINT8 handle, BD_ADDR bd_addr, UINT8 cmd, UINT8 label, + UINT8 err_code, UINT8 err_param); + +#ifdef __cplusplus +} +#endif + +#endif /* AVDT_CAPI_H */ diff --git a/components/bt/bluedroid/stack/include/avrc_api.h b/components/bt/bluedroid/stack/include/avrc_api.h new file mode 100755 index 0000000000..2198074d9e --- /dev/null +++ b/components/bt/bluedroid/stack/include/avrc_api.h @@ -0,0 +1,639 @@ +/****************************************************************************** + * + * Copyright (C) 2006-2012 Broadcom Corporation + * + * 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. + * + ******************************************************************************/ + +/****************************************************************************** + * + * nterface to AVRCP Application Programming Interface + * + ******************************************************************************/ +#ifndef AVRC_API_H +#define AVRC_API_H +#include "bt_target.h" +#include "avct_api.h" +#include "sdp_api.h" +#include "avrc_defs.h" + +/***************************************************************************** +** constants +*****************************************************************************/ + +/* API function return value result codes. */ +#define AVRC_SUCCESS AVCT_SUCCESS /* 0 Function successful */ +#define AVRC_NO_RESOURCES AVCT_NO_RESOURCES /* 1 Not enough resources */ +#define AVRC_BAD_HANDLE AVCT_BAD_HANDLE /* 2 Bad handle */ +#define AVRC_PID_IN_USE AVCT_PID_IN_USE /* 3 PID already in use */ +#define AVRC_NOT_OPEN AVCT_NOT_OPEN /* 4 Connection not open */ +#define AVRC_MSG_TOO_BIG 5 /* 5 the message length exceed the MTU of the browsing channel */ +#define AVRC_FAIL 0x10 /* 0x10 generic failure */ +#define AVRC_BAD_PARAM 0x11 /* 0x11 bad parameter */ + +/* Control role - same as AVCT_TARGET/AVCT_CONTROL */ +#define AVRC_CT_TARGET 1 /* target */ +#define AVRC_CT_CONTROL 2 /* controller */ +#define AVRC_CT_PASSIVE 4 /* If conflict, allow the other side to succeed */ + +/* Connection role */ +#define AVRC_CONN_INT AVCT_INT /* initiator */ +#define AVRC_CONN_ACP AVCT_ACP /* Acceptor */ + + +/* AVRC CTRL events */ +/* AVRC_OPEN_IND_EVT event is sent when the connection is successfully opened. + * This eventis sent in response to an AVRC_Open(). */ +#define AVRC_OPEN_IND_EVT 0 + +/* AVRC_CLOSE_IND_EVT event is sent when a connection is closed. + * This event can result from a call to AVRC_Close() or when the peer closes + * the connection. It is also sent when a connection attempted through + * AVRC_Open() fails. */ +#define AVRC_CLOSE_IND_EVT 1 + +/* AVRC_CONG_IND_EVT event indicates that AVCTP is congested and cannot send + * any more messages. */ +#define AVRC_CONG_IND_EVT 2 + +/* AVRC_UNCONG_IND_EVT event indicates that AVCTP is uncongested and ready to + * send messages. */ +#define AVRC_UNCONG_IND_EVT 3 + + /* AVRC_BROWSE_OPEN_IND_EVT event is sent when the browse channel is successfully opened. + * This eventis sent in response to an AVRC_Open() or AVRC_OpenBrowse() . */ +#define AVRC_BROWSE_OPEN_IND_EVT 4 + +/* AVRC_BROWSE_CLOSE_IND_EVT event is sent when a browse channel is closed. + * This event can result from a call to AVRC_Close(), AVRC_CloseBrowse() or when the peer closes + * the connection. It is also sent when a connection attempted through + * AVRC_OpenBrowse() fails. */ +#define AVRC_BROWSE_CLOSE_IND_EVT 5 + +/* AVRC_BROWSE_CONG_IND_EVT event indicates that AVCTP browse channel is congested and cannot send + * any more messages. */ +#define AVRC_BROWSE_CONG_IND_EVT 6 + +/* AVRC_BROWSE_UNCONG_IND_EVT event indicates that AVCTP browse channel is uncongested and ready to + * send messages. */ +#define AVRC_BROWSE_UNCONG_IND_EVT 7 + +/* AVRC_CMD_TIMEOUT_EVT event indicates timeout waiting for AVRC command response from the peer */ +#define AVRC_CMD_TIMEOUT_EVT 8 + +/* Supported categories */ +#define AVRC_SUPF_CT_CAT1 0x0001 /* Category 1 */ +#define AVRC_SUPF_CT_CAT2 0x0002 /* Category 2 */ +#define AVRC_SUPF_CT_CAT3 0x0004 /* Category 3 */ +#define AVRC_SUPF_CT_CAT4 0x0008 /* Category 4 */ +#define AVRC_SUPF_CT_BROWSE 0x0040 /* Browsing */ + +#define AVRC_SUPF_TG_CAT1 0x0001 /* Category 1 */ +#define AVRC_SUPF_TG_CAT2 0x0002 /* Category 2 */ +#define AVRC_SUPF_TG_CAT3 0x0004 /* Category 3 */ +#define AVRC_SUPF_TG_CAT4 0x0008 /* Category 4 */ +#define AVRC_SUPF_TG_APP_SETTINGS 0x0010 /* Player Application Settings */ +#define AVRC_SUPF_TG_GROUP_NAVI 0x0020 /* Group Navigation */ +#define AVRC_SUPF_TG_BROWSE 0x0040 /* Browsing */ +#define AVRC_SUPF_TG_MULTI_PLAYER 0x0080 /* Muliple Media Player */ + +#define AVRC_META_SUCCESS AVRC_SUCCESS +#define AVRC_META_FAIL AVRC_FAIL +#define AVRC_METADATA_CMD 0x0000 +#define AVRC_METADATA_RESP 0x0001 + + + +/***************************************************************************** +** data type definitions +*****************************************************************************/ + +/* This data type is used in AVRC_FindService() to initialize the SDP database + * to hold the result service search. */ +typedef struct +{ + UINT32 db_len; /* Length, in bytes, of the discovery database */ + tSDP_DISCOVERY_DB *p_db; /* Pointer to the discovery database */ + UINT16 num_attr;/* The number of attributes in p_attrs */ + UINT16 *p_attrs; /* The attributes filter. If NULL, AVRCP API sets the attribute filter + * to be ATTR_ID_SERVICE_CLASS_ID_LIST, ATTR_ID_BT_PROFILE_DESC_LIST, + * ATTR_ID_SUPPORTED_FEATURES, ATTR_ID_SERVICE_NAME and ATTR_ID_PROVIDER_NAME. + * If not NULL, the input is taken as the filter. */ +} tAVRC_SDP_DB_PARAMS; + +/* This callback function returns service discovery information to the + * application after the AVRC_FindService() API function is called. The + * implementation of this callback function must copy the p_service_name + * and p_provider_name parameters passed to it as they are not guaranteed + * to remain after the callback function exits. */ +typedef void (tAVRC_FIND_CBACK) (UINT16 status); + + +/* This is the control callback function. This function passes events + * listed in Table 20 to the application. */ +typedef void (tAVRC_CTRL_CBACK) (UINT8 handle, UINT8 event, UINT16 result, + BD_ADDR peer_addr); + + +/* This is the message callback function. It is executed when AVCTP has + * a message packet ready for the application. The implementation of this + * callback function must copy the tAVRC_MSG structure passed to it as it + * is not guaranteed to remain after the callback function exits. */ +typedef void (tAVRC_MSG_CBACK) (UINT8 handle, UINT8 label, UINT8 opcode, + tAVRC_MSG *p_msg); + +typedef struct +{ + tAVRC_CTRL_CBACK *p_ctrl_cback; /* pointer to application control callback */ + tAVRC_MSG_CBACK *p_msg_cback; /* pointer to application message callback */ + UINT32 company_id; /* the company ID */ + UINT8 conn; /* Connection role (Initiator/acceptor) */ + UINT8 control; /* Control role (Control/Target) */ +} tAVRC_CONN_CB; + + + +/***************************************************************************** +** external function declarations +*****************************************************************************/ +#ifdef __cplusplus +extern "C" +{ +#endif + +/****************************************************************************** +** +** Function AVRC_AddRecord +** +** Description This function is called to build an AVRCP SDP record. +** Prior to calling this function the application must +** call SDP_CreateRecord() to create an SDP record. +** +** Input Parameters: +** service_uuid: Indicates TG(UUID_SERVCLASS_AV_REM_CTRL_TARGET) +** or CT(UUID_SERVCLASS_AV_REMOTE_CONTROL) +** +** p_service_name: Pointer to a null-terminated character +** string containing the service name. +** If service name is not used set this to NULL. +** +** p_provider_name: Pointer to a null-terminated character +** string containing the provider name. +** If provider name is not used set this to NULL. +** +** categories: Supported categories. +** +** sdp_handle: SDP handle returned by SDP_CreateRecord(). +** +** Output Parameters: +** None. +** +** Returns AVRC_SUCCESS if successful. +** AVRC_NO_RESOURCES if not enough resources to build the SDP record. +** +******************************************************************************/ +extern UINT16 AVRC_AddRecord(UINT16 service_uuid, char *p_service_name, + char *p_provider_name, UINT16 categories, UINT32 sdp_handle); + +/****************************************************************************** +** +** Function AVRC_FindService +** +** Description This function is called by the application to perform service +** discovery and retrieve AVRCP SDP record information from a +** peer device. Information is returned for the first service +** record found on the server that matches the service UUID. +** The callback function will be executed when service discovery +** is complete. There can only be one outstanding call to +** AVRC_FindService() at a time; the application must wait for +** the callback before it makes another call to the function. +** The application is responsible for allocating memory for the +** discovery database. It is recommended that the size of the +** discovery database be at least 300 bytes. The application +** can deallocate the memory after the callback function has +** executed. +** +** Input Parameters: +** service_uuid: Indicates TG(UUID_SERVCLASS_AV_REM_CTRL_TARGET) +** or CT(UUID_SERVCLASS_AV_REMOTE_CONTROL) +** +** bd_addr: BD address of the peer device. +** +** p_db: SDP discovery database parameters. +** +** p_cback: Pointer to the callback function. +** +** Output Parameters: +** None. +** +** Returns AVRC_SUCCESS if successful. +** AVRC_BAD_PARAMS if discovery database parameters are invalid. +** AVRC_NO_RESOURCES if there are not enough resources to +** perform the service search. +** +******************************************************************************/ +extern UINT16 AVRC_FindService(UINT16 service_uuid, BD_ADDR bd_addr, + tAVRC_SDP_DB_PARAMS *p_db, tAVRC_FIND_CBACK *p_cback); + +/****************************************************************************** +** +** Function AVRC_Open +** +** Description This function is called to open a connection to AVCTP. +** The connection can be either an initiator or acceptor, as +** determined by the p_ccb->stream parameter. +** The connection can be a target, a controller or for both role, +** as determined by the p_ccb->control parameter. +** By definition, a target connection is an acceptor connection +** that waits for an incoming AVCTP connection from the peer. +** The connection remains available to the application until +** the application closes it by calling AVRC_Close(). The +** application does not need to reopen the connection after an +** AVRC_CLOSE_IND_EVT is received. +** +** Input Parameters: +** p_ccb->company_id: Company Identifier. +** +** p_ccb->p_ctrl_cback: Pointer to control callback function. +** +** p_ccb->p_msg_cback: Pointer to message callback function. +** +** p_ccb->conn: AVCTP connection role. This is set to +** AVCTP_INT for initiator connections and AVCTP_ACP +** for acceptor connections. +** +** p_ccb->control: Control role. This is set to +** AVRC_CT_TARGET for target connections, AVRC_CT_CONTROL +** for control connections or (AVRC_CT_TARGET|AVRC_CT_CONTROL) +** for connections that support both roles. +** +** peer_addr: BD address of peer device. This value is +** only used for initiator connections; for acceptor +** connections it can be set to NULL. +** +** Output Parameters: +** p_handle: Pointer to handle. This parameter is only +** valid if AVRC_SUCCESS is returned. +** +** Returns AVRC_SUCCESS if successful. +** AVRC_NO_RESOURCES if there are not enough resources to open +** the connection. +** +******************************************************************************/ +extern UINT16 AVRC_Open(UINT8 *p_handle, tAVRC_CONN_CB *p_ccb, + BD_ADDR_PTR peer_addr); + +/****************************************************************************** +** +** Function AVRC_Close +** +** Description Close a connection opened with AVRC_Open(). +** This function is called when the +** application is no longer using a connection. +** +** Input Parameters: +** handle: Handle of this connection. +** +** Output Parameters: +** None. +** +** Returns AVRC_SUCCESS if successful. +** AVRC_BAD_HANDLE if handle is invalid. +** +******************************************************************************/ +extern UINT16 AVRC_Close(UINT8 handle); + +/****************************************************************************** +** +** Function AVRC_OpenBrowse +** +** Description This function is called to open a browsing connection to AVCTP. +** The connection can be either an initiator or acceptor, as +** determined by the conn_role. +** The handle is returned by a previous call to AVRC_Open. +** +** Returns AVRC_SUCCESS if successful. +** AVRC_NO_RESOURCES if there are not enough resources to open +** the connection. +** +******************************************************************************/ +extern UINT16 AVRC_OpenBrowse(UINT8 handle, UINT8 conn_role); + +/****************************************************************************** +** +** Function AVRC_CloseBrowse +** +** Description Close a connection opened with AVRC_OpenBrowse(). +** This function is called when the +** application is no longer using a connection. +** +** Returns AVRC_SUCCESS if successful. +** AVRC_BAD_HANDLE if handle is invalid. +** +******************************************************************************/ +extern UINT16 AVRC_CloseBrowse(UINT8 handle); + +/****************************************************************************** +** +** Function AVRC_MsgReq +** +** Description This function is used to send the AVRCP byte stream in p_pkt +** down to AVCTP. +** +** It is expected that p_pkt->offset is at least AVCT_MSG_OFFSET +** p_pkt->layer_specific is AVCT_DATA_CTRL or AVCT_DATA_BROWSE +** p_pkt->event is AVRC_OP_VENDOR, AVRC_OP_PASS_THRU or AVRC_OP_BROWSING +** The above BT_HDR settings are set by the AVRC_Bld* functions. +** +** Returns AVRC_SUCCESS if successful. +** AVRC_BAD_HANDLE if handle is invalid. +** +******************************************************************************/ +extern UINT16 AVRC_MsgReq (UINT8 handle, UINT8 label, UINT8 ctype, BT_HDR *p_pkt); + +/****************************************************************************** +** +** Function AVRC_UnitCmd +** +** Description Send a UNIT INFO command to the peer device. This +** function can only be called for controller role connections. +** Any response message from the peer is passed back through +** the tAVRC_MSG_CBACK callback function. +** +** Input Parameters: +** handle: Handle of this connection. +** +** label: Transaction label. +** +** Output Parameters: +** None. +** +** Returns AVRC_SUCCESS if successful. +** AVRC_BAD_HANDLE if handle is invalid. +** +******************************************************************************/ +extern UINT16 AVRC_UnitCmd(UINT8 handle, UINT8 label); + +/****************************************************************************** +** +** Function AVRC_SubCmd +** +** Description Send a SUBUNIT INFO command to the peer device. This +** function can only be called for controller role connections. +** Any response message from the peer is passed back through +** the tAVRC_MSG_CBACK callback function. +** +** Input Parameters: +** handle: Handle of this connection. +** +** label: Transaction label. +** +** page: Specifies which part of the subunit type table +** is requested. For AVRCP it is typically zero. +** Value range is 0-7. +** +** Output Parameters: +** None. +** +** Returns AVRC_SUCCESS if successful. +** AVRC_BAD_HANDLE if handle is invalid. +** +******************************************************************************/ +extern UINT16 AVRC_SubCmd(UINT8 handle, UINT8 label, UINT8 page); + + +/****************************************************************************** +** +** Function AVRC_PassCmd +** +** Description Send a PASS THROUGH command to the peer device. This +** function can only be called for controller role connections. +** Any response message from the peer is passed back through +** the tAVRC_MSG_CBACK callback function. +** +** Input Parameters: +** handle: Handle of this connection. +** +** label: Transaction label. +** +** p_msg: Pointer to PASS THROUGH message structure. +** +** Output Parameters: +** None. +** +** Returns AVRC_SUCCESS if successful. +** AVRC_BAD_HANDLE if handle is invalid. +** +******************************************************************************/ +extern UINT16 AVRC_PassCmd(UINT8 handle, UINT8 label, tAVRC_MSG_PASS *p_msg); + +/****************************************************************************** +** +** Function AVRC_PassRsp +** +** Description Send a PASS THROUGH response to the peer device. This +** function can only be called for target role connections. +** This function must be called when a PASS THROUGH command +** message is received from the peer through the +** tAVRC_MSG_CBACK callback function. +** +** Input Parameters: +** handle: Handle of this connection. +** +** label: Transaction label. Must be the same value as +** passed with the command message in the callback function. +** +** p_msg: Pointer to PASS THROUGH message structure. +** +** Output Parameters: +** None. +** +** Returns AVRC_SUCCESS if successful. +** AVRC_BAD_HANDLE if handle is invalid. +** +******************************************************************************/ +extern UINT16 AVRC_PassRsp(UINT8 handle, UINT8 label, tAVRC_MSG_PASS *p_msg); + + +/****************************************************************************** +** +** Function AVRC_VendorCmd +** +** Description Send a VENDOR DEPENDENT command to the peer device. This +** function can only be called for controller role connections. +** Any response message from the peer is passed back through +** the tAVRC_MSG_CBACK callback function. +** +** Input Parameters: +** handle: Handle of this connection. +** +** label: Transaction label. +** +** p_msg: Pointer to VENDOR DEPENDENT message structure. +** +** Output Parameters: +** None. +** +** Returns AVRC_SUCCESS if successful. +** AVRC_BAD_HANDLE if handle is invalid. +** +******************************************************************************/ +extern UINT16 AVRC_VendorCmd(UINT8 handle, UINT8 label, tAVRC_MSG_VENDOR *p_msg); + + +/****************************************************************************** +** +** Function AVRC_VendorRsp +** +** Description Send a VENDOR DEPENDENT response to the peer device. This +** function can only be called for target role connections. +** This function must be called when a VENDOR DEPENDENT +** command message is received from the peer through the +** tAVRC_MSG_CBACK callback function. +** +** Input Parameters: +** handle: Handle of this connection. +** +** label: Transaction label. Must be the same value as +** passed with the command message in the callback function. +** +** p_msg: Pointer to VENDOR DEPENDENT message structure. +** +** Output Parameters: +** None. +** +** Returns AVRC_SUCCESS if successful. +** AVRC_BAD_HANDLE if handle is invalid. +** +******************************************************************************/ +extern UINT16 AVRC_VendorRsp(UINT8 handle, UINT8 label, tAVRC_MSG_VENDOR *p_msg); + + +/****************************************************************************** +** +** Function AVRC_SetTraceLevel +** +** Description Sets the trace level for AVRC. If 0xff is passed, the +** current trace level is returned. +** +** Input Parameters: +** new_level: The level to set the AVRC tracing to: +** 0xff-returns the current setting. +** 0-turns off tracing. +** >= 1-Errors. +** >= 2-Warnings. +** >= 3-APIs. +** >= 4-Events. +** >= 5-Debug. +** +** Returns The new trace level or current trace level if +** the input parameter is 0xff. +** +******************************************************************************/ +extern UINT8 AVRC_SetTraceLevel (UINT8 new_level); + +/******************************************************************************* +** +** Function AVRC_Init +** +** Description This function is called at stack startup to allocate the +** control block (if using dynamic memory), and initializes the +** control block and tracing level. +** +** Returns void +** +*******************************************************************************/ +extern void AVRC_Init(void); + +/******************************************************************************* +** +** Function AVRC_ParsCommand +** +** Description This function is used to parse the received command. +** +** Returns AVRC_STS_NO_ERROR, if the message in p_data is parsed successfully. +** Otherwise, the error code defined by AVRCP 1.4 +** +*******************************************************************************/ +extern tAVRC_STS AVRC_ParsCommand (tAVRC_MSG *p_msg, tAVRC_COMMAND *p_result, + UINT8 *p_buf, UINT16 buf_len); + +/******************************************************************************* +** +** Function AVRC_ParsResponse +** +** Description This function is used to parse the received response. +** +** Returns AVRC_STS_NO_ERROR, if the message in p_data is parsed successfully. +** Otherwise, the error code defined by AVRCP 1.4 +** +*******************************************************************************/ +extern tAVRC_STS AVRC_ParsResponse (tAVRC_MSG *p_msg, tAVRC_RESPONSE *p_result, + UINT8 *p_buf, UINT16 buf_len); + +/******************************************************************************* +** +** Function AVRC_BldCommand +** +** Description This function builds the given AVRCP command to the given +** GKI buffer +** +** Returns AVRC_STS_NO_ERROR, if the command is built successfully +** Otherwise, the error code. +** +*******************************************************************************/ +extern tAVRC_STS AVRC_BldCommand( tAVRC_COMMAND *p_cmd, BT_HDR **pp_pkt); + +/******************************************************************************* +** +** Function AVRC_BldResponse +** +** Description This function builds the given AVRCP response to the given +** GKI buffer +** +** Returns AVRC_STS_NO_ERROR, if the response is built successfully +** Otherwise, the error code. +** +*******************************************************************************/ +extern tAVRC_STS AVRC_BldResponse( UINT8 handle, tAVRC_RESPONSE *p_rsp, BT_HDR **pp_pkt); + +/************************************************************************** +** +** Function AVRC_IsValidAvcType +** +** Description Check if correct AVC type is specified +** +** Returns returns TRUE if it is valid +** +** +*******************************************************************************/ +extern BOOLEAN AVRC_IsValidAvcType(UINT8 pdu_id, UINT8 avc_type); + +/******************************************************************************* +** +** Function AVRC_IsValidPlayerAttr +** +** Description Check if the given attrib value is a valid one +** +** +** Returns returns TRUE if it is valid +** +*******************************************************************************/ +extern BOOLEAN AVRC_IsValidPlayerAttr(UINT8 attr); + +#ifdef __cplusplus +} +#endif + +#endif /* AVRC_API_H */ diff --git a/components/bt/bluedroid/stack/include/avrc_defs.h b/components/bt/bluedroid/stack/include/avrc_defs.h new file mode 100755 index 0000000000..d6ff8a0b59 --- /dev/null +++ b/components/bt/bluedroid/stack/include/avrc_defs.h @@ -0,0 +1,1417 @@ +/****************************************************************************** + * + * Copyright (C) 2006-2012 Broadcom Corporation + * + * 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. + * + ******************************************************************************/ + +/****************************************************************************** + * + * AVRCP definition and data types + * + ******************************************************************************/ +#ifndef _AVRC_DEFS_H +#define _AVRC_DEFS_H + +/***************************************************************************** +** constants +*****************************************************************************/ + +/* Profile revision numbers */ +#define AVRC_REV_1_0 0x0100 +#define AVRC_REV_1_3 0x0103 +#define AVRC_REV_1_4 0x0104 + +#define AVRC_PACKET_LEN 512 /* Per the spec, you must support 512 byte RC packets */ + +#define AVRC_MIN_CONTROL_MTU 48 /* Per the spec, minimum MTU for the control channel */ +#define AVRC_MIN_BROWSE_MTU 335 /* Per the spec, minimum MTU for the browsing channel */ + +#define AVRC_META_PDU_OFFSET 4 +#define AVRC_SUB_TYPE_LEN 4 +#define AVRC_UID_SIZE 8 +#define AVRC_FEATURE_MASK_SIZE 16 + +/* command type codes */ +#define AVRC_CMD_CTRL 0 /* Instruct a target to perform an operation */ +#define AVRC_CMD_STATUS 1 /* Check a device’s current status */ +#define AVRC_CMD_SPEC_INQ 2 /* Check whether a target supports a particular + control command; all operands are included */ +#define AVRC_CMD_NOTIF 3 /* Used for receiving notification of a change in a device’s state */ +#define AVRC_CMD_GEN_INQ 4 /* Check whether a target supports a particular + control command; operands are not included */ + +/* response type codes */ +#define AVRC_RSP_NOT_IMPL 8 /* The target does not implement the command specified + by the opcode and operand, + or doesn’t implement the specified subunit */ +#define AVRC_RSP_ACCEPT 9 /* The target executed or is executing the command */ +#define AVRC_RSP_REJ 10 /* The target implements the command specified by the + opcode but cannot respond because the current state + of the target doesn’t allow it */ +#define AVRC_RSP_IN_TRANS 11 /* The target implements the status command but it is + in a state of transition; the status command may + be retried at a future time */ +#define AVRC_RSP_IMPL_STBL 12 /* For specific inquiry or general inquiy commands, + the target implements the command; for status + commands, the target returns stable and includes + the status results */ +#define AVRC_RSP_CHANGED 13 /* The response frame contains a notification that the + target device’s state has changed */ +#define AVRC_RSP_INTERIM 15 /* For control commands, the target has accepted the + request but cannot return information within 100 + milliseconds; for notify commands, the target accepted + the command, and will notify the controller of a change + of target state at a future time */ + +/* subunit type */ +#define AVRC_SUB_MONITOR 0x00 /* Monitor */ +#define AVRC_SUB_AUDIO 0x01 /* Audio */ +#define AVRC_SUB_PRINTER 0x02 /* Printer */ +#define AVRC_SUB_DISC 0x03 /* Disc */ +#define AVRC_SUB_TAPE 0x04 /* Tape recorder/player */ +#define AVRC_SUB_TUNER 0x05 /* Tuner */ +#define AVRC_SUB_CA 0x06 /* CA */ +#define AVRC_SUB_CAMERA 0x07 /* Camera */ +#define AVRC_SUB_PANEL 0x09 /* Panel */ +#define AVRC_SUB_BB 0x0A /* Bulletin Board */ +#define AVRC_SUB_CAM_STOR 0x0B /* Camera Storage */ +#define AVRC_SUB_VENDOR 0x1C /* Vendor unique */ +#define AVRC_SUB_EXT 0x1E /* Subunit type extended to next byte */ +#define AVRC_SUB_UNIT 0x1F /* Unit */ + +/* opcodes - defined by 1394ta */ +#define AVRC_OP_UNIT_INFO 0x30 /* Report unit information */ +#define AVRC_OP_SUB_INFO 0x31 /* Report subunit information */ +#define AVRC_OP_VENDOR 0x00 /* Vendor-dependent commands */ +#define AVRC_OP_PASS_THRU 0x7C /* panel subunit opcode */ +/* opcodes 80-9F and E0-FF are not used by 1394ta.Sneak one for the browsing channel */ +#define AVRC_OP_BROWSE 0xFF /* Browsing */ +#define AVRC_OP_INVALID 0xFE /* invalid one */ + +/* Company ID's +*/ +#define AVRC_CO_BLUETOOTH_SIG 0x00FFFFFF +#define AVRC_CO_WIDCOMM 0x00000361 +#define AVRC_CO_BROADCOM 0x00001018 +#define AVRC_CO_METADATA 0x00001958 /* Unique COMPANY ID for Metadata messages */ + +/* State flag for Passthrough commands +*/ +#define AVRC_STATE_PRESS 0 +#define AVRC_STATE_RELEASE 1 + +/* Operation ID list for Passthrough commands +*/ +#define AVRC_ID_SELECT 0x00 /* select */ +#define AVRC_ID_UP 0x01 /* up */ +#define AVRC_ID_DOWN 0x02 /* down */ +#define AVRC_ID_LEFT 0x03 /* left */ +#define AVRC_ID_RIGHT 0x04 /* right */ +#define AVRC_ID_RIGHT_UP 0x05 /* right-up */ +#define AVRC_ID_RIGHT_DOWN 0x06 /* right-down */ +#define AVRC_ID_LEFT_UP 0x07 /* left-up */ +#define AVRC_ID_LEFT_DOWN 0x08 /* left-down */ +#define AVRC_ID_ROOT_MENU 0x09 /* root menu */ +#define AVRC_ID_SETUP_MENU 0x0A /* setup menu */ +#define AVRC_ID_CONT_MENU 0x0B /* contents menu */ +#define AVRC_ID_FAV_MENU 0x0C /* favorite menu */ +#define AVRC_ID_EXIT 0x0D /* exit */ +#define AVRC_ID_0 0x20 /* 0 */ +#define AVRC_ID_1 0x21 /* 1 */ +#define AVRC_ID_2 0x22 /* 2 */ +#define AVRC_ID_3 0x23 /* 3 */ +#define AVRC_ID_4 0x24 /* 4 */ +#define AVRC_ID_5 0x25 /* 5 */ +#define AVRC_ID_6 0x26 /* 6 */ +#define AVRC_ID_7 0x27 /* 7 */ +#define AVRC_ID_8 0x28 /* 8 */ +#define AVRC_ID_9 0x29 /* 9 */ +#define AVRC_ID_DOT 0x2A /* dot */ +#define AVRC_ID_ENTER 0x2B /* enter */ +#define AVRC_ID_CLEAR 0x2C /* clear */ +#define AVRC_ID_CHAN_UP 0x30 /* channel up */ +#define AVRC_ID_CHAN_DOWN 0x31 /* channel down */ +#define AVRC_ID_PREV_CHAN 0x32 /* previous channel */ +#define AVRC_ID_SOUND_SEL 0x33 /* sound select */ +#define AVRC_ID_INPUT_SEL 0x34 /* input select */ +#define AVRC_ID_DISP_INFO 0x35 /* display information */ +#define AVRC_ID_HELP 0x36 /* help */ +#define AVRC_ID_PAGE_UP 0x37 /* page up */ +#define AVRC_ID_PAGE_DOWN 0x38 /* page down */ +#define AVRC_ID_POWER 0x40 /* power */ +#define AVRC_ID_VOL_UP 0x41 /* volume up */ +#define AVRC_ID_VOL_DOWN 0x42 /* volume down */ +#define AVRC_ID_MUTE 0x43 /* mute */ +#define AVRC_ID_PLAY 0x44 /* play */ +#define AVRC_ID_STOP 0x45 /* stop */ +#define AVRC_ID_PAUSE 0x46 /* pause */ +#define AVRC_ID_RECORD 0x47 /* record */ +#define AVRC_ID_REWIND 0x48 /* rewind */ +#define AVRC_ID_FAST_FOR 0x49 /* fast forward */ +#define AVRC_ID_EJECT 0x4A /* eject */ +#define AVRC_ID_FORWARD 0x4B /* forward */ +#define AVRC_ID_BACKWARD 0x4C /* backward */ +#define AVRC_ID_ANGLE 0x50 /* angle */ +#define AVRC_ID_SUBPICT 0x51 /* subpicture */ +#define AVRC_ID_F1 0x71 /* F1 */ +#define AVRC_ID_F2 0x72 /* F2 */ +#define AVRC_ID_F3 0x73 /* F3 */ +#define AVRC_ID_F4 0x74 /* F4 */ +#define AVRC_ID_F5 0x75 /* F5 */ +#define AVRC_ID_VENDOR 0x7E /* vendor unique */ +#define AVRC_KEYPRESSED_RELEASE 0x80 + +/***************************************************************************** +** Metadata transfer definitions +*****************************************************************************/ + +/* Define the Metadata Packet types +*/ +#define AVRC_PKT_SINGLE 0 +#define AVRC_PKT_START 1 +#define AVRC_PKT_CONTINUE 2 +#define AVRC_PKT_END 3 +#define AVRC_PKT_TYPE_MASK 3 + +/* Define the PDUs carried in the vendor dependant data +*/ +#define AVRC_PDU_GET_CAPABILITIES 0x10 +#define AVRC_PDU_LIST_PLAYER_APP_ATTR 0x11 +#define AVRC_PDU_LIST_PLAYER_APP_VALUES 0x12 +#define AVRC_PDU_GET_CUR_PLAYER_APP_VALUE 0x13 +#define AVRC_PDU_SET_PLAYER_APP_VALUE 0x14 +#define AVRC_PDU_GET_PLAYER_APP_ATTR_TEXT 0x15 +#define AVRC_PDU_GET_PLAYER_APP_VALUE_TEXT 0x16 +#define AVRC_PDU_INFORM_DISPLAY_CHARSET 0x17 +#define AVRC_PDU_INFORM_BATTERY_STAT_OF_CT 0x18 +#define AVRC_PDU_GET_ELEMENT_ATTR 0x20 +#define AVRC_PDU_GET_PLAY_STATUS 0x30 +#define AVRC_PDU_REGISTER_NOTIFICATION 0x31 +#define AVRC_PDU_REQUEST_CONTINUATION_RSP 0x40 +#define AVRC_PDU_ABORT_CONTINUATION_RSP 0x41 +/* added in 1.4 */ +#define AVRC_PDU_SET_ABSOLUTE_VOLUME 0x50 +#define AVRC_PDU_SET_ADDRESSED_PLAYER 0x60 +#define AVRC_PDU_SET_BROWSED_PLAYER 0x70 +#define AVRC_PDU_GET_FOLDER_ITEMS 0x71 +#define AVRC_PDU_CHANGE_PATH 0x72 +#define AVRC_PDU_GET_ITEM_ATTRIBUTES 0x73 +#define AVRC_PDU_PLAY_ITEM 0x74 +#define AVRC_PDU_SEARCH 0x80 +#define AVRC_PDU_ADD_TO_NOW_PLAYING 0x90 +#define AVRC_PDU_GENERAL_REJECT 0xA0 + +/* Define the vendor unique id carried in the pass through data +*/ +#define AVRC_PDU_NEXT_GROUP 0x00 +#define AVRC_PDU_PREV_GROUP 0x01 +/* the only pass through vendor unique commands defined by AVRC is the group navigation commands + * The len for vendor unique data is 5 */ +#define AVRC_PASS_THRU_GROUP_LEN 5 + +#define AVRC_PDU_INVALID 0xff +/* 6.15.3 error status code for general reject */ +#define AVRC_STS_BAD_CMD 0x00 /* Invalid command, sent if TG received a PDU that it did not understand. */ +#define AVRC_STS_BAD_PARAM 0x01 /* Invalid parameter, sent if the TG received a PDU with a parameter ID that it did not understand. Sent if there is only one parameter ID in the PDU. */ +#define AVRC_STS_NOT_FOUND 0x02 /* Specified parameter not found., sent if the parameter ID is understood, but content is wrong or corrupted. */ +#define AVRC_STS_INTERNAL_ERR 0x03 /* Internal Error, sent if there are error conditions not covered by a more specific error code. */ +#define AVRC_STS_NO_ERROR 0x04 /* Operation completed without error. This is the status that should be returned if the operation was successful. */ +#define AVRC_STS_UID_CHANGED 0x05 /* UID Changed - The UIDs on the device have changed */ +/* #define AVRC_STS_GEN_ERROR 0x06 Unknown Error - this is changed to "reserved" */ +#define AVRC_STS_BAD_DIR 0x07 /* Invalid Direction - The Direction parameter is invalid - Change Path*/ +#define AVRC_STS_NOT_DIR 0x08 /* Not a Directory - The UID provided does not refer to a folder item Change Path*/ +#define AVRC_STS_NOT_EXIST 0x09 /* Does Not Exist - The UID provided does not refer to any item Change Path, PlayItem, AddToNowPlaying, GetItemAttributes*/ +#define AVRC_STS_BAD_SCOPE 0x0a /* Invalid Scope - The scope parameter is invalid GetFolderItems, PlayItem, AddToNowPlayer, GetItemAttributes, */ +#define AVRC_STS_BAD_RANGE 0x0b /* Range Out of Bounds - The start of range provided is not valid GetFolderItems*/ +#define AVRC_STS_UID_IS_DIR 0x0c /* UID is a Directory - The UID provided refers to a directory, which cannot be handled by this media player PlayItem, AddToNowPlaying */ +#define AVRC_STS_IN_USE 0x0d /* Media in Use - The media is not able to be used for this operation at this time PlayItem, AddToNowPlaying */ +#define AVRC_STS_NOW_LIST_FULL 0x0e /* Now Playing List Full - No more items can be added to the Now Playing List AddToNowPlaying*/ +#define AVRC_STS_SEARCH_NOT_SUP 0x0f /* Search Not Supported - The Browsed Media Player does not support search Search */ +#define AVRC_STS_SEARCH_BUSY 0x10 /* Search in Progress - A search operation is already in progress Search*/ +#define AVRC_STS_BAD_PLAYER_ID 0x11 /* Invalid Player Id - The specified Player Id does not refer to a valid player SetAddressedPlayer, SetBrowsedPlayer*/ +#define AVRC_STS_PLAYER_N_BR 0x12 /* Player Not Browsable - The Player Id supplied refers to a Media Player which does not support browsing. SetBrowsedPlayer */ +#define AVRC_STS_PLAYER_N_ADDR 0x13 /* Player Not Addressed. The Player Id supplied refers to a player which is not currently addressed, and the command is not able to be performed if the player is not set as addressed. Search, SetBrowsedPlayer*/ +#define AVRC_STS_BAD_SEARCH_RES 0x14 /* No valid Search Results - The Search result list does not contain valid entries, e.g. after being invalidated due to change of browsed player GetFolderItems */ +#define AVRC_STS_NO_AVAL_PLAYER 0x15 /* No available players ALL */ +#define AVRC_STS_ADDR_PLAYER_CHG 0x16 /* Addressed Player Changed - Register Notification */ +typedef UINT8 tAVRC_STS; + + +/* Define the Capability IDs +*/ +#define AVRC_CAP_COMPANY_ID 0x02 +#define AVRC_CAP_EVENTS_SUPPORTED 0x03 +#define AVRC_COMPANY_ID_LEN 3 +#define AVRC_CAPABILITY_OFFSET 2 + +/* Define the Player Application Settings IDs +*/ +#define AVRC_PLAYER_SETTING_EQUALIZER 0x01 +#define AVRC_PLAYER_SETTING_REPEAT 0x02 +#define AVRC_PLAYER_SETTING_SHUFFLE 0x03 +#define AVRC_PLAYER_SETTING_SCAN 0x04 +#define AVRC_PLAYER_SETTING_LOW_MENU_EXT 0x80 +#define AVRC_PLAYER_SETTING_HIGH_MENU_EXT 0xff + +/* Define the possible values of the Player Application Settings +*/ +#define AVRC_PLAYER_VAL_OFF 0x01 +#define AVRC_PLAYER_VAL_ON 0x02 +#define AVRC_PLAYER_VAL_SINGLE_REPEAT 0x02 +#define AVRC_PLAYER_VAL_ALL_REPEAT 0x03 +#define AVRC_PLAYER_VAL_GROUP_REPEAT 0x04 +#define AVRC_PLAYER_VAL_ALL_SHUFFLE 0x02 +#define AVRC_PLAYER_VAL_GROUP_SHUFFLE 0x03 +#define AVRC_PLAYER_VAL_ALL_SCAN 0x02 +#define AVRC_PLAYER_VAL_GROUP_SCAN 0x03 + +/* Define the possible values of Battery Status PDU +*/ +#define AVRC_BATTERY_STATUS_NORMAL 0x00 +#define AVRC_BATTERY_STATUS_WARNING 0x01 +#define AVRC_BATTERY_STATUS_CRITICAL 0x02 +#define AVRC_BATTERY_STATUS_EXTERNAL 0x03 +#define AVRC_BATTERY_STATUS_FULL_CHARGE 0x04 +typedef UINT8 tAVRC_BATTERY_STATUS; + +/* Define character set */ +#define AVRC_CHAR_SET_SIZE 2 + +/* Define the Media Attribute IDs +*/ +#define AVRC_MEDIA_ATTR_ID_TITLE 0x00000001 +#define AVRC_MEDIA_ATTR_ID_ARTIST 0x00000002 +#define AVRC_MEDIA_ATTR_ID_ALBUM 0x00000003 +#define AVRC_MEDIA_ATTR_ID_TRACK_NUM 0x00000004 +#define AVRC_MEDIA_ATTR_ID_NUM_TRACKS 0x00000005 +#define AVRC_MEDIA_ATTR_ID_GENRE 0x00000006 +#define AVRC_MEDIA_ATTR_ID_PLAYING_TIME 0x00000007 /* in miliseconds */ +#define AVRC_MAX_NUM_MEDIA_ATTR_ID 7 + +/* Define the possible values of play state +*/ +#define AVRC_PLAYSTATE_RESP_MSG_SIZE 9 +#define AVRC_PLAYSTATE_STOPPED 0x00 /* Stopped */ +#define AVRC_PLAYSTATE_PLAYING 0x01 /* Playing */ +#define AVRC_PLAYSTATE_PAUSED 0x02 /* Paused */ +#define AVRC_PLAYSTATE_FWD_SEEK 0x03 /* Fwd Seek*/ +#define AVRC_PLAYSTATE_REV_SEEK 0x04 /* Rev Seek*/ +#define AVRC_PLAYSTATE_ERROR 0xFF /* Error */ +typedef UINT8 tAVRC_PLAYSTATE; + +/* Define the events that can be registered for notifications +*/ +#define AVRC_EVT_PLAY_STATUS_CHANGE 0x01 +#define AVRC_EVT_TRACK_CHANGE 0x02 +#define AVRC_EVT_TRACK_REACHED_END 0x03 +#define AVRC_EVT_TRACK_REACHED_START 0x04 +#define AVRC_EVT_PLAY_POS_CHANGED 0x05 +#define AVRC_EVT_BATTERY_STATUS_CHANGE 0x06 +#define AVRC_EVT_SYSTEM_STATUS_CHANGE 0x07 +#define AVRC_EVT_APP_SETTING_CHANGE 0x08 +/* added in AVRCP 1.4 */ +#define AVRC_EVT_NOW_PLAYING_CHANGE 0x09 +#define AVRC_EVT_AVAL_PLAYERS_CHANGE 0x0a +#define AVRC_EVT_ADDR_PLAYER_CHANGE 0x0b +#define AVRC_EVT_UIDS_CHANGE 0x0c +#define AVRC_EVT_VOLUME_CHANGE 0x0d + +/* the number of events that can be registered for notifications */ +#define AVRC_NUM_NOTIF_EVENTS 0x0d + +#define AVRC_EVT_MSG_LEN_1 0x01 +#define AVRC_EVT_MSG_LEN_2 0x02 +#define AVRC_EVT_MSG_LEN_5 0x05 +#define AVRC_EVT_MSG_LEN_9 0x09 + +#define AVRC_MAX_VOLUME 0x7F + +/* Define the possible values of system status +*/ +#define AVRC_SYSTEMSTATE_PWR_ON 0x00 +#define AVRC_SYSTEMSTATE_PWR_OFF 0x01 +#define AVRC_SYSTEMSTATE_PWR_UNPLUGGED 0x02 +typedef UINT8 tAVRC_SYSTEMSTATE; + +/* the frequently used character set ids */ +#define AVRC_CHARSET_ID_ASCII ((UINT16) 0x0003) /* ASCII */ +#define AVRC_CHARSET_ID_UTF8 ((UINT16) 0x006a) /* UTF-8 */ +#define AVRC_CHARSET_ID_UTF16 ((UINT16) 0x03f7) /* 1015 */ +#define AVRC_CHARSET_ID_UTF32 ((UINT16) 0x03f9) /* 1017 */ + +/***************************************************************************** +** Advanced Control +*****************************************************************************/ +#define AVRC_ITEM_PLAYER 0x01 +#define AVRC_ITEM_FOLDER 0x02 +#define AVRC_ITEM_MEDIA 0x03 + +#define AVRC_SCOPE_PLAYER_LIST 0x00 /* Media Player Item - Contains all available media players */ +#define AVRC_SCOPE_FILE_SYSTEM 0x01 /* Folder Item, Media Element Item + - The virtual filesystem containing the media content of the browsed player */ +#define AVRC_SCOPE_SEARCH 0x02 /* Media Element Item The results of a search operation on the browsed player */ +#define AVRC_SCOPE_NOW_PLAYING 0x03 /* Media Element Item The Now Playing list (or queue) of the addressed player */ + +#define AVRC_FOLDER_ITEM_COUNT_NONE 0xFF + +/* folder type */ +#define AVRC_FOLDER_TYPE_MIXED 0x00 +#define AVRC_FOLDER_TYPE_TITLES 0x01 +#define AVRC_FOLDER_TYPE_ALNUMS 0x02 +#define AVRC_FOLDER_TYPE_ARTISTS 0x03 +#define AVRC_FOLDER_TYPE_GENRES 0x04 +#define AVRC_FOLDER_TYPE_PLAYLISTS 0x05 +#define AVRC_FOLDER_TYPE_YEARS 0x06 + +/* major player type */ +#define AVRC_MJ_TYPE_AUDIO 0x01 /* Audio */ +#define AVRC_MJ_TYPE_VIDEO 0x02 /* Video */ +#define AVRC_MJ_TYPE_BC_AUDIO 0x04 /* Broadcasting Audio */ +#define AVRC_MJ_TYPE_BC_VIDEO 0x08 /* Broadcasting Video */ +#define AVRC_MJ_TYPE_INVALID 0xF0 + +/* player sub type */ +#define AVRC_SUB_TYPE_NONE 0x00 +#define AVRC_SUB_TYPE_AUDIO_BOOK 0x01 /* Audio Book */ +#define AVRC_SUB_TYPE_PODCAST 0x02 /* Podcast */ +#define AVRC_SUB_TYPE_INVALID 0xFC + +/* media item - media type */ +#define AVRC_MEDIA_TYPE_AUDIO 0x00 +#define AVRC_MEDIA_TYPE_VIDEO 0x01 + +#define AVRC_DIR_UP 0x00 /* Folder Up */ +#define AVRC_DIR_DOWN 0x01 /* Folder Down */ + +#define AVRC_UID_SIZE 8 +typedef UINT8 tAVRC_UID[AVRC_UID_SIZE]; + +/***************************************************************************** +** player attribute - supported features +*****************************************************************************/ +#define AVRC_PF_SELECT_BIT_NO 0 +#define AVRC_PF_SELECT_MASK 0x01 +#define AVRC_PF_SELECT_OFF 0 +#define AVRC_PF_SELECT_SUPPORTED(x) ((x)[AVRC_PF_SELECT_OFF] & AVRC_PF_SELECT_MASK) + +#define AVRC_PF_UP_BIT_NO 1 +#define AVRC_PF_UP_MASK 0x02 +#define AVRC_PF_UP_OFF 0 +#define AVRC_PF_UP_SUPPORTED(x) ((x)[AVRC_PF_UP_OFF] & AVRC_PF_UP_MASK) + +#define AVRC_PF_DOWN_BIT_NO 2 +#define AVRC_PF_DOWN_MASK 0x04 +#define AVRC_PF_DOWN_OFF 0 +#define AVRC_PF_DOWN_SUPPORTED(x) ((x)[AVRC_PF_DOWN_OFF] & AVRC_PF_DOWN_MASK) + +#define AVRC_PF_LEFT_BIT_NO 3 +#define AVRC_PF_LEFT_MASK 0x08 +#define AVRC_PF_LEFT_OFF 0 +#define AVRC_PF_LEFT_SUPPORTED(x) ((x)[AVRC_PF_LEFT_OFF] & AVRC_PF_LEFT_MASK) + +#define AVRC_PF_RIGHT_BIT_NO 4 +#define AVRC_PF_RIGHT_MASK 0x10 +#define AVRC_PF_RIGHT_OFF 0 +#define AVRC_PF_RIGHT_SUPPORTED(x) ((x)[AVRC_PF_RIGHT_OFF] & AVRC_PF_RIGHT_MASK) + +#define AVRC_PF_RIGHTUP_BIT_NO 5 +#define AVRC_PF_RIGHTUP_MASK 0x20 +#define AVRC_PF_RIGHTUP_OFF 0 +#define AVRC_PF_RIGHTUP_SUPPORTED(x) ((x)[AVRC_PF_RIGHTUP_OFF] & AVRC_PF_RIGHTUP_MASK) + +#define AVRC_PF_RIGHTDOWN_BIT_NO 6 +#define AVRC_PF_RIGHTDOWN_MASK 0x40 +#define AVRC_PF_RIGHTDOWN_OFF 0 +#define AVRC_PF_RIGHTDOWN_SUPPORTED(x) ((x)[AVRC_PF_RIGHTDOWN_OFF] & AVRC_PF_RIGHTDOWN_MASK) + +#define AVRC_PF_LEFTUP_BIT_NO 7 +#define AVRC_PF_LEFTUP_MASK 0x80 +#define AVRC_PF_LEFTUP_OFF 0 +#define AVRC_PF_LEFTUP_SUPPORTED(x) ((x)[AVRC_PF_LEFTUP_OFF] & AVRC_PF_LEFTUP_MASK) + +#define AVRC_PF_LEFTDOWN_BIT_NO 8 +#define AVRC_PF_LEFTDOWN_MASK 0x01 +#define AVRC_PF_LEFTDOWN_OFF 1 +#define AVRC_PF_LEFTDOWN_SUPPORTED(x) ((x)[AVRC_PF_LEFTDOWN_OFF] & AVRC_PF_LEFTDOWN_MASK) + +#define AVRC_PF_ROOT_MENU_BIT_NO 9 +#define AVRC_PF_ROOT_MENU_MASK 0x02 +#define AVRC_PF_ROOT_MENU_OFF 1 +#define AVRC_PF_ROOT_MENU_SUPPORTED(x) ((x)[AVRC_PF_ROOT_MENU_OFF] & AVRC_PF_ROOT_MENU_MASK) + +#define AVRC_PF_SETUP_MENU_BIT_NO 10 +#define AVRC_PF_SETUP_MENU_MASK 0x04 +#define AVRC_PF_SETUP_MENU_OFF 1 +#define AVRC_PF_SETUP_MENU_SUPPORTED(x) ((x)[AVRC_PF_SETUP_MENU_OFF] & AVRC_PF_SETUP_MENU_MASK) + +#define AVRC_PF_CONTENTS_MENU_BIT_NO 11 +#define AVRC_PF_CONTENTS_MENU_MASK 0x08 +#define AVRC_PF_CONTENTS_MENU_OFF 1 +#define AVRC_PF_CONTENTS_MENU_SUPPORTED(x) ((x)[AVRC_PF_CONTENTS_MENU_OFF] & AVRC_PF_CONTENTS_MENU_MASK) + +#define AVRC_PF_FAVORITE_MENU_BIT_NO 12 +#define AVRC_PF_FAVORITE_MENU_MASK 0x10 +#define AVRC_PF_FAVORITE_MENU_OFF 1 +#define AVRC_PF_FAVORITE_MENU_SUPPORTED(x) ((x)[AVRC_PF_FAVORITE_MENU_OFF] & AVRC_PF_FAVORITE_MENU_MASK) + +#define AVRC_PF_EXIT_BIT_NO 13 +#define AVRC_PF_EXIT_MASK 0x20 +#define AVRC_PF_EXIT_OFF 1 +#define AVRC_PF_EXIT_SUPPORTED(x) ((x)[AVRC_PF_EXIT_OFF] & AVRC_PF_EXIT_MASK) + +#define AVRC_PF_0_BIT_NO 14 +#define AVRC_PF_0_MASK 0x40 +#define AVRC_PF_0_OFF 1 +#define AVRC_PF_0_SUPPORTED(x) ((x)[AVRC_PF_0_OFF] & AVRC_PF_0_MASK) + +#define AVRC_PF_1_BIT_NO 15 +#define AVRC_PF_1_MASK 0x80 +#define AVRC_PF_1_OFF 1 +#define AVRC_PF_1_SUPPORTED(x) ((x)[AVRC_PF_1_OFF] & AVRC_PF_1_MASK) + +#define AVRC_PF_2_BIT_NO 16 +#define AVRC_PF_2_MASK 0x01 +#define AVRC_PF_2_OFF 2 +#define AVRC_PF_2_SUPPORTED(x) ((x)[AVRC_PF_2_OFF] & AVRC_PF_2_MASK) + +#define AVRC_PF_3_BIT_NO 17 +#define AVRC_PF_3_MASK 0x02 +#define AVRC_PF_3_OFF 2 +#define AVRC_PF_3_SUPPORTED(x) ((x)[AVRC_PF_3_OFF] & AVRC_PF_3_MASK) + +#define AVRC_PF_4_BIT_NO 18 +#define AVRC_PF_4_MASK 0x04 +#define AVRC_PF_4_OFF 2 +#define AVRC_PF_4_SUPPORTED(x) ((x)[AVRC_PF_4_OFF] & AVRC_PF_4_MASK) + +#define AVRC_PF_5_BIT_NO 19 +#define AVRC_PF_5_MASK 0x08 +#define AVRC_PF_5_OFF 2 +#define AVRC_PF_5_SUPPORTED(x) ((x)[AVRC_PF_5_OFF] & AVRC_PF_5_MASK) + +#define AVRC_PF_6_BIT_NO 20 +#define AVRC_PF_6_MASK 0x10 +#define AVRC_PF_6_OFF 2 +#define AVRC_PF_6_SUPPORTED(x) ((x)[AVRC_PF_6_OFF] & AVRC_PF_6_MASK) + +#define AVRC_PF_7_BIT_NO 21 +#define AVRC_PF_7_MASK 0x20 +#define AVRC_PF_7_OFF 2 +#define AVRC_PF_7_SUPPORTED(x) ((x)[AVRC_PF_7_OFF] & AVRC_PF_7_MASK) + +#define AVRC_PF_8_BIT_NO 22 +#define AVRC_PF_8_MASK 0x40 +#define AVRC_PF_8_OFF 2 +#define AVRC_PF_8_SUPPORTED(x) ((x)[AVRC_PF_8_OFF] & AVRC_PF_8_MASK) + +#define AVRC_PF_9_BIT_NO 23 +#define AVRC_PF_9_MASK 0x80 +#define AVRC_PF_9_OFF 2 +#define AVRC_PF_9_SUPPORTED(x) ((x)[AVRC_PF_9_OFF] & AVRC_PF_9_MASK) + +#define AVRC_PF_DOT_BIT_NO 24 +#define AVRC_PF_DOT_MASK 0x01 +#define AVRC_PF_DOT_OFF 3 +#define AVRC_PF_DOT_SUPPORTED(x) ((x)[AVRC_PF_DOT_OFF] & AVRC_PF_DOT_MASK) + +#define AVRC_PF_ENTER_BIT_NO 25 +#define AVRC_PF_ENTER_MASK 0x02 +#define AVRC_PF_ENTER_OFF 3 +#define AVRC_PF_ENTER_SUPPORTED(x) ((x)[AVRC_PF_ENTER_OFF] & AVRC_PF_ENTER_MASK) + +#define AVRC_PF_CLEAR_BIT_NO 26 +#define AVRC_PF_CLEAR_MASK 0x04 +#define AVRC_PF_CLEAR_OFF 3 +#define AVRC_PF_CLEAR_SUPPORTED(x) ((x)[AVRC_PF_CLEAR_OFF] & AVRC_PF_CLEAR_MASK) + +#define AVRC_PF_CHNL_UP_BIT_NO 27 +#define AVRC_PF_CHNL_UP_MASK 0x08 +#define AVRC_PF_CHNL_UP_OFF 3 +#define AVRC_PF_CHNL_UP_SUPPORTED(x) ((x)[AVRC_PF_CHNL_UP_OFF] & AVRC_PF_CHNL_UP_MASK) + +#define AVRC_PF_CHNL_DOWN_BIT_NO 28 +#define AVRC_PF_CHNL_DOWN_MASK 0x10 +#define AVRC_PF_CHNL_DOWN_OFF 3 +#define AVRC_PF_CHNL_DOWN_SUPPORTED(x) ((x)[AVRC_PF_CHNL_DOWN_OFF] & AVRC_PF_CHNL_DOWN_MASK) + +#define AVRC_PF_PREV_CHNL_BIT_NO 29 +#define AVRC_PF_PREV_CHNL_MASK 0x20 +#define AVRC_PF_PREV_CHNL_OFF 3 +#define AVRC_PF_PREV_CHNL_SUPPORTED(x) ((x)[AVRC_PF_PREV_CHNL_OFF] & AVRC_PF_PREV_CHNL_MASK) + +#define AVRC_PF_SOUND_SEL_BIT_NO 30 +#define AVRC_PF_SOUND_SEL_MASK 0x40 +#define AVRC_PF_SOUND_SEL_OFF 3 +#define AVRC_PF_SOUND_SEL_SUPPORTED(x) ((x)[AVRC_PF_SOUND_SEL_OFF] & AVRC_PF_SOUND_SEL_MASK) + +#define AVRC_PF_INPUT_SEL_BIT_NO 31 +#define AVRC_PF_INPUT_SEL_MASK 0x80 +#define AVRC_PF_INPUT_SEL_OFF 3 +#define AVRC_PF_INPUT_SEL_SUPPORTED(x) ((x)[AVRC_PF_INPUT_SEL_OFF] & AVRC_PF_INPUT_SEL_MASK) + +#define AVRC_PF_DISP_INFO_BIT_NO 32 +#define AVRC_PF_DISP_INFO_MASK 0x01 +#define AVRC_PF_DISP_INFO_OFF 4 +#define AVRC_PF_DISP_INFO_SUPPORTED(x) ((x)[AVRC_PF_DISP_INFO_OFF] & AVRC_PF_DISP_INFO_MASK) + +#define AVRC_PF_HELP_BIT_NO 33 +#define AVRC_PF_HELP_MASK 0x02 +#define AVRC_PF_HELP_OFF 4 +#define AVRC_PF_HELP_SUPPORTED(x) ((x)[AVRC_PF_HELP_OFF] & AVRC_PF_HELP_MASK) + +#define AVRC_PF_PAGE_UP_BIT_NO 34 +#define AVRC_PF_PAGE_UP_MASK 0x04 +#define AVRC_PF_PAGE_UP_OFF 4 +#define AVRC_PF_PAGE_UP_SUPPORTED(x) ((x)[AVRC_PF_PAGE_UP_OFF] & AVRC_PF_PAGE_UP_MASK) + +#define AVRC_PF_PAGE_DOWN_BIT_NO 35 +#define AVRC_PF_PAGE_DOWN_MASK 0x08 +#define AVRC_PF_PAGE_DOWN_OFF 4 +#define AVRC_PF_PAGE_DOWN_SUPPORTED(x) ((x)[AVRC_PF_PAGE_DOWN_OFF] & AVRC_PF_PAGE_DOWN_MASK) + +#define AVRC_PF_POWER_BIT_NO 36 +#define AVRC_PF_POWER_MASK 0x10 +#define AVRC_PF_POWER_OFF 4 +#define AVRC_PF_POWER_SUPPORTED(x) ((x)[AVRC_PF_POWER_OFF] & AVRC_PF_POWER_MASK) + +#define AVRC_PF_VOL_UP_BIT_NO 37 +#define AVRC_PF_VOL_UP_MASK 0x20 +#define AVRC_PF_VOL_UP_OFF 4 +#define AVRC_PF_VOL_UP_SUPPORTED(x) ((x)[AVRC_PF_VOL_UP_OFF] & AVRC_PF_VOL_UP_MASK) + +#define AVRC_PF_VOL_DOWN_BIT_NO 38 +#define AVRC_PF_VOL_DOWN_MASK 0x40 +#define AVRC_PF_VOL_DOWN_OFF 4 +#define AVRC_PF_VOL_DOWN_SUPPORTED(x) ((x)[AVRC_PF_VOL_DOWN_OFF] & AVRC_PF_VOL_DOWN_MASK) + +#define AVRC_PF_MUTE_BIT_NO 39 +#define AVRC_PF_MUTE_MASK 0x80 +#define AVRC_PF_MUTE_OFF 4 +#define AVRC_PF_MUTE_SUPPORTED(x) ((x)[AVRC_PF_MUTE_OFF] & AVRC_PF_MUTE_MASK) + +#define AVRC_PF_PLAY_BIT_NO 40 +#define AVRC_PF_PLAY_MASK 0x01 +#define AVRC_PF_PLAY_OFF 5 +#define AVRC_PF_PLAY_SUPPORTED(x) ((x)[AVRC_PF_PLAY_OFF] & AVRC_PF_PLAY_MASK) + +#define AVRC_PF_STOP_BIT_NO 41 +#define AVRC_PF_STOP_MASK 0x02 +#define AVRC_PF_STOP_OFF 5 +#define AVRC_PF_STOP_SUPPORTED(x) ((x)[AVRC_PF_STOP_OFF] & AVRC_PF_STOP_MASK) + +#define AVRC_PF_PAUSE_BIT_NO 42 +#define AVRC_PF_PAUSE_MASK 0x04 +#define AVRC_PF_PAUSE_OFF 5 +#define AVRC_PF_PAUSE_SUPPORTED(x) ((x)[AVRC_PF_PAUSE_OFF] & AVRC_PF_PAUSE_MASK) + +#define AVRC_PF_RECORD_BIT_NO 43 +#define AVRC_PF_RECORD_MASK 0x08 +#define AVRC_PF_RECORD_OFF 5 +#define AVRC_PF_RECORD_SUPPORTED(x) ((x)[AVRC_PF_RECORD_OFF] & AVRC_PF_RECORD_MASK) + +#define AVRC_PF_REWIND_BIT_NO 44 +#define AVRC_PF_REWIND_MASK 0x10 +#define AVRC_PF_REWIND_OFF 5 +#define AVRC_PF_REWIND_SUPPORTED(x) ((x)[AVRC_PF_REWIND_OFF] & AVRC_PF_REWIND_MASK) + +#define AVRC_PF_FAST_FWD_BIT_NO 45 +#define AVRC_PF_FAST_FWD_MASK 0x20 +#define AVRC_PF_FAST_FWD_OFF 5 +#define AVRC_PF_FAST_FWD_SUPPORTED(x) ((x)[AVRC_PF_FAST_FWD_OFF] & AVRC_PF_FAST_FWD_MASK) + +#define AVRC_PF_EJECT_BIT_NO 46 +#define AVRC_PF_EJECT_MASK 0x40 +#define AVRC_PF_EJECT_OFF 5 +#define AVRC_PF_EJECT_SUPPORTED(x) ((x)[AVRC_PF_EJECT_OFF] & AVRC_PF_EJECT_MASK) + +#define AVRC_PF_FORWARD_BIT_NO 47 +#define AVRC_PF_FORWARD_MASK 0x80 +#define AVRC_PF_FORWARD_OFF 5 +#define AVRC_PF_FORWARD_SUPPORTED(x) ((x)[AVRC_PF_FORWARD_OFF] & AVRC_PF_FORWARD_MASK) + +#define AVRC_PF_BACKWARD_BIT_NO 48 +#define AVRC_PF_BACKWARD_MASK 0x01 +#define AVRC_PF_BACKWARD_OFF 6 +#define AVRC_PF_BACKWARD_SUPPORTED(x) ((x)[AVRC_PF_BACKWARD_OFF] & AVRC_PF_BACKWARD_MASK) + +#define AVRC_PF_ANGLE_BIT_NO 49 +#define AVRC_PF_ANGLE_MASK 0x02 +#define AVRC_PF_ANGLE_OFF 6 +#define AVRC_PF_ANGLE_SUPPORTED(x) ((x)[AVRC_PF_ANGLE_OFF] & AVRC_PF_ANGLE_MASK) + +#define AVRC_PF_SUBPICTURE_BIT_NO 50 +#define AVRC_PF_SUBPICTURE_MASK 0x04 +#define AVRC_PF_SUBPICTURE_OFF 6 +#define AVRC_PF_SUBPICTURE_SUPPORTED(x) ((x)[AVRC_PF_SUBPICTURE_OFF] & AVRC_PF_SUBPICTURE_MASK) + +#define AVRC_PF_F1_BIT_NO 51 +#define AVRC_PF_F1_MASK 0x08 +#define AVRC_PF_F1_OFF 6 +#define AVRC_PF_F1_SUPPORTED(x) ((x)[AVRC_PF_F1_OFF] & AVRC_PF_F1_MASK) + +#define AVRC_PF_F2_BIT_NO 52 +#define AVRC_PF_F2_MASK 0x10 +#define AVRC_PF_F2_OFF 6 +#define AVRC_PF_F2_SUPPORTED(x) ((x)[AVRC_PF_F2_OFF] & AVRC_PF_F2_MASK) + +#define AVRC_PF_F3_BIT_NO 53 +#define AVRC_PF_F3_MASK 0x20 +#define AVRC_PF_F3_OFF 6 +#define AVRC_PF_F3_SUPPORTED(x) ((x)[AVRC_PF_F3_OFF] & AVRC_PF_F3_MASK) + +#define AVRC_PF_F4_BIT_NO 54 +#define AVRC_PF_F4_MASK 0x40 +#define AVRC_PF_F4_OFF 6 +#define AVRC_PF_F4_SUPPORTED(x) ((x)[AVRC_PF_F4_OFF] & AVRC_PF_F4_MASK) + +#define AVRC_PF_F5_BIT_NO 55 +#define AVRC_PF_F5_MASK 0x80 +#define AVRC_PF_F5_OFF 6 +#define AVRC_PF_F5_SUPPORTED(x) ((x)[AVRC_PF_F5_OFF] & AVRC_PF_F5_MASK) + +/* Vendor unique. This PASSTHROUGH command is supported. */ +#define AVRC_PF_VENDOR_BIT_NO 56 +#define AVRC_PF_VENDOR_MASK 0x01 +#define AVRC_PF_VENDOR_OFF 7 +#define AVRC_PF_VENDOR_SUPPORTED(x) ((x)[AVRC_PF_VENDOR_OFF] & AVRC_PF_VENDOR_MASK) + +/* Basic Group Navigation. This overrules the SDP entry as it is set per player.7 */ +#define AVRC_PF_GROUP_NAVI_BIT_NO 57 +#define AVRC_PF_GROUP_NAVI_MASK 0x02 +#define AVRC_PF_GROUP_NAVI_OFF 7 +#define AVRC_PF_GROUP_NAVI_SUPPORTED(x) ((x)[AVRC_PF_GROUP_NAVI_OFF] & AVRC_PF_GROUP_NAVI_MASK) + +/* Advanced Control Player. This bit is set if the player supports at least AVRCP 1.4. */ +#define AVRC_PF_ADV_CTRL_BIT_NO 58 +#define AVRC_PF_ADV_CTRL_MASK 0x04 +#define AVRC_PF_ADV_CTRL_OFF 7 +#define AVRC_PF_ADV_CTRL_SUPPORTED(x) ((x)[AVRC_PF_ADV_CTRL_OFF] & AVRC_PF_ADV_CTRL_MASK) + +/* Browsing. This bit is set if the player supports browsing. */ +#define AVRC_PF_BROWSE_BIT_NO 59 +#define AVRC_PF_BROWSE_MASK 0x08 +#define AVRC_PF_BROWSE_OFF 7 +#define AVRC_PF_BROWSE_SUPPORTED(x) ((x)[AVRC_PF_BROWSE_OFF] & AVRC_PF_BROWSE_MASK) + +/* Searching. This bit is set if the player supports searching. */ +#define AVRC_PF_SEARCH_BIT_NO 60 +#define AVRC_PF_SEARCH_MASK 0x10 +#define AVRC_PF_SEARCH_OFF 7 +#define AVRC_PF_SEARCH_SUPPORTED(x) ((x)[AVRC_PF_SEARCH_OFF] & AVRC_PF_SEARCH_MASK) + +/* AddToNowPlaying. This bit is set if the player supports the AddToNowPlaying command. */ +#define AVRC_PF_ADD2NOWPLAY_BIT_NO 61 +#define AVRC_PF_ADD2NOWPLAY_MASK 0x20 +#define AVRC_PF_ADD2NOWPLAY_OFF 7 +#define AVRC_PF_ADD2NOWPLAY_SUPPORTED(x) ((x)[AVRC_PF_ADD2NOWPLAY_OFF] & AVRC_PF_ADD2NOWPLAY_MASK) + +/* UIDs unique in player browse tree. This bit is set if the player is able to maintain unique UIDs across the player browse tree. */ +#define AVRC_PF_UID_UNIQUE_BIT_NO 62 +#define AVRC_PF_UID_UNIQUE_MASK 0x40 +#define AVRC_PF_UID_UNIQUE_OFF 7 +#define AVRC_PF_UID_UNIQUE_SUPPORTED(x) ((x)[AVRC_PF_UID_UNIQUE_OFF] & AVRC_PF_UID_UNIQUE_MASK) + +/* OnlyBrowsableWhenAddressed. This bit is set if the player is only able to be browsed when it is set as the Addressed Player. */ +#define AVRC_PF_BR_WH_ADDR_BIT_NO 63 +#define AVRC_PF_BR_WH_ADDR_MASK 0x80 +#define AVRC_PF_BR_WH_ADDR_OFF 7 +#define AVRC_PF_BR_WH_ADDR_SUPPORTED(x) ((x)[AVRC_PF_BR_WH_ADDR_OFF] & AVRC_PF_BR_WH_ADDR_MASK) + +/* OnlySearchableWhenAddressed. This bit is set if the player is only able to be searched when it is set as the Addressed player. */ +#define AVRC_PF_SEARCH_WH_ADDR_BIT_NO 64 +#define AVRC_PF_SEARCH_WH_ADDR_MASK 0x01 +#define AVRC_PF_SEARCH_WH_ADDR_OFF 8 +#define AVRC_PF_SEARCH_WH_ADDR_SUPPORTED(x) ((x)[AVRC_PF_SEARCH_WH_ADDR_OFF] & AVRC_PF_SEARCH_WH_ADDR_MASK) + +/* NowPlaying. This bit is set if the player supports the NowPlaying folder. Note that for all players that support browsing this bit shall be set */ +#define AVRC_PF_NOW_PLAY_BIT_NO 65 +#define AVRC_PF_NOW_PLAY_MASK 0x02 +#define AVRC_PF_NOW_PLAY_OFF 8 +#define AVRC_PF_NOW_PLAY_SUPPORTED(x) ((x)[AVRC_PF_NOW_PLAY_OFF] & AVRC_PF_NOW_PLAY_MASK) + +/* UIDPersistency. This bit is set if the Player is able to persist UID values between AVRCP Browse Reconnect */ +#define AVRC_PF_UID_PERSIST_BIT_NO 66 +#define AVRC_PF_UID_PERSIST_MASK 0x04 +#define AVRC_PF_UID_PERSIST_OFF 8 +#define AVRC_PF_UID_PERSIST_SUPPORTED(x) ((x)[AVRC_PF_UID_PERSIST_OFF] & AVRC_PF_UID_PERSIST_MASK) + +/***************************************************************************** +** data type definitions +*****************************************************************************/ + +/* +This structure contains the header parameters of an AV/C message. +*/ +typedef struct +{ + UINT8 ctype; /* Command type. */ + UINT8 subunit_type; /* Subunit type. */ + UINT8 subunit_id; /* Subunit ID. This value is typically ignored in AVRCP, + * except for VENDOR DEPENDENT messages when the value is + * vendor-dependent. Value range is 0-7. */ + UINT8 opcode; /* Op Code (passthrough, vendor, etc) */ +} tAVRC_HDR; + +/* This structure contains a UNIT INFO message. */ +typedef struct +{ + tAVRC_HDR hdr; /* Message header. */ + UINT32 company_id; /* Company identifier. */ + UINT8 unit_type; /* Unit type. Uses the same values as subunit type. */ + UINT8 unit; /* This value is vendor dependent and typically zero. */ +} tAVRC_MSG_UNIT; + +/* This structure contains a SUBUNIT INFO message. */ +typedef struct +{ + tAVRC_HDR hdr; /* Message header. */ + UINT8 subunit_type[AVRC_SUB_TYPE_LEN]; + /* Array containing subunit type values. */ + BOOLEAN panel; /* TRUE if the panel subunit type is in the + * subunit_type array, FALSE otherwise. */ + UINT8 page; /* Specifies which part of the subunit type table is + * returned. For AVRCP it is typically zero. + * Value range is 0-7. */ +} tAVRC_MSG_SUB; + +/* This structure contains a VENDOR DEPENDENT message. */ +typedef struct +{ + tAVRC_HDR hdr; /* Message header. */ + UINT32 company_id; /* Company identifier. */ + UINT8 *p_vendor_data;/* Pointer to vendor dependent data. */ + UINT16 vendor_len; /* Length in bytes of vendor dependent data. */ +} tAVRC_MSG_VENDOR; + +/* PASS THROUGH message structure */ +typedef struct +{ + tAVRC_HDR hdr; /* hdr.ctype Unused. + * hdr.subunit_type Unused. + * hdr.subunit_id Unused. */ + UINT8 op_id; /* Operation ID. */ + UINT8 state; /* Keypress state. */ + UINT8 *p_pass_data;/* Pointer to data. This parameter is only valid + * when the op_id is AVRC_ID_VENDOR.*/ + UINT8 pass_len; /* Length in bytes of data. This parameter is only + * valid when the op_id is AVRC_ID_VENDOR.*/ +} tAVRC_MSG_PASS; + +/* Command/Response indicator. */ +#define AVRC_CMD AVCT_CMD /* Command message */ +#define AVRC_RSP AVCT_RSP /* Response message */ + +/* Browsing channel message structure */ +typedef struct +{ + tAVRC_HDR hdr; /* hdr.ctype AVRC_CMD or AVRC_RSP. + * hdr.subunit_type Unused. + * hdr.subunit_id Unused. */ + UINT8 *p_browse_data; /* Pointer to data. */ + UINT16 browse_len; /* Length in bytes of data. */ + BT_HDR *p_browse_pkt; /* The GKI buffer received. Set to NULL, if the callback function wants to keep the buffer */ +} tAVRC_MSG_BROWSE; + +/* This is a union of all message type structures. */ +typedef union +{ + tAVRC_HDR hdr; /* Message header. */ + tAVRC_MSG_UNIT unit; /* UNIT INFO message. */ + tAVRC_MSG_SUB sub; /* SUBUNIT INFO message. */ + tAVRC_MSG_VENDOR vendor; /* VENDOR DEPENDENT message. */ + tAVRC_MSG_PASS pass; /* PASS THROUGH message. */ + tAVRC_MSG_BROWSE browse; /* messages thru browsing channel */ +} tAVRC_MSG; + +/* macros */ +#define AVRC_IS_VALID_CAP_ID(a) (((a == AVRC_CAP_COMPANY_ID) || (a == AVRC_CAP_EVENTS_SUPPORTED)) ? TRUE : FALSE) + +#define AVRC_IS_VALID_EVENT_ID(a) (((a >= AVRC_EVT_PLAY_STATUS_CHANGE) && \ + (a <= AVRC_EVT_APP_SETTING_CHANGE)) ? TRUE : FALSE) + +#define AVRC_IS_VALID_ATTRIBUTE(a) (((((a > 0) && a <= AVRC_PLAYER_SETTING_SCAN)) || \ + (a >= AVRC_PLAYER_SETTING_LOW_MENU_EXT)) ? TRUE : FALSE) + +#define AVRC_IS_VALID_MEDIA_ATTRIBUTE(a) ((a >= AVRC_MEDIA_ATTR_ID_TITLE) && \ + (a <= AVRC_MEDIA_ATTR_ID_PLAYING_TIME) ? TRUE : FALSE) + +#define AVRC_IS_VALID_BATTERY_STATUS(a) ((a <= AVRC_BATTERY_STATUS_FULL_CHARGE) ? TRUE : FALSE) + +#define AVRC_IS_VALID_SYSTEM_STATUS(a) ((a <= AVRC_SYSTEMSTATE_PWR_UNPLUGGED) ? TRUE : FALSE) + +#define AVRC_IS_VALID_GROUP(a) ((a <= AVRC_PDU_PREV_GROUP) ? TRUE : FALSE) + +/* Company ID is 24-bit integer We can not use the macros in bt_types.h */ +#define AVRC_CO_ID_TO_BE_STREAM(p, u32) {*(p)++ = (UINT8)((u32) >> 16); *(p)++ = (UINT8)((u32) >> 8); *(p)++ = (UINT8)(u32); } +#define AVRC_BE_STREAM_TO_CO_ID(u32, p) {u32 = (((UINT32)(*((p) + 2))) + (((UINT32)(*((p) + 1))) << 8) + (((UINT32)(*(p))) << 16)); (p) += 3;} + +/***************************************************************************** +** data type definitions +*****************************************************************************/ +#define AVRC_MAX_APP_ATTR_SIZE 16 +#define AVRC_MAX_CHARSET_SIZE 16 +#define AVRC_MAX_ELEM_ATTR_SIZE 8 + + +/***************************************************************************** +** Metadata transfer Building/Parsing definitions +*****************************************************************************/ + +typedef struct { + UINT16 charset_id; + UINT16 str_len; + UINT8 *p_str; +} tAVRC_FULL_NAME; + +typedef struct { + UINT16 str_len; + UINT8 *p_str; +} tAVRC_NAME; + + +#ifndef AVRC_CAP_MAX_NUM_COMP_ID +#define AVRC_CAP_MAX_NUM_COMP_ID 4 +#endif + +#ifndef AVRC_CAP_MAX_NUM_EVT_ID +#define AVRC_CAP_MAX_NUM_EVT_ID 16 +#endif + +typedef union +{ + UINT32 company_id[AVRC_CAP_MAX_NUM_COMP_ID]; + UINT8 event_id[AVRC_CAP_MAX_NUM_EVT_ID]; +} tAVRC_CAPS_PARAM; + +typedef struct +{ + UINT8 attr_id; + UINT8 attr_val; +} tAVRC_APP_SETTING; + +typedef struct +{ + UINT8 attr_id; + UINT16 charset_id; + UINT8 str_len; + UINT8 *p_str; +} tAVRC_APP_SETTING_TEXT; + +typedef UINT8 tAVRC_FEATURE_MASK[AVRC_FEATURE_MASK_SIZE]; + +typedef struct +{ + UINT16 player_id; /* A unique identifier for this media player.*/ + UINT8 major_type; /* Use AVRC_MJ_TYPE_AUDIO, AVRC_MJ_TYPE_VIDEO, AVRC_MJ_TYPE_BC_AUDIO, or AVRC_MJ_TYPE_BC_VIDEO.*/ + UINT32 sub_type; /* Use AVRC_SUB_TYPE_NONE, AVRC_SUB_TYPE_AUDIO_BOOK, or AVRC_SUB_TYPE_PODCAST*/ + UINT8 play_status; /* Use AVRC_PLAYSTATE_STOPPED, AVRC_PLAYSTATE_PLAYING, AVRC_PLAYSTATE_PAUSED, AVRC_PLAYSTATE_FWD_SEEK, + AVRC_PLAYSTATE_REV_SEEK, or AVRC_PLAYSTATE_ERROR*/ + tAVRC_FEATURE_MASK features; /* Supported feature bit mask*/ + tAVRC_FULL_NAME name; /* The player name, name length and character set id.*/ +} tAVRC_ITEM_PLAYER; + +typedef struct +{ + tAVRC_UID uid; /* The uid of this folder */ + UINT8 type; /* Use AVRC_FOLDER_TYPE_MIXED, AVRC_FOLDER_TYPE_TITLES, + AVRC_FOLDER_TYPE_ALNUMS, AVRC_FOLDER_TYPE_ARTISTS, AVRC_FOLDER_TYPE_GENRES, + AVRC_FOLDER_TYPE_PLAYLISTS, or AVRC_FOLDER_TYPE_YEARS.*/ + BOOLEAN playable; /* TRUE, if the folder can be played. */ + tAVRC_FULL_NAME name; /* The folder name, name length and character set id. */ +} tAVRC_ITEM_FOLDER; + +typedef struct +{ + UINT32 attr_id; /* Use AVRC_MEDIA_ATTR_ID_TITLE, AVRC_MEDIA_ATTR_ID_ARTIST, AVRC_MEDIA_ATTR_ID_ALBUM, + AVRC_MEDIA_ATTR_ID_TRACK_NUM, AVRC_MEDIA_ATTR_ID_NUM_TRACKS, + AVRC_MEDIA_ATTR_ID_GENRE, AVRC_MEDIA_ATTR_ID_PLAYING_TIME */ + tAVRC_FULL_NAME name; /* The attribute value, value length and character set id. */ +} tAVRC_ATTR_ENTRY; + +typedef struct +{ + tAVRC_UID uid; /* The uid of this media element item */ + UINT8 type; /* Use AVRC_MEDIA_TYPE_AUDIO or AVRC_MEDIA_TYPE_VIDEO. */ + tAVRC_FULL_NAME name; /* The media name, name length and character set id. */ + UINT8 attr_count; /* The number of attributes in p_attr_list */ + tAVRC_ATTR_ENTRY* p_attr_list; /* Attribute entry list. */ +} tAVRC_ITEM_MEDIA; + +typedef struct +{ + UINT8 item_type; /* AVRC_ITEM_PLAYER, AVRC_ITEM_FOLDER, or AVRC_ITEM_MEDIA */ + union + { + tAVRC_ITEM_PLAYER player; /* The properties of a media player item.*/ + tAVRC_ITEM_FOLDER folder; /* The properties of a folder item.*/ + tAVRC_ITEM_MEDIA media; /* The properties of a media item.*/ + } u; +} tAVRC_ITEM; + +/* GetCapability */ +typedef struct +{ + UINT8 pdu; + tAVRC_STS status; + UINT8 opcode; /* Op Code (assigned by AVRC_BldCommand according to pdu) */ + UINT8 capability_id; +} tAVRC_GET_CAPS_CMD; + +/* ListPlayerAppValues */ +typedef struct +{ + UINT8 pdu; + tAVRC_STS status; + UINT8 opcode; /* Op Code (assigned by AVRC_BldCommand according to pdu) */ + UINT8 attr_id; +} tAVRC_LIST_APP_VALUES_CMD; + +/* GetCurAppValue */ +typedef struct +{ + UINT8 pdu; + tAVRC_STS status; + UINT8 opcode; /* Op Code (assigned by AVRC_BldCommand according to pdu) */ + UINT8 num_attr; + UINT8 attrs[AVRC_MAX_APP_ATTR_SIZE]; +} tAVRC_GET_CUR_APP_VALUE_CMD; + +/* SetAppValue */ +typedef struct +{ + UINT8 pdu; + tAVRC_STS status; + UINT8 opcode; /* Op Code (assigned by AVRC_BldCommand according to pdu) */ + UINT8 num_val; + tAVRC_APP_SETTING *p_vals; +} tAVRC_SET_APP_VALUE_CMD; + +/* GetAppAttrTxt */ +typedef struct +{ + UINT8 pdu; + tAVRC_STS status; + UINT8 opcode; /* Op Code (assigned by AVRC_BldCommand according to pdu) */ + UINT8 num_attr; + UINT8 attrs[AVRC_MAX_APP_ATTR_SIZE]; +} tAVRC_GET_APP_ATTR_TXT_CMD; + +/* GetAppValueTxt */ +typedef struct +{ + UINT8 pdu; + tAVRC_STS status; + UINT8 opcode; /* Op Code (assigned by AVRC_BldCommand according to pdu) */ + UINT8 attr_id; + UINT8 num_val; + UINT8 vals[AVRC_MAX_APP_ATTR_SIZE]; +} tAVRC_GET_APP_VAL_TXT_CMD; + +/* InformCharset */ +typedef struct +{ + UINT8 pdu; + tAVRC_STS status; + UINT8 opcode; /* Op Code (assigned by AVRC_BldCommand according to pdu) */ + UINT8 num_id; + UINT16 charsets[AVRC_MAX_CHARSET_SIZE]; +} tAVRC_INFORM_CHARSET_CMD; + +/* InformBatteryStatus */ +typedef struct +{ + UINT8 pdu; + tAVRC_STS status; + UINT8 opcode; /* Op Code (assigned by AVRC_BldCommand according to pdu) */ + UINT8 battery_status; +} tAVRC_BATTERY_STATUS_CMD; + +/* GetElemAttrs */ +typedef struct +{ + UINT8 pdu; + tAVRC_STS status; + UINT8 opcode; /* Op Code (assigned by AVRC_BldCommand according to pdu) */ + UINT8 num_attr; + UINT32 attrs[AVRC_MAX_ELEM_ATTR_SIZE]; +} tAVRC_GET_ELEM_ATTRS_CMD; + +/* RegNotify */ +typedef struct +{ + UINT8 pdu; + tAVRC_STS status; + UINT8 opcode; /* Op Code (assigned by AVRC_BldCommand according to pdu) */ + UINT8 event_id; + UINT32 param; +} tAVRC_REG_NOTIF_CMD; + +/* SetAddrPlayer */ +typedef struct +{ + UINT8 pdu; + tAVRC_STS status; + UINT8 opcode; /* Op Code (assigned by AVRC_BldCommand according to pdu) */ + UINT16 player_id; +} tAVRC_SET_ADDR_PLAYER_CMD; + +/* SetBrowsedPlayer */ +typedef struct +{ + UINT8 pdu; + tAVRC_STS status; + UINT8 opcode; /* Op Code (assigned by AVRC_BldCommand according to pdu) */ + UINT16 player_id; +} tAVRC_SET_BR_PLAYER_CMD; + +/* SetAbsVolume */ +typedef struct +{ + UINT8 pdu; + tAVRC_STS status; + UINT8 opcode; /* Op Code (assigned by AVRC_BldCommand according to pdu) */ + UINT8 volume; +} tAVRC_SET_VOLUME_CMD; + +/* GetFolderItems */ +typedef struct +{ + UINT8 pdu; + tAVRC_STS status; + UINT8 opcode; /* Op Code (assigned by AVRC_BldCommand according to pdu) */ + UINT8 scope; + UINT32 start_item; + UINT32 end_item; + UINT8 attr_count; + UINT32 *p_attr_list; +} tAVRC_GET_ITEMS_CMD; + +/* ChangePath */ +typedef struct +{ + UINT8 pdu; + tAVRC_STS status; + UINT8 opcode; /* Op Code (assigned by AVRC_BldCommand according to pdu) */ + UINT16 uid_counter; + UINT8 direction; + tAVRC_UID folder_uid; +} tAVRC_CHG_PATH_CMD; + +/* GetItemAttrs */ +typedef struct +{ + UINT8 pdu; + tAVRC_STS status; + UINT8 opcode; /* Op Code (assigned by AVRC_BldCommand according to pdu) */ + UINT8 scope; + tAVRC_UID uid; + UINT16 uid_counter; + UINT8 attr_count; + UINT32 *p_attr_list; +} tAVRC_GET_ATTRS_CMD; + +/* Search */ +typedef struct +{ + UINT8 pdu; + tAVRC_STS status; + UINT8 opcode; /* Op Code (assigned by AVRC_BldCommand according to pdu) */ + tAVRC_FULL_NAME string; +} tAVRC_SEARCH_CMD; + +/* PlayItem */ +typedef struct +{ + UINT8 pdu; + tAVRC_STS status; + UINT8 opcode; /* Op Code (assigned by AVRC_BldCommand according to pdu) */ + UINT8 scope; + tAVRC_UID uid; + UINT16 uid_counter; +} tAVRC_PLAY_ITEM_CMD; + +/* AddToNowPlaying */ +typedef struct +{ + UINT8 pdu; + tAVRC_STS status; + UINT8 opcode; /* Op Code (assigned by AVRC_BldCommand according to pdu) */ + UINT8 scope; + tAVRC_UID uid; + UINT16 uid_counter; +} tAVRC_ADD_TO_PLAY_CMD; + +typedef struct +{ + UINT8 pdu; + tAVRC_STS status; + UINT8 opcode; /* Op Code (assigned by AVRC_BldCommand according to pdu) */ +} tAVRC_CMD; + +/* Continue and Abort */ +typedef struct +{ + UINT8 pdu; + tAVRC_STS status; + UINT8 opcode; /* Op Code (assigned by AVRC_BldCommand according to pdu) */ + UINT8 target_pdu; +} tAVRC_NEXT_CMD; + +typedef union +{ + UINT8 pdu; + tAVRC_CMD cmd; + tAVRC_GET_CAPS_CMD get_caps; /* GetCapability */ + tAVRC_CMD list_app_attr; /* ListPlayerAppAttr */ + tAVRC_LIST_APP_VALUES_CMD list_app_values; /* ListPlayerAppValues */ + tAVRC_GET_CUR_APP_VALUE_CMD get_cur_app_val; /* GetCurAppValue */ + tAVRC_SET_APP_VALUE_CMD set_app_val; /* SetAppValue */ + tAVRC_GET_APP_ATTR_TXT_CMD get_app_attr_txt; /* GetAppAttrTxt */ + tAVRC_GET_APP_VAL_TXT_CMD get_app_val_txt; /* GetAppValueTxt */ + tAVRC_INFORM_CHARSET_CMD inform_charset; /* InformCharset */ + tAVRC_BATTERY_STATUS_CMD inform_battery_status; /* InformBatteryStatus */ + tAVRC_GET_ELEM_ATTRS_CMD get_elem_attrs; /* GetElemAttrs */ + tAVRC_CMD get_play_status; /* GetPlayStatus */ + tAVRC_REG_NOTIF_CMD reg_notif; /* RegNotify */ + tAVRC_NEXT_CMD continu; /* Continue */ + tAVRC_NEXT_CMD abort; /* Abort */ + + tAVRC_SET_ADDR_PLAYER_CMD addr_player; /* SetAddrPlayer */ + tAVRC_SET_VOLUME_CMD volume; /* SetAbsVolume */ + tAVRC_SET_BR_PLAYER_CMD br_player; /* SetBrowsedPlayer */ + tAVRC_GET_ITEMS_CMD get_items; /* GetFolderItems */ + tAVRC_CHG_PATH_CMD chg_path; /* ChangePath */ + tAVRC_GET_ATTRS_CMD get_attrs; /* GetItemAttrs */ + tAVRC_SEARCH_CMD search; /* Search */ + tAVRC_PLAY_ITEM_CMD play_item; /* PlayItem */ + tAVRC_ADD_TO_PLAY_CMD add_to_play; /* AddToNowPlaying */ +} tAVRC_COMMAND; + +/* GetCapability */ +typedef struct +{ + UINT8 pdu; + tAVRC_STS status; + UINT8 opcode; /* Op Code (copied from avrc_cmd.opcode by AVRC_BldResponse user. invalid one to generate according to pdu) */ + UINT8 capability_id; + UINT8 count; + tAVRC_CAPS_PARAM param; +} tAVRC_GET_CAPS_RSP; + +/* ListPlayerAppAttr */ +typedef struct +{ + UINT8 pdu; + tAVRC_STS status; + UINT8 opcode; /* Op Code (copied from avrc_cmd.opcode by AVRC_BldResponse user. invalid one to generate according to pdu) */ + UINT8 num_attr; + UINT8 attrs[AVRC_MAX_APP_ATTR_SIZE]; +} tAVRC_LIST_APP_ATTR_RSP; + +/* ListPlayerAppValues */ +typedef struct +{ + UINT8 pdu; + tAVRC_STS status; + UINT8 opcode; /* Op Code (copied from avrc_cmd.opcode by AVRC_BldResponse user. invalid one to generate according to pdu) */ + UINT8 num_val; + UINT8 vals[AVRC_MAX_APP_ATTR_SIZE]; +} tAVRC_LIST_APP_VALUES_RSP; + +/* GetCurAppValue */ +typedef struct +{ + UINT8 pdu; + tAVRC_STS status; + UINT8 opcode; /* Op Code (copied from avrc_cmd.opcode by AVRC_BldResponse user. invalid one to generate according to pdu) */ + UINT8 num_val; + tAVRC_APP_SETTING *p_vals; +} tAVRC_GET_CUR_APP_VALUE_RSP; + +/* GetAppAttrTxt */ +typedef struct +{ + UINT8 pdu; + tAVRC_STS status; + UINT8 opcode; /* Op Code (copied from avrc_cmd.opcode by AVRC_BldResponse user. invalid one to generate according to pdu) */ + UINT8 num_attr; + tAVRC_APP_SETTING_TEXT *p_attrs; +} tAVRC_GET_APP_ATTR_TXT_RSP; + +/* GetElemAttrs */ +typedef struct +{ + UINT8 pdu; + tAVRC_STS status; + UINT8 opcode; /* Op Code (copied from avrc_cmd.opcode by AVRC_BldResponse user. invalid one to generate according to pdu) */ + UINT8 num_attr; + tAVRC_ATTR_ENTRY *p_attrs; +} tAVRC_GET_ELEM_ATTRS_RSP; + +/* GetPlayStatus */ +typedef struct +{ + UINT8 pdu; + tAVRC_STS status; + UINT8 opcode; /* Op Code (copied from avrc_cmd.opcode by AVRC_BldResponse user. invalid one to generate according to pdu) */ + UINT32 song_len; + UINT32 song_pos; + UINT8 play_status; +} tAVRC_GET_PLAY_STATUS_RSP; + +/* notification event parameter for AddressedPlayer change */ +typedef struct +{ + UINT16 player_id; + UINT16 uid_counter; +} tAVRC_ADDR_PLAYER_PARAM; + +#ifndef AVRC_MAX_APP_SETTINGS +#define AVRC_MAX_APP_SETTINGS 8 +#endif + +/* notification event parameter for Player Application setting change */ +typedef struct +{ + UINT8 num_attr; + UINT8 attr_id[AVRC_MAX_APP_SETTINGS]; + UINT8 attr_value[AVRC_MAX_APP_SETTINGS]; +} tAVRC_PLAYER_APP_PARAM; + +typedef union +{ + tAVRC_PLAYSTATE play_status; + tAVRC_UID track; + UINT32 play_pos; + tAVRC_BATTERY_STATUS battery_status; + tAVRC_SYSTEMSTATE system_status; + tAVRC_PLAYER_APP_PARAM player_setting; + tAVRC_ADDR_PLAYER_PARAM addr_player; + UINT16 uid_counter; + UINT8 volume; +} tAVRC_NOTIF_RSP_PARAM; + +/* RegNotify */ +typedef struct +{ + UINT8 pdu; + tAVRC_STS status; + UINT8 opcode; /* Op Code (copied from avrc_cmd.opcode by AVRC_BldResponse user. invalid one to generate according to pdu) */ + UINT8 event_id; + tAVRC_NOTIF_RSP_PARAM param; +} tAVRC_REG_NOTIF_RSP; + +/* SetAbsVolume */ +typedef struct +{ + UINT8 pdu; + tAVRC_STS status; + UINT8 opcode; /* Op Code (copied from avrc_cmd.opcode by AVRC_BldResponse user. invalid one to generate according to pdu) */ + UINT8 volume; +} tAVRC_SET_VOLUME_RSP; + +/* SetBrowsedPlayer */ +typedef struct +{ + UINT8 pdu; + tAVRC_STS status; + UINT8 opcode; /* Op Code (copied from avrc_cmd.opcode by AVRC_BldResponse user. invalid one to generate according to pdu) */ + UINT16 uid_counter; + UINT32 num_items; + UINT16 charset_id; + UINT8 folder_depth; + tAVRC_NAME *p_folders; +} tAVRC_SET_BR_PLAYER_RSP; + +/* GetFolderItems */ +typedef struct +{ + UINT8 pdu; + tAVRC_STS status; + UINT8 opcode; /* Op Code (copied from avrc_cmd.opcode by AVRC_BldResponse user. invalid one to generate according to pdu) */ + UINT16 uid_counter; + UINT16 item_count; + tAVRC_ITEM *p_item_list; +} tAVRC_GET_ITEMS_RSP; + +/* ChangePath */ +typedef struct +{ + UINT8 pdu; + tAVRC_STS status; + UINT8 opcode; /* Op Code (copied from avrc_cmd.opcode by AVRC_BldResponse user. invalid one to generate according to pdu) */ + UINT32 num_items; +} tAVRC_CHG_PATH_RSP; + +/* GetItemAttrs */ +typedef struct +{ + UINT8 pdu; + tAVRC_STS status; + UINT8 opcode; /* Op Code (copied from avrc_cmd.opcode by AVRC_BldResponse user. invalid one to generate according to pdu) */ + UINT8 attr_count; + tAVRC_ATTR_ENTRY *p_attr_list; +} tAVRC_GET_ATTRS_RSP; + +/* Search */ +typedef struct +{ + UINT8 pdu; + tAVRC_STS status; + UINT8 opcode; /* Op Code (copied from avrc_cmd.opcode by AVRC_BldResponse user. invalid one to generate according to pdu) */ + UINT16 uid_counter; + UINT32 num_items; +} tAVRC_SEARCH_RSP; + + +typedef struct +{ + UINT8 pdu; + tAVRC_STS status; + UINT8 opcode; /* Op Code (copied from avrc_cmd.opcode by AVRC_BldResponse user. invalid one to generate according to pdu) */ +} tAVRC_RSP; + +typedef union +{ + UINT8 pdu; + tAVRC_RSP rsp; + tAVRC_GET_CAPS_RSP get_caps; /* GetCapability */ + tAVRC_LIST_APP_ATTR_RSP list_app_attr; /* ListPlayerAppAttr */ + tAVRC_LIST_APP_VALUES_RSP list_app_values; /* ListPlayerAppValues */ + tAVRC_GET_CUR_APP_VALUE_RSP get_cur_app_val; /* GetCurAppValue */ + tAVRC_RSP set_app_val; /* SetAppValue */ + tAVRC_GET_APP_ATTR_TXT_RSP get_app_attr_txt; /* GetAppAttrTxt */ + tAVRC_GET_APP_ATTR_TXT_RSP get_app_val_txt; /* GetAppValueTxt */ + tAVRC_RSP inform_charset; /* InformCharset */ + tAVRC_RSP inform_battery_status; /* InformBatteryStatus */ + tAVRC_GET_ELEM_ATTRS_RSP get_elem_attrs; /* GetElemAttrs */ + tAVRC_GET_PLAY_STATUS_RSP get_play_status; /* GetPlayStatus */ + tAVRC_REG_NOTIF_RSP reg_notif; /* RegNotify */ + tAVRC_RSP continu; /* Continue */ + tAVRC_RSP abort; /* Abort */ + + tAVRC_RSP addr_player; /* SetAddrPlayer */ + tAVRC_SET_VOLUME_RSP volume; /* SetAbsVolume */ + tAVRC_SET_BR_PLAYER_RSP br_player; /* SetBrowsedPlayer */ + tAVRC_GET_ITEMS_RSP get_items; /* GetFolderItems */ + tAVRC_CHG_PATH_RSP chg_path; /* ChangePath */ + tAVRC_GET_ATTRS_RSP get_attrs; /* GetItemAttrs */ + tAVRC_SEARCH_RSP search; /* Search */ + tAVRC_RSP play_item; /* PlayItem */ + tAVRC_RSP add_to_play; /* AddToNowPlaying */ +} tAVRC_RESPONSE; + + +#endif diff --git a/components/bt/bluedroid/stack/include/bnep_api.h b/components/bt/bluedroid/stack/include/bnep_api.h new file mode 100755 index 0000000000..3ca31d5d30 --- /dev/null +++ b/components/bt/bluedroid/stack/include/bnep_api.h @@ -0,0 +1,464 @@ +/****************************************************************************** + * + * Copyright (C) 2001-2012 Broadcom Corporation + * + * 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 interface file contains the interface to the Bluetooth Network + * Encapsilation Protocol (BNEP). + * + ******************************************************************************/ +#ifndef BNEP_API_H +#define BNEP_API_H + +#include "l2c_api.h" + +/***************************************************************************** +** Constants +*****************************************************************************/ + +/* Define the minimum offset needed in a GKI buffer for +** sending BNEP packets. Note, we are currently not sending +** extension headers, but may in the future, so allow +** space for them +*/ +#define BNEP_MINIMUM_OFFSET (15 + L2CAP_MIN_OFFSET) +#define BNEP_INVALID_HANDLE 0xFFFF + +/***************************************************************************** +** Type Definitions +*****************************************************************************/ + +/* Define the result codes from BNEP +*/ +enum +{ + BNEP_SUCCESS, /* Success */ + BNEP_CONN_DISCONNECTED, /* Connection terminated */ + BNEP_NO_RESOURCES, /* No resources */ + BNEP_MTU_EXCEDED, /* Attempt to write long data */ + BNEP_INVALID_OFFSET, /* Insufficient offset in GKI buffer */ + BNEP_CONN_FAILED, /* Connection failed */ + BNEP_CONN_FAILED_CFG, /* Connection failed cos of config */ + BNEP_CONN_FAILED_SRC_UUID, /* Connection failed wrong source UUID */ + BNEP_CONN_FAILED_DST_UUID, /* Connection failed wrong destination UUID */ + BNEP_CONN_FAILED_UUID_SIZE, /* Connection failed wrong size UUID */ + BNEP_Q_SIZE_EXCEEDED, /* Too many buffers to dest */ + BNEP_TOO_MANY_FILTERS, /* Too many local filters specified */ + BNEP_SET_FILTER_FAIL, /* Set Filter failed */ + BNEP_WRONG_HANDLE, /* Wrong handle for the connection */ + BNEP_WRONG_STATE, /* Connection is in wrong state */ + BNEP_SECURITY_FAIL, /* Failed because of security */ + BNEP_IGNORE_CMD, /* To ignore the rcvd command */ + BNEP_TX_FLOW_ON, /* tx data flow enabled */ + BNEP_TX_FLOW_OFF /* tx data flow disabled */ + +}; typedef UINT8 tBNEP_RESULT; + + +/*************************** +** Callback Functions +****************************/ + +/* Connection state change callback prototype. Parameters are +** Connection handle +** BD Address of remote +** Connection state change result +** BNEP_SUCCESS indicates connection is success +** All values are used to indicate the reason for failure +** Flag to indicate if it is just a role change +*/ +typedef void (tBNEP_CONN_STATE_CB) (UINT16 handle, + BD_ADDR rem_bda, + tBNEP_RESULT result, + BOOLEAN is_role_change); + + + + +/* Connection indication callback prototype. Parameters are +** BD Address of remote, remote UUID and local UUID +** and flag to indicate role change and handle to the connection +** When BNEP calls this function profile should +** use BNEP_ConnectResp call to accept or reject the request +*/ +typedef void (tBNEP_CONNECT_IND_CB) (UINT16 handle, + BD_ADDR bd_addr, + tBT_UUID *remote_uuid, + tBT_UUID *local_uuid, + BOOLEAN is_role_change); + + + +/* Data buffer received indication callback prototype. Parameters are +** Handle to the connection +** Source BD/Ethernet Address +** Dest BD/Ethernet address +** Protocol +** Pointer to the buffer +** Flag to indicate whether extension headers to be forwarded are present +*/ +typedef void (tBNEP_DATA_BUF_CB) (UINT16 handle, + UINT8 *src, + UINT8 *dst, + UINT16 protocol, + BT_HDR *p_buf, + BOOLEAN fw_ext_present); + + +/* Data received indication callback prototype. Parameters are +** Handle to the connection +** Source BD/Ethernet Address +** Dest BD/Ethernet address +** Protocol +** Pointer to the beginning of the data +** Length of data +** Flag to indicate whether extension headers to be forwarded are present +*/ +typedef void (tBNEP_DATA_IND_CB) (UINT16 handle, + UINT8 *src, + UINT8 *dst, + UINT16 protocol, + UINT8 *p_data, + UINT16 len, + BOOLEAN fw_ext_present); + +/* Flow control callback for TX data. Parameters are +** Handle to the connection +** Event flow status +*/ +typedef void (tBNEP_TX_DATA_FLOW_CB) (UINT16 handle, + tBNEP_RESULT event); + +/* Filters received indication callback prototype. Parameters are +** Handle to the connection +** TRUE if the cb is called for indication +** Ignore this if it is indication, otherwise it is the result +** for the filter set operation performed by the local +** device +** Number of protocol filters present +** Pointer to the filters start. Filters are present in pairs +** of start of the range and end of the range. +** They will be present in big endian order. First +** two bytes will be starting of the first range and +** next two bytes will be ending of the range. +*/ +typedef void (tBNEP_FILTER_IND_CB) (UINT16 handle, + BOOLEAN indication, + tBNEP_RESULT result, + UINT16 num_filters, + UINT8 *p_filters); + + + +/* Multicast Filters received indication callback prototype. Parameters are +** Handle to the connection +** TRUE if the cb is called for indication +** Ignore this if it is indication, otherwise it is the result +** for the filter set operation performed by the local +** device +** Number of multicast filters present +** Pointer to the filters start. Filters are present in pairs +** of start of the range and end of the range. +** First six bytes will be starting of the first range and +** next six bytes will be ending of the range. +*/ +typedef void (tBNEP_MFILTER_IND_CB) (UINT16 handle, + BOOLEAN indication, + tBNEP_RESULT result, + UINT16 num_mfilters, + UINT8 *p_mfilters); + +/* This is the structure used by profile to register with BNEP */ +typedef struct +{ + tBNEP_CONNECT_IND_CB *p_conn_ind_cb; /* To indicate the conn request */ + tBNEP_CONN_STATE_CB *p_conn_state_cb; /* To indicate conn state change */ + tBNEP_DATA_IND_CB *p_data_ind_cb; /* To pass the data received */ + tBNEP_DATA_BUF_CB *p_data_buf_cb; /* To pass the data buffer received */ + tBNEP_TX_DATA_FLOW_CB *p_tx_data_flow_cb; /* data flow callback */ + tBNEP_FILTER_IND_CB *p_filter_ind_cb; /* To indicate that peer set protocol filters */ + tBNEP_MFILTER_IND_CB *p_mfilter_ind_cb; /* To indicate that peer set mcast filters */ + +} tBNEP_REGISTER; + + + +/* This is the structure used by profile to get the status of BNEP */ +typedef struct +{ +#define BNEP_STATUS_FAILE 0 +#define BNEP_STATUS_CONNECTED 1 + UINT8 con_status; + + UINT16 l2cap_cid; + BD_ADDR rem_bda; + UINT16 rem_mtu_size; + UINT16 xmit_q_depth; + + UINT16 sent_num_filters; + UINT16 sent_mcast_filters; + UINT16 rcvd_num_filters; + UINT16 rcvd_mcast_filters; + tBT_UUID src_uuid; + tBT_UUID dst_uuid; + +} tBNEP_STATUS; + + + +/***************************************************************************** +** External Function Declarations +*****************************************************************************/ +#ifdef __cplusplus +extern "C" { +#endif + +/******************************************************************************* +** +** Function BNEP_Register +** +** Description This function is called by the upper layer to register +** its callbacks with BNEP +** +** Parameters: p_reg_info - contains all callback function pointers +** +** +** Returns BNEP_SUCCESS if registered successfully +** BNEP_FAILURE if connection state callback is missing +** +*******************************************************************************/ +extern tBNEP_RESULT BNEP_Register (tBNEP_REGISTER *p_reg_info); + +/******************************************************************************* +** +** Function BNEP_Deregister +** +** Description This function is called by the upper layer to de-register +** its callbacks. +** +** Parameters: void +** +** +** Returns void +** +*******************************************************************************/ +extern void BNEP_Deregister (void); + + +/******************************************************************************* +** +** Function BNEP_Connect +** +** Description This function creates a BNEP connection to a remote +** device. +** +** Parameters: p_rem_addr - BD_ADDR of the peer +** src_uuid - source uuid for the connection +** dst_uuid - destination uuid for the connection +** p_handle - pointer to return the handle for the connection +** +** Returns BNEP_SUCCESS if connection started +** BNEP_NO_RESOURCES if no resources +** +*******************************************************************************/ +extern tBNEP_RESULT BNEP_Connect (BD_ADDR p_rem_bda, + tBT_UUID *src_uuid, + tBT_UUID *dst_uuid, + UINT16 *p_handle); + +/******************************************************************************* +** +** Function BNEP_ConnectResp +** +** Description This function is called in responce to connection indication +** +** +** Parameters: handle - handle given in the connection indication +** resp - responce for the connection indication +** +** Returns BNEP_SUCCESS if connection started +** BNEP_WRONG_HANDLE if the connection is not found +** BNEP_WRONG_STATE if the responce is not expected +** +*******************************************************************************/ +extern tBNEP_RESULT BNEP_ConnectResp (UINT16 handle, tBNEP_RESULT resp); + +/******************************************************************************* +** +** Function BNEP_Disconnect +** +** Description This function is called to close the specified connection. +** +** Parameters: handle - handle of the connection +** +** Returns BNEP_SUCCESS if connection is disconnected +** BNEP_WRONG_HANDLE if no connection is not found +** +*******************************************************************************/ +extern tBNEP_RESULT BNEP_Disconnect (UINT16 handle); + +/******************************************************************************* +** +** Function BNEP_WriteBuf +** +** Description This function sends data in a GKI buffer on BNEP connection +** +** Parameters: handle - handle of the connection to write +** p_dest_addr - BD_ADDR/Ethernet addr of the destination +** p_buf - pointer to address of buffer with data +** protocol - protocol type of the packet +** p_src_addr - (optional) BD_ADDR/ethernet address of the source +** (should be NULL if it is local BD Addr) +** fw_ext_present - forwarded extensions present +** +** Returns: BNEP_WRONG_HANDLE - if passed handle is not valid +** BNEP_MTU_EXCEDED - If the data length is greater than MTU +** BNEP_IGNORE_CMD - If the packet is filtered out +** BNEP_Q_SIZE_EXCEEDED - If the Tx Q is full +** BNEP_SUCCESS - If written successfully +** +*******************************************************************************/ +extern tBNEP_RESULT BNEP_WriteBuf (UINT16 handle, + UINT8 *p_dest_addr, + BT_HDR *p_buf, + UINT16 protocol, + UINT8 *p_src_addr, + BOOLEAN fw_ext_present); + +/******************************************************************************* +** +** Function BNEP_Write +** +** Description This function sends data over a BNEP connection +** +** Parameters: handle - handle of the connection to write +** p_dest_addr - BD_ADDR/Ethernet addr of the destination +** p_data - pointer to data start +** protocol - protocol type of the packet +** p_src_addr - (optional) BD_ADDR/ethernet address of the source +** (should be NULL if it is local BD Addr) +** fw_ext_present - forwarded extensions present +** +** Returns: BNEP_WRONG_HANDLE - if passed handle is not valid +** BNEP_MTU_EXCEDED - If the data length is greater than MTU +** BNEP_IGNORE_CMD - If the packet is filtered out +** BNEP_Q_SIZE_EXCEEDED - If the Tx Q is full +** BNEP_NO_RESOURCES - If not able to allocate a buffer +** BNEP_SUCCESS - If written successfully +** +*******************************************************************************/ +extern tBNEP_RESULT BNEP_Write (UINT16 handle, + UINT8 *p_dest_addr, + UINT8 *p_data, + UINT16 len, + UINT16 protocol, + UINT8 *p_src_addr, + BOOLEAN fw_ext_present); + +/******************************************************************************* +** +** Function BNEP_SetProtocolFilters +** +** Description This function sets the protocol filters on peer device +** +** Parameters: handle - Handle for the connection +** num_filters - total number of filter ranges +** p_start_array - Array of beginings of all protocol ranges +** p_end_array - Array of ends of all protocol ranges +** +** Returns BNEP_WRONG_HANDLE - if the connection handle is not valid +** BNEP_SET_FILTER_FAIL - if the connection is in wrong state +** BNEP_TOO_MANY_FILTERS - if too many filters +** BNEP_SUCCESS - if request sent successfully +** +*******************************************************************************/ +extern tBNEP_RESULT BNEP_SetProtocolFilters (UINT16 handle, + UINT16 num_filters, + UINT16 *p_start_array, + UINT16 *p_end_array); + +/******************************************************************************* +** +** Function BNEP_SetMulticastFilters +** +** Description This function sets the filters for multicast addresses for BNEP. +** +** Parameters: handle - Handle for the connection +** num_filters - total number of filter ranges +** p_start_array - Pointer to sequence of beginings of all +** multicast address ranges +** p_end_array - Pointer to sequence of ends of all +** multicast address ranges +** +** Returns BNEP_WRONG_HANDLE - if the connection handle is not valid +** BNEP_SET_FILTER_FAIL - if the connection is in wrong state +** BNEP_TOO_MANY_FILTERS - if too many filters +** BNEP_SUCCESS - if request sent successfully +** +*******************************************************************************/ +extern tBNEP_RESULT BNEP_SetMulticastFilters (UINT16 handle, + UINT16 num_filters, + UINT8 *p_start_array, + UINT8 *p_end_array); + +/******************************************************************************* +** +** Function BNEP_SetTraceLevel +** +** Description This function sets the trace level for BNEP. If called with +** a value of 0xFF, it simply reads the current trace level. +** +** Returns the new (current) trace level +** +*******************************************************************************/ +extern UINT8 BNEP_SetTraceLevel (UINT8 new_level); + +/******************************************************************************* +** +** Function BNEP_Init +** +** Description This function initializes the BNEP unit. It should be called +** before accessing any other APIs to initialize the control block +** +** Returns void +** +*******************************************************************************/ +extern void BNEP_Init (void); + +/******************************************************************************* +** +** Function BNEP_GetStatus +** +** Description This function gets the status information for BNEP connection +** +** Returns BNEP_SUCCESS - if the status is available +** BNEP_NO_RESOURCES - if no structure is passed for output +** BNEP_WRONG_HANDLE - if the handle is invalid +** BNEP_WRONG_STATE - if not in connected state +** +*******************************************************************************/ +extern tBNEP_RESULT BNEP_GetStatus (UINT16 handle, tBNEP_STATUS *p_status); + + + +#ifdef __cplusplus +} +#endif + + +#endif diff --git a/components/bt/bluedroid/stack/include/bnep_int.h b/components/bt/bluedroid/stack/include/bnep_int.h new file mode 100755 index 0000000000..5322e5039f --- /dev/null +++ b/components/bt/bluedroid/stack/include/bnep_int.h @@ -0,0 +1,250 @@ +/****************************************************************************** + * + * Copyright (C) 2001-2012 Broadcom Corporation + * + * 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 internally used BNEP definitions + * + ******************************************************************************/ + +#ifndef BNEP_INT_H +#define BNEP_INT_H + +#include "bt_target.h" +#include "gki.h" +#include "bnep_api.h" +#include "btm_int.h" +#include "btu.h" + + +/* BNEP frame types +*/ +#define BNEP_FRAME_GENERAL_ETHERNET 0x00 +#define BNEP_FRAME_CONTROL 0x01 +#define BNEP_FRAME_COMPRESSED_ETHERNET 0x02 +#define BNEP_FRAME_COMPRESSED_ETHERNET_SRC_ONLY 0x03 +#define BNEP_FRAME_COMPRESSED_ETHERNET_DEST_ONLY 0x04 + + +/* BNEP filter control message types +*/ +#define BNEP_CONTROL_COMMAND_NOT_UNDERSTOOD 0x00 +#define BNEP_SETUP_CONNECTION_REQUEST_MSG 0x01 +#define BNEP_SETUP_CONNECTION_RESPONSE_MSG 0x02 +#define BNEP_FILTER_NET_TYPE_SET_MSG 0x03 +#define BNEP_FILTER_NET_TYPE_RESPONSE_MSG 0x04 +#define BNEP_FILTER_MULTI_ADDR_SET_MSG 0x05 +#define BNEP_FILTER_MULTI_ADDR_RESPONSE_MSG 0x06 + + +/* BNEP header extension types +*/ +#define BNEP_EXTENSION_FILTER_CONTROL 0x00 + + +/* BNEP Setup Connection response codes +*/ +#define BNEP_SETUP_CONN_OK 0x0000 +#define BNEP_SETUP_INVALID_DEST_UUID 0x0001 +#define BNEP_SETUP_INVALID_SRC_UUID 0x0002 +#define BNEP_SETUP_INVALID_UUID_SIZE 0x0003 +#define BNEP_SETUP_CONN_NOT_ALLOWED 0x0004 + + +/* BNEP filter control response codes +*/ +#define BNEP_FILTER_CRL_OK 0x0000 +#define BNEP_FILTER_CRL_UNSUPPORTED 0x0001 +#define BNEP_FILTER_CRL_BAD_RANGE 0x0002 +#define BNEP_FILTER_CRL_MAX_REACHED 0x0003 +#define BNEP_FILTER_CRL_SECURITY_ERR 0x0004 + + +/* 802.1p protocol packet will have actual protocol field in side the payload */ +#define BNEP_802_1_P_PROTOCOL 0x8100 + +/* Timeout definitions. +*/ +#define BNEP_CONN_TIMEOUT 20 /* Connection related timeout */ +#define BNEP_HOST_TIMEOUT 200 /* host responce timeout */ +#define BNEP_FILTER_SET_TIMEOUT 10 + +/* Define the Out-Flow default values. */ +#define BNEP_OFLOW_QOS_FLAG 0 +#define BNEP_OFLOW_SERV_TYPE 0 +#define BNEP_OFLOW_TOKEN_RATE 0 +#define BNEP_OFLOW_TOKEN_BUCKET_SIZE 0 +#define BNEP_OFLOW_PEAK_BANDWIDTH 0 +#define BNEP_OFLOW_LATENCY 0 +#define BNEP_OFLOW_DELAY_VARIATION 0 + +/* Define the In-Flow default values. */ +#define BNEP_IFLOW_QOS_FLAG 0 +#define BNEP_IFLOW_SERV_TYPE 0 +#define BNEP_IFLOW_TOKEN_RATE 0 +#define BNEP_IFLOW_TOKEN_BUCKET_SIZE 0 +#define BNEP_IFLOW_PEAK_BANDWIDTH 0 +#define BNEP_IFLOW_LATENCY 0 +#define BNEP_IFLOW_DELAY_VARIATION 0 + +#define BNEP_FLUSH_TO 0xFFFF + +#define BNEP_MAX_RETRANSMITS 3 + +/* Define the BNEP Connection Control Block +*/ +typedef struct +{ +#define BNEP_STATE_IDLE 0 +#define BNEP_STATE_CONN_START 1 +#define BNEP_STATE_CFG_SETUP 2 +#define BNEP_STATE_CONN_SETUP 3 +#define BNEP_STATE_SEC_CHECKING 4 +#define BNEP_STATE_SETUP_RCVD 5 +#define BNEP_STATE_CONNECTED 6 + UINT8 con_state; + +#define BNEP_FLAGS_IS_ORIG 0x01 +#define BNEP_FLAGS_HIS_CFG_DONE 0x02 +#define BNEP_FLAGS_MY_CFG_DONE 0x04 +#define BNEP_FLAGS_L2CAP_CONGESTED 0x08 +#define BNEP_FLAGS_FILTER_RESP_PEND 0x10 +#define BNEP_FLAGS_MULTI_RESP_PEND 0x20 +#define BNEP_FLAGS_SETUP_RCVD 0x40 +#define BNEP_FLAGS_CONN_COMPLETED 0x80 + UINT8 con_flags; + BT_HDR *p_pending_data; + + UINT16 l2cap_cid; + BD_ADDR rem_bda; + UINT16 rem_mtu_size; + TIMER_LIST_ENT conn_tle; + BUFFER_Q xmit_q; + + UINT16 sent_num_filters; + UINT16 sent_prot_filter_start[BNEP_MAX_PROT_FILTERS]; + UINT16 sent_prot_filter_end[BNEP_MAX_PROT_FILTERS]; + + UINT16 sent_mcast_filters; + BD_ADDR sent_mcast_filter_start[BNEP_MAX_MULTI_FILTERS]; + BD_ADDR sent_mcast_filter_end[BNEP_MAX_MULTI_FILTERS]; + + UINT16 rcvd_num_filters; + UINT16 rcvd_prot_filter_start[BNEP_MAX_PROT_FILTERS]; + UINT16 rcvd_prot_filter_end[BNEP_MAX_PROT_FILTERS]; + + UINT16 rcvd_mcast_filters; + BD_ADDR rcvd_mcast_filter_start[BNEP_MAX_MULTI_FILTERS]; + BD_ADDR rcvd_mcast_filter_end[BNEP_MAX_MULTI_FILTERS]; + + UINT16 bad_pkts_rcvd; + UINT8 re_transmits; + UINT16 handle; + tBT_UUID prv_src_uuid; + tBT_UUID prv_dst_uuid; + tBT_UUID src_uuid; + tBT_UUID dst_uuid; + +} tBNEP_CONN; + + +/* The main BNEP control block +*/ +typedef struct +{ + tL2CAP_CFG_INFO l2cap_my_cfg; /* My L2CAP config */ + tBNEP_CONN bcb[BNEP_MAX_CONNECTIONS]; + + tBNEP_CONNECT_IND_CB *p_conn_ind_cb; + tBNEP_CONN_STATE_CB *p_conn_state_cb; + tBNEP_DATA_IND_CB *p_data_ind_cb; + tBNEP_DATA_BUF_CB *p_data_buf_cb; + tBNEP_FILTER_IND_CB *p_filter_ind_cb; + tBNEP_MFILTER_IND_CB *p_mfilter_ind_cb; + tBNEP_TX_DATA_FLOW_CB *p_tx_data_flow_cb; + + tL2CAP_APPL_INFO reg_info; + + TIMER_LIST_ENT bnep_tle; + BOOLEAN profile_registered; /* TRUE when we got our BD addr */ + UINT8 trace_level; + +} tBNEP_CB; + +#ifdef __cplusplus +extern "C" { +#endif + +/* Global BNEP data +*/ +#if BNEP_DYNAMIC_MEMORY == FALSE +extern tBNEP_CB bnep_cb; +#else +extern tBNEP_CB *bnep_cb_ptr; +#define bnep_cb (*bnep_cb_ptr) +#endif + +/* Functions provided by bnep_main.c +*/ +extern tBNEP_RESULT bnep_register_with_l2cap (void); +extern void bnep_disconnect (tBNEP_CONN *p_bcb, UINT16 reason); +extern tBNEP_CONN *bnep_conn_originate (UINT8 *p_bd_addr); +extern void bnep_process_timeout (TIMER_LIST_ENT *p_tle); +extern void bnep_connected (tBNEP_CONN *p_bcb); + + +/* Functions provided by bnep_utils.c +*/ +extern tBNEP_CONN *bnepu_find_bcb_by_cid (UINT16 cid); +extern tBNEP_CONN *bnepu_find_bcb_by_bd_addr (UINT8 *p_bda); +extern tBNEP_CONN *bnepu_allocate_bcb (BD_ADDR p_rem_bda); +extern void bnepu_release_bcb (tBNEP_CONN *p_bcb); +extern void bnepu_send_peer_our_filters (tBNEP_CONN *p_bcb); +extern void bnepu_send_peer_our_multi_filters (tBNEP_CONN *p_bcb); +extern BOOLEAN bnepu_does_dest_support_prot (tBNEP_CONN *p_bcb, UINT16 protocol); +extern void bnepu_build_bnep_hdr (tBNEP_CONN *p_bcb, BT_HDR *p_buf, UINT16 protocol, + UINT8 *p_src_addr, UINT8 *p_dest_addr, BOOLEAN ext_bit); +extern void test_bnepu_build_bnep_hdr (tBNEP_CONN *p_bcb, BT_HDR *p_buf, UINT16 protocol, + UINT8 *p_src_addr, UINT8 *p_dest_addr, UINT8 type); + +extern tBNEP_CONN *bnepu_get_route_to_dest (UINT8 *p_bda); +extern void bnepu_check_send_packet (tBNEP_CONN *p_bcb, BT_HDR *p_buf); +extern void bnep_send_command_not_understood (tBNEP_CONN *p_bcb, UINT8 cmd_code); +extern void bnepu_process_peer_filter_set (tBNEP_CONN *p_bcb, UINT8 *p_filters, UINT16 len); +extern void bnepu_process_peer_filter_rsp (tBNEP_CONN *p_bcb, UINT8 *p_data); +extern void bnepu_process_multicast_filter_rsp (tBNEP_CONN *p_bcb, UINT8 *p_data); +extern void bnep_send_conn_req (tBNEP_CONN *p_bcb); +extern void bnep_send_conn_responce (tBNEP_CONN *p_bcb, UINT16 resp_code); +extern void bnep_process_setup_conn_req (tBNEP_CONN *p_bcb, UINT8 *p_setup, UINT8 len); +extern void bnep_process_setup_conn_responce (tBNEP_CONN *p_bcb, UINT8 *p_setup); +extern UINT8 *bnep_process_control_packet (tBNEP_CONN *p_bcb, UINT8 *p, UINT16 *len, + BOOLEAN is_ext); +extern void bnep_sec_check_complete (BD_ADDR bd_addr, tBT_TRANSPORT trasnport, + void *p_ref_data, UINT8 result); +extern tBNEP_RESULT bnep_is_packet_allowed (tBNEP_CONN *p_bcb, BD_ADDR p_dest_addr, UINT16 protocol, + BOOLEAN fw_ext_present, UINT8 *p_data); +extern UINT32 bnep_get_uuid32 (tBT_UUID *src_uuid); + + + +#ifdef __cplusplus +} +#endif + + +#endif diff --git a/components/bt/bluedroid/stack/include/bt_types.h b/components/bt/bluedroid/stack/include/bt_types.h new file mode 100755 index 0000000000..b01e29db3c --- /dev/null +++ b/components/bt/bluedroid/stack/include/bt_types.h @@ -0,0 +1,797 @@ +/****************************************************************************** + * + * Copyright (C) 1999-2012 Broadcom Corporation + * + * 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. + * + ******************************************************************************/ + +#ifndef BT_TYPES_H +#define BT_TYPES_H + +#include +#include + +#ifndef FALSE +# define FALSE false +#endif + +#ifndef TRUE +# define TRUE true +#endif + +typedef uint8_t UINT8; +typedef uint16_t UINT16; +typedef uint32_t UINT32; +typedef uint64_t UINT64; + +typedef int8_t INT8; +typedef int16_t INT16; +typedef int32_t INT32; +typedef bool BOOLEAN; + +#define PACKED __packed +#define INLINE __inline + +#define BCM_STRCPY_S(x1,x2,x3) strcpy((x1),(x3)) +#define BCM_STRNCPY_S(x1,x2,x3,x4) strncpy((x1),(x3),(x4)) + +/* READ WELL !! +** +** This section defines global events. These are events that cross layers. +** Any event that passes between layers MUST be one of these events. Tasks +** can use their own events internally, but a FUNDAMENTAL design issue is +** that global events MUST be one of these events defined below. +** +** The convention used is the the event name contains the layer that the +** event is going to. +*/ +#define BT_EVT_MASK 0xFF00 +#define BT_SUB_EVT_MASK 0x00FF + /* To Bluetooth Upper Layers */ + /************************************/ +#define BT_EVT_TO_BTU_L2C_EVT 0x0900 /* L2CAP event */ +#define BT_EVT_TO_BTU_HCI_EVT 0x1000 /* HCI Event */ +#define BT_EVT_TO_BTU_HCI_BR_EDR_EVT (0x0000 | BT_EVT_TO_BTU_HCI_EVT) /* event from BR/EDR controller */ +#define BT_EVT_TO_BTU_HCI_AMP1_EVT (0x0001 | BT_EVT_TO_BTU_HCI_EVT) /* event from local AMP 1 controller */ +#define BT_EVT_TO_BTU_HCI_AMP2_EVT (0x0002 | BT_EVT_TO_BTU_HCI_EVT) /* event from local AMP 2 controller */ +#define BT_EVT_TO_BTU_HCI_AMP3_EVT (0x0003 | BT_EVT_TO_BTU_HCI_EVT) /* event from local AMP 3 controller */ + +#define BT_EVT_TO_BTU_HCI_ACL 0x1100 /* ACL Data from HCI */ +#define BT_EVT_TO_BTU_HCI_SCO 0x1200 /* SCO Data from HCI */ +#define BT_EVT_TO_BTU_HCIT_ERR 0x1300 /* HCI Transport Error */ + +#define BT_EVT_TO_BTU_SP_EVT 0x1400 /* Serial Port Event */ +#define BT_EVT_TO_BTU_SP_DATA 0x1500 /* Serial Port Data */ + +#define BT_EVT_TO_BTU_HCI_CMD 0x1600 /* HCI command from upper layer */ + + +#define BT_EVT_TO_BTU_L2C_SEG_XMIT 0x1900 /* L2CAP segment(s) transmitted */ + +#define BT_EVT_PROXY_INCOMING_MSG 0x1A00 /* BlueStackTester event: incoming message from target */ + +#define BT_EVT_BTSIM 0x1B00 /* Insight BTSIM event */ +#define BT_EVT_BTISE 0x1C00 /* Insight Script Engine event */ + + /* To LM */ + /************************************/ +#define BT_EVT_TO_LM_HCI_CMD 0x2000 /* HCI Command */ +#define BT_EVT_TO_LM_HCI_ACL 0x2100 /* HCI ACL Data */ +#define BT_EVT_TO_LM_HCI_SCO 0x2200 /* HCI SCO Data */ +#define BT_EVT_TO_LM_HCIT_ERR 0x2300 /* HCI Transport Error */ +#define BT_EVT_TO_LM_LC_EVT 0x2400 /* LC event */ +#define BT_EVT_TO_LM_LC_LMP 0x2500 /* LC Received LMP command frame */ +#define BT_EVT_TO_LM_LC_ACL 0x2600 /* LC Received ACL data */ +#define BT_EVT_TO_LM_LC_SCO 0x2700 /* LC Received SCO data (not used) */ +#define BT_EVT_TO_LM_LC_ACL_TX 0x2800 /* LMP data transmit complete */ +#define BT_EVT_TO_LM_LC_LMPC_TX 0x2900 /* LMP Command transmit complete */ +#define BT_EVT_TO_LM_LOCAL_ACL_LB 0x2a00 /* Data to be locally loopbacked */ +#define BT_EVT_TO_LM_HCI_ACL_ACK 0x2b00 /* HCI ACL Data ack (not used) */ +#define BT_EVT_TO_LM_DIAG 0x2c00 /* LM Diagnostics commands */ + + +#define BT_EVT_TO_BTM_CMDS 0x2f00 +#define BT_EVT_TO_BTM_PM_MDCHG_EVT (0x0001 | BT_EVT_TO_BTM_CMDS) + +#define BT_EVT_TO_TCS_CMDS 0x3000 + +#define BT_EVT_TO_CTP_CMDS 0x3300 + +/* ftp events */ +#define BT_EVT_TO_FTP_SRVR_CMDS 0x3600 +#define BT_EVT_TO_FTP_CLNT_CMDS 0x3700 + +#define BT_EVT_TO_BTU_SAP 0x3800 /* SIM Access Profile events */ + +/* opp events */ +#define BT_EVT_TO_OPP_SRVR_CMDS 0x3900 +#define BT_EVT_TO_OPP_CLNT_CMDS 0x3a00 + +/* gap events */ +#define BT_EVT_TO_GAP_MSG 0x3b00 + +/* for NFC */ + /************************************/ +#define BT_EVT_TO_NFC_NCI 0x4000 /* NCI Command, Notification or Data*/ +#define BT_EVT_TO_NFC_INIT 0x4100 /* Initialization message */ +#define BT_EVT_TO_NCI_LP 0x4200 /* Low power */ +#define BT_EVT_TO_NFC_ERR 0x4300 /* Error notification to NFC Task */ + +#define BT_EVT_TO_NFCCSIM_NCI 0x4a00 /* events to NFCC simulation (NCI packets) */ + +/* HCISU Events */ + +#define BT_EVT_HCISU 0x5000 + +// btla-specific ++ +#define BT_EVT_TO_HCISU_RECONFIG_EVT (0x0001 | BT_EVT_HCISU) +#define BT_EVT_TO_HCISU_UPDATE_BAUDRATE_EVT (0x0002 | BT_EVT_HCISU) +#define BT_EVT_TO_HCISU_LP_ENABLE_EVT (0x0003 | BT_EVT_HCISU) +#define BT_EVT_TO_HCISU_LP_DISABLE_EVT (0x0004 | BT_EVT_HCISU) +// btla-specific -- +#define BT_EVT_TO_HCISU_LP_APP_SLEEPING_EVT (0x0005 | BT_EVT_HCISU) +#define BT_EVT_TO_HCISU_LP_ALLOW_BT_SLEEP_EVT (0x0006 | BT_EVT_HCISU) +#define BT_EVT_TO_HCISU_LP_WAKEUP_HOST_EVT (0x0007 | BT_EVT_HCISU) +#define BT_EVT_TO_HCISU_LP_RCV_H4IBSS_EVT (0x0008 | BT_EVT_HCISU) +#define BT_EVT_TO_HCISU_H5_RESET_EVT (0x0009 | BT_EVT_HCISU) +#define BT_EVT_HCISU_START_QUICK_TIMER (0x000a | BT_EVT_HCISU) + +#define BT_EVT_DATA_TO_AMP_1 0x5100 +#define BT_EVT_DATA_TO_AMP_15 0x5f00 + +/* HSP Events */ + +#define BT_EVT_BTU_HSP2 0x6000 + +#define BT_EVT_TO_BTU_HSP2_EVT (0x0001 | BT_EVT_BTU_HSP2) + +/* BPP Events */ +#define BT_EVT_TO_BPP_PR_CMDS 0x6100 /* Printer Events */ +#define BT_EVT_TO_BPP_SND_CMDS 0x6200 /* BPP Sender Events */ + +/* BIP Events */ +#define BT_EVT_TO_BIP_CMDS 0x6300 + +/* HCRP Events */ + +#define BT_EVT_BTU_HCRP 0x7000 + +#define BT_EVT_TO_BTU_HCRP_EVT (0x0001 | BT_EVT_BTU_HCRP) +#define BT_EVT_TO_BTU_HCRPM_EVT (0x0002 | BT_EVT_BTU_HCRP) + + +#define BT_EVT_BTU_HFP 0x8000 +#define BT_EVT_TO_BTU_HFP_EVT (0x0001 | BT_EVT_BTU_HFP) + +#define BT_EVT_BTU_IPC_EVT 0x9000 +#define BT_EVT_BTU_IPC_LOGMSG_EVT (0x0000 | BT_EVT_BTU_IPC_EVT) +#define BT_EVT_BTU_IPC_ACL_EVT (0x0001 | BT_EVT_BTU_IPC_EVT) +#define BT_EVT_BTU_IPC_BTU_EVT (0x0002 | BT_EVT_BTU_IPC_EVT) +#define BT_EVT_BTU_IPC_L2C_EVT (0x0003 | BT_EVT_BTU_IPC_EVT) +#define BT_EVT_BTU_IPC_L2C_MSG_EVT (0x0004 | BT_EVT_BTU_IPC_EVT) +#define BT_EVT_BTU_IPC_BTM_EVT (0x0005 | BT_EVT_BTU_IPC_EVT) +#define BT_EVT_BTU_IPC_AVDT_EVT (0x0006 | BT_EVT_BTU_IPC_EVT) +#define BT_EVT_BTU_IPC_SLIP_EVT (0x0007 | BT_EVT_BTU_IPC_EVT) +#define BT_EVT_BTU_IPC_MGMT_EVT (0x0008 | BT_EVT_BTU_IPC_EVT) +#define BT_EVT_BTU_IPC_BTTRC_EVT (0x0009 | BT_EVT_BTU_IPC_EVT) +#define BT_EVT_BTU_IPC_BURST_EVT (0x000A | BT_EVT_BTU_IPC_EVT) + + +/* BTIF Events */ +#define BT_EVT_BTIF 0xA000 +#define BT_EVT_CONTEXT_SWITCH_EVT (0x0001 | BT_EVT_BTIF) + +/* Define the header of each buffer used in the Bluetooth stack. +*/ +typedef struct +{ + uint16_t event; + uint16_t len; + uint16_t offset; + uint16_t layer_specific; + uint8_t data[]; +} BT_HDR; + +#define BT_HDR_SIZE (sizeof (BT_HDR)) + +#define BT_PSM_SDP 0x0001 +#define BT_PSM_RFCOMM 0x0003 +#define BT_PSM_TCS 0x0005 +#define BT_PSM_CTP 0x0007 +#define BT_PSM_BNEP 0x000F +#define BT_PSM_HIDC 0x0011 +#define BT_PSM_HIDI 0x0013 +#define BT_PSM_UPNP 0x0015 +#define BT_PSM_AVCTP 0x0017 +#define BT_PSM_AVDTP 0x0019 +#define BT_PSM_AVCTP_13 0x001B /* Advanced Control - Browsing */ +#define BT_PSM_UDI_CP 0x001D /* Unrestricted Digital Information Profile C-Plane */ +#define BT_PSM_ATT 0x001F /* Attribute Protocol */ + + +/* These macros extract the HCI opcodes from a buffer +*/ +#define HCI_GET_CMD_HDR_OPCODE(p) (UINT16)((*((UINT8 *)((p) + 1) + p->offset) + \ + (*((UINT8 *)((p) + 1) + p->offset + 1) << 8))) +#define HCI_GET_CMD_HDR_PARAM_LEN(p) (UINT8) (*((UINT8 *)((p) + 1) + p->offset + 2)) + +#define HCI_GET_EVT_HDR_OPCODE(p) (UINT8)(*((UINT8 *)((p) + 1) + p->offset)) +#define HCI_GET_EVT_HDR_PARAM_LEN(p) (UINT8) (*((UINT8 *)((p) + 1) + p->offset + 1)) + + +/******************************************************************************** +** Macros to get and put bytes to and from a stream (Little Endian format). +*/ +#define UINT32_TO_STREAM(p, u32) {*(p)++ = (UINT8)(u32); *(p)++ = (UINT8)((u32) >> 8); *(p)++ = (UINT8)((u32) >> 16); *(p)++ = (UINT8)((u32) >> 24);} +#define UINT24_TO_STREAM(p, u24) {*(p)++ = (UINT8)(u24); *(p)++ = (UINT8)((u24) >> 8); *(p)++ = (UINT8)((u24) >> 16);} +#define UINT16_TO_STREAM(p, u16) {*(p)++ = (UINT8)(u16); *(p)++ = (UINT8)((u16) >> 8);} +#define UINT8_TO_STREAM(p, u8) {*(p)++ = (UINT8)(u8);} +#define INT8_TO_STREAM(p, u8) {*(p)++ = (INT8)(u8);} +#define ARRAY32_TO_STREAM(p, a) {register int ijk; for (ijk = 0; ijk < 32; ijk++) *(p)++ = (UINT8) a[31 - ijk];} +#define ARRAY16_TO_STREAM(p, a) {register int ijk; for (ijk = 0; ijk < 16; ijk++) *(p)++ = (UINT8) a[15 - ijk];} +#define ARRAY8_TO_STREAM(p, a) {register int ijk; for (ijk = 0; ijk < 8; ijk++) *(p)++ = (UINT8) a[7 - ijk];} +#define BDADDR_TO_STREAM(p, a) {register int ijk; for (ijk = 0; ijk < BD_ADDR_LEN; ijk++) *(p)++ = (UINT8) a[BD_ADDR_LEN - 1 - ijk];} +#define LAP_TO_STREAM(p, a) {register int ijk; for (ijk = 0; ijk < LAP_LEN; ijk++) *(p)++ = (UINT8) a[LAP_LEN - 1 - ijk];} +#define DEVCLASS_TO_STREAM(p, a) {register int ijk; for (ijk = 0; ijk < DEV_CLASS_LEN;ijk++) *(p)++ = (UINT8) a[DEV_CLASS_LEN - 1 - ijk];} +#define ARRAY_TO_STREAM(p, a, len) {register int ijk; for (ijk = 0; ijk < len; ijk++) *(p)++ = (UINT8) a[ijk];} +#define REVERSE_ARRAY_TO_STREAM(p, a, len) {register int ijk; for (ijk = 0; ijk < len; ijk++) *(p)++ = (UINT8) a[len - 1 - ijk];} + +#define STREAM_TO_UINT8(u8, p) {u8 = (UINT8)(*(p)); (p) += 1;} +#define STREAM_TO_UINT16(u16, p) {u16 = ((UINT16)(*(p)) + (((UINT16)(*((p) + 1))) << 8)); (p) += 2;} +#define STREAM_TO_UINT24(u32, p) {u32 = (((UINT32)(*(p))) + ((((UINT32)(*((p) + 1)))) << 8) + ((((UINT32)(*((p) + 2)))) << 16) ); (p) += 3;} +#define STREAM_TO_UINT32(u32, p) {u32 = (((UINT32)(*(p))) + ((((UINT32)(*((p) + 1)))) << 8) + ((((UINT32)(*((p) + 2)))) << 16) + ((((UINT32)(*((p) + 3)))) << 24)); (p) += 4;} +#define STREAM_TO_BDADDR(a, p) {register int ijk; register UINT8 *pbda = (UINT8 *)a + BD_ADDR_LEN - 1; for (ijk = 0; ijk < BD_ADDR_LEN; ijk++) *pbda-- = *p++;} +#define STREAM_TO_ARRAY32(a, p) {register int ijk; register UINT8 *_pa = (UINT8 *)a + 31; for (ijk = 0; ijk < 32; ijk++) *_pa-- = *p++;} +#define STREAM_TO_ARRAY16(a, p) {register int ijk; register UINT8 *_pa = (UINT8 *)a + 15; for (ijk = 0; ijk < 16; ijk++) *_pa-- = *p++;} +#define STREAM_TO_ARRAY8(a, p) {register int ijk; register UINT8 *_pa = (UINT8 *)a + 7; for (ijk = 0; ijk < 8; ijk++) *_pa-- = *p++;} +#define STREAM_TO_DEVCLASS(a, p) {register int ijk; register UINT8 *_pa = (UINT8 *)a + DEV_CLASS_LEN - 1; for (ijk = 0; ijk < DEV_CLASS_LEN; ijk++) *_pa-- = *p++;} +#define STREAM_TO_LAP(a, p) {register int ijk; register UINT8 *plap = (UINT8 *)a + LAP_LEN - 1; for (ijk = 0; ijk < LAP_LEN; ijk++) *plap-- = *p++;} +#define STREAM_TO_ARRAY(a, p, len) {register int ijk; for (ijk = 0; ijk < len; ijk++) ((UINT8 *) a)[ijk] = *p++;} +#define REVERSE_STREAM_TO_ARRAY(a, p, len) {register int ijk; register UINT8 *_pa = (UINT8 *)a + len - 1; for (ijk = 0; ijk < len; ijk++) *_pa-- = *p++;} + +#define STREAM_SKIP_UINT8(p) do { (p) += 1; } while (0) +#define STREAM_SKIP_UINT16(p) do { (p) += 2; } while (0) + +/******************************************************************************** +** Macros to get and put bytes to and from a field (Little Endian format). +** These are the same as to stream, except the pointer is not incremented. +*/ +#define UINT32_TO_FIELD(p, u32) {*(UINT8 *)(p) = (UINT8)(u32); *((UINT8 *)(p)+1) = (UINT8)((u32) >> 8); *((UINT8 *)(p)+2) = (UINT8)((u32) >> 16); *((UINT8 *)(p)+3) = (UINT8)((u32) >> 24);} +#define UINT24_TO_FIELD(p, u24) {*(UINT8 *)(p) = (UINT8)(u24); *((UINT8 *)(p)+1) = (UINT8)((u24) >> 8); *((UINT8 *)(p)+2) = (UINT8)((u24) >> 16);} +#define UINT16_TO_FIELD(p, u16) {*(UINT8 *)(p) = (UINT8)(u16); *((UINT8 *)(p)+1) = (UINT8)((u16) >> 8);} +#define UINT8_TO_FIELD(p, u8) {*(UINT8 *)(p) = (UINT8)(u8);} + + +/******************************************************************************** +** Macros to get and put bytes to and from a stream (Big Endian format) +*/ +#define UINT32_TO_BE_STREAM(p, u32) {*(p)++ = (UINT8)((u32) >> 24); *(p)++ = (UINT8)((u32) >> 16); *(p)++ = (UINT8)((u32) >> 8); *(p)++ = (UINT8)(u32); } +#define UINT24_TO_BE_STREAM(p, u24) {*(p)++ = (UINT8)((u24) >> 16); *(p)++ = (UINT8)((u24) >> 8); *(p)++ = (UINT8)(u24);} +#define UINT16_TO_BE_STREAM(p, u16) {*(p)++ = (UINT8)((u16) >> 8); *(p)++ = (UINT8)(u16);} +#define UINT8_TO_BE_STREAM(p, u8) {*(p)++ = (UINT8)(u8);} +#define ARRAY_TO_BE_STREAM(p, a, len) {register int ijk; for (ijk = 0; ijk < len; ijk++) *(p)++ = (UINT8) a[ijk];} +#define ARRAY_TO_BE_STREAM_REVERSE(p, a, len) {register int ijk; for (ijk = 0; ijk < len; ijk++) *(p)++ = (UINT8) a[len - ijk - 1];} + +#define BE_STREAM_TO_UINT8(u8, p) {u8 = (UINT8)(*(p)); (p) += 1;} +#define BE_STREAM_TO_UINT16(u16, p) {u16 = (UINT16)(((UINT16)(*(p)) << 8) + (UINT16)(*((p) + 1))); (p) += 2;} +#define BE_STREAM_TO_UINT24(u32, p) {u32 = (((UINT32)(*((p) + 2))) + ((UINT32)(*((p) + 1)) << 8) + ((UINT32)(*(p)) << 16)); (p) += 3;} +#define BE_STREAM_TO_UINT32(u32, p) {u32 = ((UINT32)(*((p) + 3)) + ((UINT32)(*((p) + 2)) << 8) + ((UINT32)(*((p) + 1)) << 16) + ((UINT32)(*(p)) << 24)); (p) += 4;} +#define BE_STREAM_TO_ARRAY(p, a, len) {register int ijk; for (ijk = 0; ijk < len; ijk++) ((UINT8 *) a)[ijk] = *p++;} + + +/******************************************************************************** +** Macros to get and put bytes to and from a field (Big Endian format). +** These are the same as to stream, except the pointer is not incremented. +*/ +#define UINT32_TO_BE_FIELD(p, u32) {*(UINT8 *)(p) = (UINT8)((u32) >> 24); *((UINT8 *)(p)+1) = (UINT8)((u32) >> 16); *((UINT8 *)(p)+2) = (UINT8)((u32) >> 8); *((UINT8 *)(p)+3) = (UINT8)(u32); } +#define UINT24_TO_BE_FIELD(p, u24) {*(UINT8 *)(p) = (UINT8)((u24) >> 16); *((UINT8 *)(p)+1) = (UINT8)((u24) >> 8); *((UINT8 *)(p)+2) = (UINT8)(u24);} +#define UINT16_TO_BE_FIELD(p, u16) {*(UINT8 *)(p) = (UINT8)((u16) >> 8); *((UINT8 *)(p)+1) = (UINT8)(u16);} +#define UINT8_TO_BE_FIELD(p, u8) {*(UINT8 *)(p) = (UINT8)(u8);} + + +/* Common Bluetooth field definitions */ +#define BD_ADDR_LEN 6 /* Device address length */ +typedef UINT8 BD_ADDR[BD_ADDR_LEN]; /* Device address */ +typedef UINT8 *BD_ADDR_PTR; /* Pointer to Device Address */ + +#define AMP_KEY_TYPE_GAMP 0 +#define AMP_KEY_TYPE_WIFI 1 +#define AMP_KEY_TYPE_UWB 2 +typedef UINT8 tAMP_KEY_TYPE; + +#define BT_OCTET8_LEN 8 +typedef UINT8 BT_OCTET8[BT_OCTET8_LEN]; /* octet array: size 16 */ + +#define LINK_KEY_LEN 16 +typedef UINT8 LINK_KEY[LINK_KEY_LEN]; /* Link Key */ + +#define AMP_LINK_KEY_LEN 32 +typedef UINT8 AMP_LINK_KEY[AMP_LINK_KEY_LEN]; /* Dedicated AMP and GAMP Link Keys */ + +#define BT_OCTET16_LEN 16 +typedef UINT8 BT_OCTET16[BT_OCTET16_LEN]; /* octet array: size 16 */ + +#define PIN_CODE_LEN 16 +typedef UINT8 PIN_CODE[PIN_CODE_LEN]; /* Pin Code (upto 128 bits) MSB is 0 */ +typedef UINT8 *PIN_CODE_PTR; /* Pointer to Pin Code */ + +#define BT_OCTET32_LEN 32 +typedef UINT8 BT_OCTET32[BT_OCTET32_LEN]; /* octet array: size 32 */ + +#define DEV_CLASS_LEN 3 +typedef UINT8 DEV_CLASS[DEV_CLASS_LEN]; /* Device class */ +typedef UINT8 *DEV_CLASS_PTR; /* Pointer to Device class */ + +#define EXT_INQ_RESP_LEN 3 +typedef UINT8 EXT_INQ_RESP[EXT_INQ_RESP_LEN];/* Extended Inquiry Response */ +typedef UINT8 *EXT_INQ_RESP_PTR; /* Pointer to Extended Inquiry Response */ + +#define BD_NAME_LEN 248 +typedef UINT8 BD_NAME[BD_NAME_LEN + 1]; /* Device name */ +typedef UINT8 *BD_NAME_PTR; /* Pointer to Device name */ + +#define BD_FEATURES_LEN 8 +typedef UINT8 BD_FEATURES[BD_FEATURES_LEN]; /* LMP features supported by device */ + +#define BT_EVENT_MASK_LEN 8 +typedef UINT8 BT_EVENT_MASK[BT_EVENT_MASK_LEN]; /* Event Mask */ + +#define LAP_LEN 3 +typedef UINT8 LAP[LAP_LEN]; /* IAC as passed to Inquiry (LAP) */ +typedef UINT8 INQ_LAP[LAP_LEN]; /* IAC as passed to Inquiry (LAP) */ + +#define RAND_NUM_LEN 16 +typedef UINT8 RAND_NUM[RAND_NUM_LEN]; + +#define ACO_LEN 12 +typedef UINT8 ACO[ACO_LEN]; /* Authenticated ciphering offset */ + +#define COF_LEN 12 +typedef UINT8 COF[COF_LEN]; /* ciphering offset number */ + +typedef struct { + UINT8 qos_flags; /* TBD */ + UINT8 service_type; /* see below */ + UINT32 token_rate; /* bytes/second */ + UINT32 token_bucket_size; /* bytes */ + UINT32 peak_bandwidth; /* bytes/second */ + UINT32 latency; /* microseconds */ + UINT32 delay_variation; /* microseconds */ +} FLOW_SPEC; + +/* Values for service_type */ +#define NO_TRAFFIC 0 +#define BEST_EFFORT 1 +#define GUARANTEED 2 + +/* Service class of the CoD */ +#define SERV_CLASS_NETWORKING (1 << 1) +#define SERV_CLASS_RENDERING (1 << 2) +#define SERV_CLASS_CAPTURING (1 << 3) +#define SERV_CLASS_OBJECT_TRANSFER (1 << 4) +#define SERV_CLASS_OBJECT_AUDIO (1 << 5) +#define SERV_CLASS_OBJECT_TELEPHONY (1 << 6) +#define SERV_CLASS_OBJECT_INFORMATION (1 << 7) + +/* Second byte */ +#define SERV_CLASS_LIMITED_DISC_MODE (0x20) + +/* Field size definitions. Note that byte lengths are rounded up. */ +#define ACCESS_CODE_BIT_LEN 72 +#define ACCESS_CODE_BYTE_LEN 9 +#define SHORTENED_ACCESS_CODE_BIT_LEN 68 + +typedef UINT8 ACCESS_CODE[ACCESS_CODE_BYTE_LEN]; + +#define SYNTH_TX 1 /* want synth code to TRANSMIT at this freq */ +#define SYNTH_RX 2 /* want synth code to RECEIVE at this freq */ + +#define SYNC_REPS 1 /* repeats of sync word transmitted to start of burst */ + +/* Bluetooth CLK27 */ +#define BT_CLK27 (2 << 26) + +/* Bluetooth CLK12 is 1.28 sec */ +#define BT_CLK12_TO_MS(x) ((x) * 1280) +#define BT_MS_TO_CLK12(x) ((x) / 1280) +#define BT_CLK12_TO_SLOTS(x) ((x) << 11) + +/* Bluetooth CLK is 0.625 msec */ +#define BT_CLK_TO_MS(x) (((x) * 5 + 3) / 8) +#define BT_MS_TO_CLK(x) (((x) * 8 + 2) / 5) + +#define BT_CLK_TO_MICROSECS(x) (((x) * 5000 + 3) / 8) +#define BT_MICROSECS_TO_CLK(x) (((x) * 8 + 2499) / 5000) + +/* Maximum UUID size - 16 bytes, and structure to hold any type of UUID. */ +#define MAX_UUID_SIZE 16 +typedef struct +{ +#define LEN_UUID_16 2 +#define LEN_UUID_32 4 +#define LEN_UUID_128 16 + + UINT16 len; + + union + { + UINT16 uuid16; + UINT32 uuid32; + UINT8 uuid128[MAX_UUID_SIZE]; + } uu; + +} tBT_UUID; + +#define BT_EIR_FLAGS_TYPE 0x01 +#define BT_EIR_MORE_16BITS_UUID_TYPE 0x02 +#define BT_EIR_COMPLETE_16BITS_UUID_TYPE 0x03 +#define BT_EIR_MORE_32BITS_UUID_TYPE 0x04 +#define BT_EIR_COMPLETE_32BITS_UUID_TYPE 0x05 +#define BT_EIR_MORE_128BITS_UUID_TYPE 0x06 +#define BT_EIR_COMPLETE_128BITS_UUID_TYPE 0x07 +#define BT_EIR_SHORTENED_LOCAL_NAME_TYPE 0x08 +#define BT_EIR_COMPLETE_LOCAL_NAME_TYPE 0x09 +#define BT_EIR_TX_POWER_LEVEL_TYPE 0x0A +#define BT_EIR_OOB_BD_ADDR_TYPE 0x0C +#define BT_EIR_OOB_COD_TYPE 0x0D +#define BT_EIR_OOB_SSP_HASH_C_TYPE 0x0E +#define BT_EIR_OOB_SSP_RAND_R_TYPE 0x0F +#define BT_EIR_MANUFACTURER_SPECIFIC_TYPE 0xFF + +#define BT_OOB_COD_SIZE 3 +#define BT_OOB_HASH_C_SIZE 16 +#define BT_OOB_RAND_R_SIZE 16 + +/* Broadcom proprietary UUIDs and reserved PSMs +** +** The lowest 4 bytes byte of the UUID or GUID depends on the feature. Typically, +** the value of those bytes will be the PSM or SCN, but it is up to the features. +*/ +#define BRCM_PROPRIETARY_UUID_BASE 0xDA, 0x23, 0x41, 0x02, 0xA3, 0xBB, 0xC1, 0x71, 0xBA, 0x09, 0x6f, 0x21 +#define BRCM_PROPRIETARY_GUID_BASE 0xda23, 0x4102, 0xa3, 0xbb, 0xc1, 0x71, 0xba, 0x09, 0x6f, 0x21 + +/* We will not allocate a PSM in the reserved range to 3rd party apps +*/ +#define BRCM_RESERVED_PSM_START 0x5AE1 +#define BRCM_RESERVED_PSM_END 0x5AFF + +#define BRCM_UTILITY_SERVICE_PSM 0x5AE1 +#define BRCM_MATCHER_PSM 0x5AE3 + +/* Connection statistics +*/ + +/* Structure to hold connection stats */ +#ifndef BT_CONN_STATS_DEFINED +#define BT_CONN_STATS_DEFINED + +/* These bits are used in the bIsConnected field */ +#define BT_CONNECTED_USING_BREDR 1 +#define BT_CONNECTED_USING_AMP 2 + +typedef struct +{ + UINT32 is_connected; + INT32 rssi; + UINT32 bytes_sent; + UINT32 bytes_rcvd; + UINT32 duration; +} tBT_CONN_STATS; + +#endif + + +/***************************************************************************** +** Low Energy definitions +** +** Address types +*/ +#define BLE_ADDR_PUBLIC 0x00 +#define BLE_ADDR_RANDOM 0x01 +#define BLE_ADDR_PUBLIC_ID 0x02 +#define BLE_ADDR_RANDOM_ID 0x03 +typedef UINT8 tBLE_ADDR_TYPE; +#define BLE_ADDR_TYPE_MASK (BLE_ADDR_RANDOM | BLE_ADDR_PUBLIC) + +#define BT_TRANSPORT_INVALID 0 +#define BT_TRANSPORT_BR_EDR 1 +#define BT_TRANSPORT_LE 2 +typedef UINT8 tBT_TRANSPORT; + +#define BLE_ADDR_IS_STATIC(x) ((x[0] & 0xC0) == 0xC0) + +typedef struct +{ + tBLE_ADDR_TYPE type; + BD_ADDR bda; +} tBLE_BD_ADDR; + +/* Device Types +*/ +#define BT_DEVICE_TYPE_BREDR 0x01 +#define BT_DEVICE_TYPE_BLE 0x02 +#define BT_DEVICE_TYPE_DUMO 0x03 +typedef UINT8 tBT_DEVICE_TYPE; +/*****************************************************************************/ + + +/* Define trace levels */ +#define BT_TRACE_LEVEL_NONE 0 /* No trace messages to be generated */ +#define BT_TRACE_LEVEL_ERROR 1 /* Error condition trace messages */ +#define BT_TRACE_LEVEL_WARNING 2 /* Warning condition trace messages */ +#define BT_TRACE_LEVEL_API 3 /* API traces */ +#define BT_TRACE_LEVEL_EVENT 4 /* Debug messages for events */ +#define BT_TRACE_LEVEL_DEBUG 5 /* Full debug messages */ +#define BT_TRACE_LEVEL_VERBOSE 6 /* Verbose debug messages */ + +#define MAX_TRACE_LEVEL 6 + + +/* Define New Trace Type Definition */ +/* TRACE_CTRL_TYPE 0x^^000000*/ +#define TRACE_CTRL_MASK 0xff000000 +#define TRACE_GET_CTRL(x) ((((UINT32)(x)) & TRACE_CTRL_MASK) >> 24) + +#define TRACE_CTRL_GENERAL 0x00000000 +#define TRACE_CTRL_STR_RESOURCE 0x01000000 +#define TRACE_CTRL_SEQ_FLOW 0x02000000 +#define TRACE_CTRL_MAX_NUM 3 + +/* LAYER SPECIFIC 0x00^^0000*/ +#define TRACE_LAYER_MASK 0x00ff0000 +#define TRACE_GET_LAYER(x) ((((UINT32)(x)) & TRACE_LAYER_MASK) >> 16) + +#define TRACE_LAYER_NONE 0x00000000 +#define TRACE_LAYER_USB 0x00010000 +#define TRACE_LAYER_SERIAL 0x00020000 +#define TRACE_LAYER_SOCKET 0x00030000 +#define TRACE_LAYER_RS232 0x00040000 +#define TRACE_LAYER_TRANS_MAX_NUM 5 +#define TRACE_LAYER_TRANS_ALL 0x007f0000 +#define TRACE_LAYER_LC 0x00050000 +#define TRACE_LAYER_LM 0x00060000 +#define TRACE_LAYER_HCI 0x00070000 +#define TRACE_LAYER_L2CAP 0x00080000 +#define TRACE_LAYER_RFCOMM 0x00090000 +#define TRACE_LAYER_SDP 0x000a0000 +#define TRACE_LAYER_TCS 0x000b0000 +#define TRACE_LAYER_OBEX 0x000c0000 +#define TRACE_LAYER_BTM 0x000d0000 +#define TRACE_LAYER_GAP 0x000e0000 +#define TRACE_LAYER_ICP 0x00110000 +#define TRACE_LAYER_HSP2 0x00120000 +#define TRACE_LAYER_SPP 0x00130000 +#define TRACE_LAYER_CTP 0x00140000 +#define TRACE_LAYER_BPP 0x00150000 +#define TRACE_LAYER_HCRP 0x00160000 +#define TRACE_LAYER_FTP 0x00170000 +#define TRACE_LAYER_OPP 0x00180000 +#define TRACE_LAYER_BTU 0x00190000 +#define TRACE_LAYER_GKI 0x001a0000 +#define TRACE_LAYER_BNEP 0x001b0000 +#define TRACE_LAYER_PAN 0x001c0000 +#define TRACE_LAYER_HFP 0x001d0000 +#define TRACE_LAYER_HID 0x001e0000 +#define TRACE_LAYER_BIP 0x001f0000 +#define TRACE_LAYER_AVP 0x00200000 +#define TRACE_LAYER_A2D 0x00210000 +#define TRACE_LAYER_SAP 0x00220000 +#define TRACE_LAYER_AMP 0x00230000 +#define TRACE_LAYER_MCA 0x00240000 +#define TRACE_LAYER_ATT 0x00250000 +#define TRACE_LAYER_SMP 0x00260000 +#define TRACE_LAYER_NFC 0x00270000 +#define TRACE_LAYER_NCI 0x00280000 +#define TRACE_LAYER_LLCP 0x00290000 +#define TRACE_LAYER_NDEF 0x002a0000 +#define TRACE_LAYER_RW 0x002b0000 +#define TRACE_LAYER_CE 0x002c0000 +#define TRACE_LAYER_P2P 0x002d0000 +#define TRACE_LAYER_SNEP 0x002e0000 +#define TRACE_LAYER_CHO 0x002f0000 +#define TRACE_LAYER_NFA 0x00300000 + +#define TRACE_LAYER_MAX_NUM 0x0031 + + +/* TRACE_ORIGINATOR 0x0000^^00*/ +#define TRACE_ORG_MASK 0x0000ff00 +#define TRACE_GET_ORG(x) ((((UINT32)(x)) & TRACE_ORG_MASK) >> 8) + +#define TRACE_ORG_STACK 0x00000000 +#define TRACE_ORG_HCI_TRANS 0x00000100 +#define TRACE_ORG_PROTO_DISP 0x00000200 +#define TRACE_ORG_RPC 0x00000300 +#define TRACE_ORG_GKI 0x00000400 +#define TRACE_ORG_APPL 0x00000500 +#define TRACE_ORG_SCR_WRAPPER 0x00000600 +#define TRACE_ORG_SCR_ENGINE 0x00000700 +#define TRACE_ORG_USER_SCR 0x00000800 +#define TRACE_ORG_TESTER 0x00000900 +#define TRACE_ORG_MAX_NUM 10 /* 32-bit mask; must be < 32 */ +#define TRACE_LITE_ORG_MAX_NUM 6 +#define TRACE_ORG_ALL 0x03ff +#define TRACE_ORG_RPC_TRANS 0x04 + +#define TRACE_ORG_REG 0x00000909 +#define TRACE_ORG_REG_SUCCESS 0x0000090a + +/* TRACE_TYPE 0x000000^^*/ +#define TRACE_TYPE_MASK 0x000000ff +#define TRACE_GET_TYPE(x) (((UINT32)(x)) & TRACE_TYPE_MASK) + +#define TRACE_TYPE_ERROR 0x00000000 +#define TRACE_TYPE_WARNING 0x00000001 +#define TRACE_TYPE_API 0x00000002 +#define TRACE_TYPE_EVENT 0x00000003 +#define TRACE_TYPE_DEBUG 0x00000004 +#define TRACE_TYPE_STACK_ONLY_MAX TRACE_TYPE_DEBUG +#define TRACE_TYPE_TX 0x00000005 +#define TRACE_TYPE_RX 0x00000006 +#define TRACE_TYPE_DEBUG_ASSERT 0x00000007 +#define TRACE_TYPE_GENERIC 0x00000008 +#define TRACE_TYPE_REG 0x00000009 +#define TRACE_TYPE_REG_SUCCESS 0x0000000a +#define TRACE_TYPE_CMD_TX 0x0000000b +#define TRACE_TYPE_EVT_TX 0x0000000c +#define TRACE_TYPE_ACL_TX 0x0000000d +#define TRACE_TYPE_CMD_RX 0x0000000e +#define TRACE_TYPE_EVT_RX 0x0000000f +#define TRACE_TYPE_ACL_RX 0x00000010 +#define TRACE_TYPE_TARGET_TRACE 0x00000011 +#define TRACE_TYPE_SCO_TX 0x00000012 +#define TRACE_TYPE_SCO_RX 0x00000013 + + +#define TRACE_TYPE_MAX_NUM 20 +#define TRACE_TYPE_ALL 0xffff + +/* Define color for script type */ +#define SCR_COLOR_DEFAULT 0 +#define SCR_COLOR_TYPE_COMMENT 1 +#define SCR_COLOR_TYPE_COMMAND 2 +#define SCR_COLOR_TYPE_EVENT 3 +#define SCR_COLOR_TYPE_SELECT 4 + +/* Define protocol trace flag values */ +#define SCR_PROTO_TRACE_HCI_SUMMARY 0x00000001 +#define SCR_PROTO_TRACE_HCI_DATA 0x00000002 +#define SCR_PROTO_TRACE_L2CAP 0x00000004 +#define SCR_PROTO_TRACE_RFCOMM 0x00000008 +#define SCR_PROTO_TRACE_SDP 0x00000010 +#define SCR_PROTO_TRACE_TCS 0x00000020 +#define SCR_PROTO_TRACE_OBEX 0x00000040 +#define SCR_PROTO_TRACE_OAPP 0x00000080 /* OBEX Application Profile */ +#define SCR_PROTO_TRACE_AMP 0x00000100 +#define SCR_PROTO_TRACE_BNEP 0x00000200 +#define SCR_PROTO_TRACE_AVP 0x00000400 +#define SCR_PROTO_TRACE_MCA 0x00000800 +#define SCR_PROTO_TRACE_ATT 0x00001000 +#define SCR_PROTO_TRACE_SMP 0x00002000 +#define SCR_PROTO_TRACE_NCI 0x00004000 +#define SCR_PROTO_TRACE_LLCP 0x00008000 +#define SCR_PROTO_TRACE_NDEF 0x00010000 +#define SCR_PROTO_TRACE_RW 0x00020000 +#define SCR_PROTO_TRACE_CE 0x00040000 +#define SCR_PROTO_TRACE_SNEP 0x00080000 +#define SCR_PROTO_TRACE_CHO 0x00100000 +#define SCR_PROTO_TRACE_ALL 0x001fffff +#define SCR_PROTO_TRACE_HCI_LOGGING_VSE 0x0800 /* Brcm vs event for logmsg and protocol traces */ + +#define MAX_SCRIPT_TYPE 5 + +#define TCS_PSM_INTERCOM 5 +#define TCS_PSM_CORDLESS 7 +#define BT_PSM_BNEP 0x000F +/* Define PSMs HID uses */ +#define HID_PSM_CONTROL 0x0011 +#define HID_PSM_INTERRUPT 0x0013 + +/* Define a function for logging */ +typedef void (BT_LOG_FUNC) (int trace_type, const char *fmt_str, ...); + +/* bd addr length and type */ +#ifndef BD_ADDR_LEN +#define BD_ADDR_LEN 6 +typedef uint8_t BD_ADDR[BD_ADDR_LEN]; +#endif + +// From bd.c + +/***************************************************************************** +** Constants +*****************************************************************************/ + +/* global constant for "any" bd addr */ +static const BD_ADDR bd_addr_any = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; +static const BD_ADDR bd_addr_null= {0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + +/***************************************************************************** +** Functions +*****************************************************************************/ + +/******************************************************************************* +** +** Function bdcpy +** +** Description Copy bd addr b to a. +** +** +** Returns void +** +*******************************************************************************/ +static inline void bdcpy(BD_ADDR a, const BD_ADDR b) +{ + int i; + + for (i = BD_ADDR_LEN; i != 0; i--) + { + *a++ = *b++; + } +} + +/******************************************************************************* +** +** Function bdcmp +** +** Description Compare bd addr b to a. +** +** +** Returns Zero if b==a, nonzero otherwise (like memcmp). +** +*******************************************************************************/ +static inline int bdcmp(const BD_ADDR a, const BD_ADDR b) +{ + int i; + + for (i = BD_ADDR_LEN; i != 0; i--) + { + if (*a++ != *b++) + { + return -1; + } + } + return 0; +} + +/******************************************************************************* +** +** Function bdcmpany +** +** Description Compare bd addr to "any" bd addr. +** +** +** Returns Zero if a equals bd_addr_any. +** +*******************************************************************************/ +static inline int bdcmpany(const BD_ADDR a) +{ + return bdcmp(a, bd_addr_any); +} + +/******************************************************************************* +** +** Function bdsetany +** +** Description Set bd addr to "any" bd addr. +** +** +** Returns void +** +*******************************************************************************/ +static inline void bdsetany(BD_ADDR a) +{ + bdcpy(a, bd_addr_any); +} +#endif diff --git a/components/bt/bluedroid/stack/include/btm_api.h b/components/bt/bluedroid/stack/include/btm_api.h new file mode 100755 index 0000000000..02ca5dd8ee --- /dev/null +++ b/components/bt/bluedroid/stack/include/btm_api.h @@ -0,0 +1,4100 @@ +/****************************************************************************** + * + * Copyright (C) 1999-2012 Broadcom Corporation + * + * 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 Bluetooth Manager (BTM) API function external + * definitions. + * + ******************************************************************************/ +#ifndef BTM_API_H +#define BTM_API_H + +#include "bt_defs.h" +#include "bt_target.h" +#include "hcidefs.h" + +#if SDP_INCLUDED == TRUE +#include "sdp_api.h" +#endif + +#if SMP_INCLUDED == TRUE +#include "smp_api.h" +#endif +/***************************************************************************** +** DEVICE CONTROL and COMMON +*****************************************************************************/ +/***************************** +** Device Control Constants +******************************/ +/* Maximum number of bytes allowed for vendor specific command parameters */ +#define BTM_MAX_VENDOR_SPECIFIC_LEN HCI_COMMAND_SIZE + +/* BTM application return status codes */ +enum +{ + BTM_SUCCESS = 0, /* 0 Command succeeded */ + BTM_CMD_STARTED, /* 1 Command started OK. */ + BTM_BUSY, /* 2 Device busy with another command */ + BTM_NO_RESOURCES, /* 3 No resources to issue command */ + BTM_MODE_UNSUPPORTED, /* 4 Request for 1 or more unsupported modes */ + BTM_ILLEGAL_VALUE, /* 5 Illegal parameter value */ + BTM_WRONG_MODE, /* 6 Device in wrong mode for request */ + BTM_UNKNOWN_ADDR, /* 7 Unknown remote BD address */ + BTM_DEVICE_TIMEOUT, /* 8 Device timeout */ + BTM_BAD_VALUE_RET, /* 9 A bad value was received from HCI */ + BTM_ERR_PROCESSING, /* 10 Generic error */ + BTM_NOT_AUTHORIZED, /* 11 Authorization failed */ + BTM_DEV_RESET, /* 12 Device has been reset */ + BTM_CMD_STORED, /* 13 request is stored in control block */ + BTM_ILLEGAL_ACTION, /* 14 state machine gets illegal command */ + BTM_DELAY_CHECK, /* 15 delay the check on encryption */ + BTM_SCO_BAD_LENGTH, /* 16 Bad SCO over HCI data length */ + BTM_SUCCESS_NO_SECURITY, /* 17 security passed, no security set */ + BTM_FAILED_ON_SECURITY, /* 18 security failed */ + BTM_REPEATED_ATTEMPTS, /* 19 repeated attempts for LE security requests */ + BTM_MODE4_LEVEL4_NOT_SUPPORTED /* 20 Secure Connections Only Mode can't be supported */ +}; + +typedef uint8_t tBTM_STATUS; + +#if (defined(BTA_HOST_INTERLEAVE_SEARCH) && BTA_HOST_INTERLEAVE_SEARCH == TRUE) +typedef enum +{ + BTM_BR_ONE, /*0 First state or BR/EDR scan 1*/ + BTM_BLE_ONE, /*1BLE scan 1*/ + BTM_BR_TWO, /*2 BR/EDR scan 2*/ + BTM_BLE_TWO, /*3 BLE scan 2*/ + BTM_FINISH, /*4 End of Interleave Scan, or normal scan*/ + BTM_NO_INTERLEAVING /*5 No Interleaving*/ +}btm_inq_state; +#endif + + + +/************************* +** Device Control Types +**************************/ +#define BTM_DEVICE_ROLE_BR 0x01 +#define BTM_DEVICE_ROLE_DUAL 0x02 +#define BTM_MAX_DEVICE_ROLE BTM_DEVICE_ROLE_DUAL +typedef UINT8 tBTM_DEVICE_ROLE; + +/* Device name of peer (may be truncated to save space in BTM database) */ +typedef UINT8 tBTM_BD_NAME[BTM_MAX_REM_BD_NAME_LEN + 1]; + +/* Structure returned with local version information */ +typedef struct +{ + UINT8 hci_version; + UINT16 hci_revision; + UINT8 lmp_version; + UINT16 manufacturer; + UINT16 lmp_subversion; +} tBTM_VERSION_INFO; + +/* Structure returned with Vendor Specific Command complete callback */ +typedef struct +{ + UINT16 opcode; + UINT16 param_len; + UINT8 *p_param_buf; +} tBTM_VSC_CMPL; + +#define BTM_VSC_CMPL_DATA_SIZE (BTM_MAX_VENDOR_SPECIFIC_LEN + sizeof(tBTM_VSC_CMPL)) +/************************************************** +** Device Control and General Callback Functions +***************************************************/ +/* Callback function for when device status changes. Appl must poll for +** what the new state is (BTM_IsDeviceUp). The event occurs whenever the stack +** has detected that the controller status has changed. This asynchronous event +** is enabled/disabled by calling BTM_RegisterForDeviceStatusNotif(). +*/ +enum +{ + BTM_DEV_STATUS_UP, + BTM_DEV_STATUS_DOWN, + BTM_DEV_STATUS_CMD_TOUT +}; + +typedef UINT8 tBTM_DEV_STATUS; + + +typedef void (tBTM_DEV_STATUS_CB) (tBTM_DEV_STATUS status); + + +/* Callback function for when a vendor specific event occurs. The length and +** array of returned parameter bytes are included. This asynchronous event +** is enabled/disabled by calling BTM_RegisterForVSEvents(). +*/ +typedef void (tBTM_VS_EVT_CB) (UINT8 len, UINT8 *p); + + +/* General callback function for notifying an application that a synchronous +** BTM function is complete. The pointer contains the address of any returned data. +*/ +typedef void (tBTM_CMPL_CB) (void *p1); + +/* VSC callback function for notifying an application that a synchronous +** BTM function is complete. The pointer contains the address of any returned data. +*/ +typedef void (tBTM_VSC_CMPL_CB) (tBTM_VSC_CMPL *p1); + +/* Callback for apps to check connection and inquiry filters. +** Parameters are the BD Address of remote and the Dev Class of remote. +** If the app returns none zero, the connection or inquiry result will be dropped. +*/ +typedef UINT8 (tBTM_FILTER_CB) (BD_ADDR bd_addr, DEV_CLASS dc); + +/***************************************************************************** +** DEVICE DISCOVERY - Inquiry, Remote Name, Discovery, Class of Device +*****************************************************************************/ +/******************************* +** Device Discovery Constants +********************************/ +/* Discoverable modes */ +#define BTM_NON_DISCOVERABLE 0 +#define BTM_LIMITED_DISCOVERABLE 1 +#define BTM_GENERAL_DISCOVERABLE 2 +#define BTM_DISCOVERABLE_MASK (BTM_LIMITED_DISCOVERABLE|BTM_GENERAL_DISCOVERABLE) +#define BTM_MAX_DISCOVERABLE BTM_GENERAL_DISCOVERABLE +/* high byte for BLE Discoverable modes */ +#define BTM_BLE_NON_DISCOVERABLE 0x0000 +#define BTM_BLE_LIMITED_DISCOVERABLE 0x0100 +#define BTM_BLE_GENERAL_DISCOVERABLE 0x0200 +#define BTM_BLE_MAX_DISCOVERABLE BTM_BLE_GENERAL_DISCOVERABLE +#define BTM_BLE_DISCOVERABLE_MASK (BTM_BLE_NON_DISCOVERABLE|BTM_BLE_LIMITED_DISCOVERABLE|BTM_BLE_GENERAL_DISCOVERABLE) + +/* Connectable modes */ +#define BTM_NON_CONNECTABLE 0 +#define BTM_CONNECTABLE 1 +#define BTM_CONNECTABLE_MASK (BTM_NON_CONNECTABLE | BTM_CONNECTABLE) +/* high byte for BLE Connectable modes */ +#define BTM_BLE_NON_CONNECTABLE 0x0000 +#define BTM_BLE_CONNECTABLE 0x0100 +#define BTM_BLE_MAX_CONNECTABLE BTM_BLE_CONNECTABLE +#define BTM_BLE_CONNECTABLE_MASK (BTM_BLE_NON_CONNECTABLE | BTM_BLE_CONNECTABLE) + +/* Inquiry modes + * Note: These modes are associated with the inquiry active values (BTM_*ACTIVE) */ +#define BTM_INQUIRY_NONE 0 +#define BTM_GENERAL_INQUIRY 0x01 +#define BTM_LIMITED_INQUIRY 0x02 +#define BTM_BR_INQUIRY_MASK (BTM_GENERAL_INQUIRY | BTM_LIMITED_INQUIRY) + +/* high byte of inquiry mode for BLE inquiry mode */ +#define BTM_BLE_INQUIRY_NONE 0x00 +#define BTM_BLE_GENERAL_INQUIRY 0x10 +#define BTM_BLE_LIMITED_INQUIRY 0x20 +#define BTM_BLE_INQUIRY_MASK (BTM_BLE_GENERAL_INQUIRY|BTM_BLE_LIMITED_INQUIRY) + +/* BTM_IsInquiryActive return values (Bit Mask) + * Note: These bit masks are associated with the inquiry modes (BTM_*_INQUIRY) */ +#define BTM_INQUIRY_INACTIVE 0x0 /* no inquiry in progress */ +#define BTM_GENERAL_INQUIRY_ACTIVE BTM_GENERAL_INQUIRY /* a general inquiry is in progress */ +#define BTM_LIMITED_INQUIRY_ACTIVE BTM_LIMITED_INQUIRY /* a limited inquiry is in progress */ +#define BTM_PERIODIC_INQUIRY_ACTIVE 0x8 /* a periodic inquiry is active */ +#define BTM_SSP_INQUIRY_ACTIVE 0x4 /* SSP is active, so inquiry is disallowed (work around for FW bug) */ +#define BTM_LE_GENERAL_INQUIRY_ACTIVE BTM_BLE_GENERAL_INQUIRY /* a general inquiry is in progress */ +#define BTM_LE_LIMITED_INQUIRY_ACTIVE BTM_BLE_LIMITED_INQUIRY /* a limited inquiry is in progress */ + +/* inquiry activity mask */ +#define BTM_BR_INQ_ACTIVE_MASK (BTM_GENERAL_INQUIRY_ACTIVE|BTM_LIMITED_INQUIRY_ACTIVE|BTM_PERIODIC_INQUIRY_ACTIVE) /* BR/EDR inquiry activity mask */ +#define BTM_BLE_SCAN_ACTIVE_MASK 0xF0 /* LE scan activity mask */ +#define BTM_BLE_INQ_ACTIVE_MASK (BTM_LE_GENERAL_INQUIRY_ACTIVE|BTM_LE_LIMITED_INQUIRY_ACTIVE) /* LE inquiry activity mask*/ +#define BTM_INQUIRY_ACTIVE_MASK (BTM_BR_INQ_ACTIVE_MASK | BTM_BLE_INQ_ACTIVE_MASK) /* inquiry activity mask */ + +/* Define scan types */ +#define BTM_SCAN_TYPE_STANDARD 0 +#define BTM_SCAN_TYPE_INTERLACED 1 /* 1.2 devices only */ + +/* Define inquiry results mode */ +#define BTM_INQ_RESULT_STANDARD 0 +#define BTM_INQ_RESULT_WITH_RSSI 1 +#define BTM_INQ_RESULT_EXTENDED 2 + +#define BTM_INQ_RES_IGNORE_RSSI 0x7f /* RSSI value not supplied (ignore it) */ + +/* Inquiry Filter Condition types (see tBTM_INQ_PARMS) */ +#define BTM_CLR_INQUIRY_FILTER 0 /* Inquiry Filtering is turned off */ +#define BTM_FILTER_COND_DEVICE_CLASS HCI_FILTER_COND_DEVICE_CLASS /* Filter on device class */ +#define BTM_FILTER_COND_BD_ADDR HCI_FILTER_COND_BD_ADDR /* Filter on device addr */ + +/* State of the remote name retrieval during inquiry operations. +** Used in the tBTM_INQ_INFO structure, and returned in the +** BTM_InqDbRead, BTM_InqDbFirst, and BTM_InqDbNext functions. +** The name field is valid when the state returned is +** BTM_INQ_RMT_NAME_DONE */ +#define BTM_INQ_RMT_NAME_EMPTY 0 +#define BTM_INQ_RMT_NAME_PENDING 1 +#define BTM_INQ_RMT_NAME_DONE 2 +#define BTM_INQ_RMT_NAME_FAILED 3 + +/********************************* + *** Class of Device constants *** + *********************************/ +#define BTM_FORMAT_TYPE_1 0x00 + +/**************************** +** minor device class field +*****************************/ + +/* 0x00 is used as unclassified for all minor device classes */ +#define BTM_COD_MINOR_UNCLASSIFIED 0x00 + +/* minor device class field for Computer Major Class */ +/* #define BTM_COD_MINOR_UNCLASSIFIED 0x00 */ +#define BTM_COD_MINOR_DESKTOP_WORKSTATION 0x04 +#define BTM_COD_MINOR_SERVER_COMPUTER 0x08 +#define BTM_COD_MINOR_LAPTOP 0x0C +#define BTM_COD_MINOR_HANDHELD_PC_PDA 0x10 /* clam shell */ +#define BTM_COD_MINOR_PALM_SIZE_PC_PDA 0x14 +#define BTM_COD_MINOR_WEARABLE_COMPUTER 0x18 /* watch sized */ + +/* minor device class field for Phone Major Class */ +/* #define BTM_COD_MINOR_UNCLASSIFIED 0x00 */ +#define BTM_COD_MINOR_CELLULAR 0x04 +#define BTM_COD_MINOR_CORDLESS 0x08 +#define BTM_COD_MINOR_SMART_PHONE 0x0C +#define BTM_COD_MINOR_WIRED_MDM_V_GTWY 0x10 /* wired modem or voice gatway */ +#define BTM_COD_MINOR_ISDN_ACCESS 0x14 + +/* minor device class field for LAN Access Point Major Class */ +/* Load Factor Field bit 5-7 */ +#define BTM_COD_MINOR_FULLY_AVAILABLE 0x00 +#define BTM_COD_MINOR_1_17_UTILIZED 0x20 +#define BTM_COD_MINOR_17_33_UTILIZED 0x40 +#define BTM_COD_MINOR_33_50_UTILIZED 0x60 +#define BTM_COD_MINOR_50_67_UTILIZED 0x80 +#define BTM_COD_MINOR_67_83_UTILIZED 0xA0 +#define BTM_COD_MINOR_83_99_UTILIZED 0xC0 +#define BTM_COD_MINOR_NO_SERVICE_AVAILABLE 0xE0 +/* sub-Field bit 2-4 */ +/* #define BTM_COD_MINOR_UNCLASSIFIED 0x00 */ + +/* minor device class field for Audio/Video Major Class */ +/* #define BTM_COD_MINOR_UNCLASSIFIED 0x00 */ +#define BTM_COD_MINOR_CONFM_HEADSET 0x04 +#define BTM_COD_MINOR_CONFM_HANDSFREE 0x08 +#define BTM_COD_MINOR_MICROPHONE 0x10 +#define BTM_COD_MINOR_LOUDSPEAKER 0x14 +#define BTM_COD_MINOR_HEADPHONES 0x18 +#define BTM_COD_MINOR_PORTABLE_AUDIO 0x1C +#define BTM_COD_MINOR_CAR_AUDIO 0x20 +#define BTM_COD_MINOR_SET_TOP_BOX 0x24 +#define BTM_COD_MINOR_HIFI_AUDIO 0x28 +#define BTM_COD_MINOR_VCR 0x2C +#define BTM_COD_MINOR_VIDEO_CAMERA 0x30 +#define BTM_COD_MINOR_CAMCORDER 0x34 +#define BTM_COD_MINOR_VIDEO_MONITOR 0x38 +#define BTM_COD_MINOR_VIDDISP_LDSPKR 0x3C +#define BTM_COD_MINOR_VIDEO_CONFERENCING 0x40 +#define BTM_COD_MINOR_GAMING_TOY 0x48 + +/* minor device class field for Peripheral Major Class */ +/* Bits 6-7 independently specify mouse, keyboard, or combo mouse/keyboard */ +#define BTM_COD_MINOR_KEYBOARD 0x40 +#define BTM_COD_MINOR_POINTING 0x80 +#define BTM_COD_MINOR_COMBO 0xC0 +/* Bits 2-5 OR'd with selection from bits 6-7 */ +/* #define BTM_COD_MINOR_UNCLASSIFIED 0x00 */ +#define BTM_COD_MINOR_JOYSTICK 0x04 +#define BTM_COD_MINOR_GAMEPAD 0x08 +#define BTM_COD_MINOR_REMOTE_CONTROL 0x0C +#define BTM_COD_MINOR_SENSING_DEVICE 0x10 +#define BTM_COD_MINOR_DIGITIZING_TABLET 0x14 +#define BTM_COD_MINOR_CARD_READER 0x18 /* e.g. SIM card reader */ +#define BTM_COD_MINOR_DIGITAL_PAN 0x1C +#define BTM_COD_MINOR_HAND_SCANNER 0x20 +#define BTM_COD_MINOR_HAND_GESTURAL_INPUT 0x24 + +/* minor device class field for Imaging Major Class */ +/* Bits 5-7 independently specify display, camera, scanner, or printer */ +#define BTM_COD_MINOR_DISPLAY 0x10 +#define BTM_COD_MINOR_CAMERA 0x20 +#define BTM_COD_MINOR_SCANNER 0x40 +#define BTM_COD_MINOR_PRINTER 0x80 +/* Bits 2-3 Reserved */ +/* #define BTM_COD_MINOR_UNCLASSIFIED 0x00 */ + +/* minor device class field for Wearable Major Class */ +/* Bits 2-7 meaningful */ +#define BTM_COD_MINOR_WRIST_WATCH 0x04 +#define BTM_COD_MINOR_PAGER 0x08 +#define BTM_COD_MINOR_JACKET 0x0C +#define BTM_COD_MINOR_HELMET 0x10 +#define BTM_COD_MINOR_GLASSES 0x14 + +/* minor device class field for Toy Major Class */ +/* Bits 2-7 meaningful */ +#define BTM_COD_MINOR_ROBOT 0x04 +#define BTM_COD_MINOR_VEHICLE 0x08 +#define BTM_COD_MINOR_DOLL_ACTION_FIGURE 0x0C +#define BTM_COD_MINOR_CONTROLLER 0x10 +#define BTM_COD_MINOR_GAME 0x14 + +/* minor device class field for Health Major Class */ +/* Bits 2-7 meaningful */ +#define BTM_COD_MINOR_BLOOD_MONITOR 0x04 +#define BTM_COD_MINOR_THERMOMETER 0x08 +#define BTM_COD_MINOR_WEIGHING_SCALE 0x0C +#define BTM_COD_MINOR_GLUCOSE_METER 0x10 +#define BTM_COD_MINOR_PULSE_OXIMETER 0x14 +#define BTM_COD_MINOR_HEART_PULSE_MONITOR 0x18 +#define BTM_COD_MINOR_HEALTH_DATA_DISPLAY 0x1C +#define BTM_COD_MINOR_STEP_COUNTER 0x20 +#define BTM_COD_MINOR_BODY_COM_ANALYZER 0x24 +#define BTM_COD_MINOR_PEAK_FLOW_MONITOR 0x28 +#define BTM_COD_MINOR_MEDICATION_MONITOR 0x2C +#define BTM_COD_MINOR_KNEE_PROSTHESIS 0x30 +#define BTM_COD_MINOR_ANKLE_PROSTHESIS 0x34 + + +/*************************** +** major device class field +****************************/ +#define BTM_COD_MAJOR_MISCELLANEOUS 0x00 +#define BTM_COD_MAJOR_COMPUTER 0x01 +#define BTM_COD_MAJOR_PHONE 0x02 +#define BTM_COD_MAJOR_LAN_ACCESS_PT 0x03 +#define BTM_COD_MAJOR_AUDIO 0x04 +#define BTM_COD_MAJOR_PERIPHERAL 0x05 +#define BTM_COD_MAJOR_IMAGING 0x06 +#define BTM_COD_MAJOR_WEARABLE 0x07 +#define BTM_COD_MAJOR_TOY 0x08 +#define BTM_COD_MAJOR_HEALTH 0x09 +#define BTM_COD_MAJOR_UNCLASSIFIED 0x1F + +/*************************** +** service class fields +****************************/ +#define BTM_COD_SERVICE_LMTD_DISCOVER 0x0020 +#define BTM_COD_SERVICE_POSITIONING 0x0100 +#define BTM_COD_SERVICE_NETWORKING 0x0200 +#define BTM_COD_SERVICE_RENDERING 0x0400 +#define BTM_COD_SERVICE_CAPTURING 0x0800 +#define BTM_COD_SERVICE_OBJ_TRANSFER 0x1000 +#define BTM_COD_SERVICE_AUDIO 0x2000 +#define BTM_COD_SERVICE_TELEPHONY 0x4000 +#define BTM_COD_SERVICE_INFORMATION 0x8000 + +/* class of device field macros */ +#define BTM_COD_FORMAT_TYPE(u8, pd) {u8 = pd[2]&0x03;} +#define BTM_COD_MINOR_CLASS(u8, pd) {u8 = pd[2]&0xFC;} +#define BTM_COD_MAJOR_CLASS(u8, pd) {u8 = pd[1]&0x1F;} +#define BTM_COD_SERVICE_CLASS(u16, pd) {u16 = pd[0]; u16<<=8; u16 += pd[1]&0xE0;} + +/* to set the fields (assumes that format type is always 0) */ +#define FIELDS_TO_COD(pd, mn, mj, sv) {pd[2] = mn; pd[1] = \ + mj+ ((sv)&BTM_COD_SERVICE_CLASS_LO_B); \ + pd[0] = (sv) >> 8;} + +/* the COD masks */ +#define BTM_COD_FORMAT_TYPE_MASK 0x03 +#define BTM_COD_MINOR_CLASS_MASK 0xFC +#define BTM_COD_MAJOR_CLASS_MASK 0x1F +#define BTM_COD_SERVICE_CLASS_LO_B 0x00E0 +#define BTM_COD_SERVICE_CLASS_MASK 0xFFE0 + + +/* BTM service definitions +** Used for storing EIR data to bit mask +*/ +enum +{ + BTM_EIR_UUID_SERVCLASS_SERVICE_DISCOVERY_SERVER, +/* BTM_EIR_UUID_SERVCLASS_BROWSE_GROUP_DESCRIPTOR, */ +/* BTM_EIR_UUID_SERVCLASS_PUBLIC_BROWSE_GROUP, */ + BTM_EIR_UUID_SERVCLASS_SERIAL_PORT, + BTM_EIR_UUID_SERVCLASS_LAN_ACCESS_USING_PPP, + BTM_EIR_UUID_SERVCLASS_DIALUP_NETWORKING, + BTM_EIR_UUID_SERVCLASS_IRMC_SYNC, + BTM_EIR_UUID_SERVCLASS_OBEX_OBJECT_PUSH, + BTM_EIR_UUID_SERVCLASS_OBEX_FILE_TRANSFER, + BTM_EIR_UUID_SERVCLASS_IRMC_SYNC_COMMAND, + BTM_EIR_UUID_SERVCLASS_HEADSET, + BTM_EIR_UUID_SERVCLASS_CORDLESS_TELEPHONY, + BTM_EIR_UUID_SERVCLASS_AUDIO_SOURCE, + BTM_EIR_UUID_SERVCLASS_AUDIO_SINK, + BTM_EIR_UUID_SERVCLASS_AV_REM_CTRL_TARGET, +/* BTM_EIR_UUID_SERVCLASS_ADV_AUDIO_DISTRIBUTION, */ + BTM_EIR_UUID_SERVCLASS_AV_REMOTE_CONTROL, +/* BTM_EIR_UUID_SERVCLASS_VIDEO_CONFERENCING, */ + BTM_EIR_UUID_SERVCLASS_INTERCOM, + BTM_EIR_UUID_SERVCLASS_FAX, + BTM_EIR_UUID_SERVCLASS_HEADSET_AUDIO_GATEWAY, +/* BTM_EIR_UUID_SERVCLASS_WAP, */ +/* BTM_EIR_UUID_SERVCLASS_WAP_CLIENT, */ + BTM_EIR_UUID_SERVCLASS_PANU, + BTM_EIR_UUID_SERVCLASS_NAP, + BTM_EIR_UUID_SERVCLASS_GN, + BTM_EIR_UUID_SERVCLASS_DIRECT_PRINTING, +/* BTM_EIR_UUID_SERVCLASS_REFERENCE_PRINTING, */ + BTM_EIR_UUID_SERVCLASS_IMAGING, + BTM_EIR_UUID_SERVCLASS_IMAGING_RESPONDER, + BTM_EIR_UUID_SERVCLASS_IMAGING_AUTO_ARCHIVE, + BTM_EIR_UUID_SERVCLASS_IMAGING_REF_OBJECTS, + BTM_EIR_UUID_SERVCLASS_HF_HANDSFREE, + BTM_EIR_UUID_SERVCLASS_AG_HANDSFREE, + BTM_EIR_UUID_SERVCLASS_DIR_PRT_REF_OBJ_SERVICE, +/* BTM_EIR_UUID_SERVCLASS_REFLECTED_UI, */ + BTM_EIR_UUID_SERVCLASS_BASIC_PRINTING, + BTM_EIR_UUID_SERVCLASS_PRINTING_STATUS, + BTM_EIR_UUID_SERVCLASS_HUMAN_INTERFACE, + BTM_EIR_UUID_SERVCLASS_CABLE_REPLACEMENT, + BTM_EIR_UUID_SERVCLASS_HCRP_PRINT, + BTM_EIR_UUID_SERVCLASS_HCRP_SCAN, +/* BTM_EIR_UUID_SERVCLASS_COMMON_ISDN_ACCESS, */ +/* BTM_EIR_UUID_SERVCLASS_VIDEO_CONFERENCING_GW, */ +/* BTM_EIR_UUID_SERVCLASS_UDI_MT, */ +/* BTM_EIR_UUID_SERVCLASS_UDI_TA, */ +/* BTM_EIR_UUID_SERVCLASS_VCP, */ + BTM_EIR_UUID_SERVCLASS_SAP, + BTM_EIR_UUID_SERVCLASS_PBAP_PCE, + BTM_EIR_UUID_SERVCLASS_PBAP_PSE, +/* BTM_EIR_UUID_SERVCLASS_TE_PHONE_ACCESS, */ +/* BTM_EIR_UUID_SERVCLASS_ME_PHONE_ACCESS, */ + BTM_EIR_UUID_SERVCLASS_PHONE_ACCESS, + BTM_EIR_UUID_SERVCLASS_HEADSET_HS, + BTM_EIR_UUID_SERVCLASS_PNP_INFORMATION, +/* BTM_EIR_UUID_SERVCLASS_GENERIC_NETWORKING, */ +/* BTM_EIR_UUID_SERVCLASS_GENERIC_FILETRANSFER, */ +/* BTM_EIR_UUID_SERVCLASS_GENERIC_AUDIO, */ +/* BTM_EIR_UUID_SERVCLASS_GENERIC_TELEPHONY, */ +/* BTM_EIR_UUID_SERVCLASS_UPNP_SERVICE, */ +/* BTM_EIR_UUID_SERVCLASS_UPNP_IP_SERVICE, */ +/* BTM_EIR_UUID_SERVCLASS_ESDP_UPNP_IP_PAN, */ +/* BTM_EIR_UUID_SERVCLASS_ESDP_UPNP_IP_LAP, */ +/* BTM_EIR_UUID_SERVCLASS_ESDP_UPNP_IP_L2CAP, */ + BTM_EIR_UUID_SERVCLASS_VIDEO_SOURCE, + BTM_EIR_UUID_SERVCLASS_VIDEO_SINK, +/* BTM_EIR_UUID_SERVCLASS_VIDEO_DISTRIBUTION */ +/* BTM_EIR_UUID_SERVCLASS_HDP_PROFILE */ + BTM_EIR_UUID_SERVCLASS_MESSAGE_ACCESS, + BTM_EIR_UUID_SERVCLASS_MESSAGE_NOTIFICATION, + BTM_EIR_UUID_SERVCLASS_HDP_SOURCE, + BTM_EIR_UUID_SERVCLASS_HDP_SINK, + BTM_EIR_MAX_SERVICES +}; + +/* search result in EIR of inquiry database */ +#define BTM_EIR_FOUND 0 +#define BTM_EIR_NOT_FOUND 1 +#define BTM_EIR_UNKNOWN 2 + +typedef UINT8 tBTM_EIR_SEARCH_RESULT; + +#define BTM_EIR_FLAGS_TYPE HCI_EIR_FLAGS_TYPE /* 0x01 */ +#define BTM_EIR_MORE_16BITS_UUID_TYPE HCI_EIR_MORE_16BITS_UUID_TYPE /* 0x02 */ +#define BTM_EIR_COMPLETE_16BITS_UUID_TYPE HCI_EIR_COMPLETE_16BITS_UUID_TYPE /* 0x03 */ +#define BTM_EIR_MORE_32BITS_UUID_TYPE HCI_EIR_MORE_32BITS_UUID_TYPE /* 0x04 */ +#define BTM_EIR_COMPLETE_32BITS_UUID_TYPE HCI_EIR_COMPLETE_32BITS_UUID_TYPE /* 0x05 */ +#define BTM_EIR_MORE_128BITS_UUID_TYPE HCI_EIR_MORE_128BITS_UUID_TYPE /* 0x06 */ +#define BTM_EIR_COMPLETE_128BITS_UUID_TYPE HCI_EIR_COMPLETE_128BITS_UUID_TYPE /* 0x07 */ +#define BTM_EIR_SHORTENED_LOCAL_NAME_TYPE HCI_EIR_SHORTENED_LOCAL_NAME_TYPE /* 0x08 */ +#define BTM_EIR_COMPLETE_LOCAL_NAME_TYPE HCI_EIR_COMPLETE_LOCAL_NAME_TYPE /* 0x09 */ +#define BTM_EIR_TX_POWER_LEVEL_TYPE HCI_EIR_TX_POWER_LEVEL_TYPE /* 0x0A */ +#define BTM_EIR_MANUFACTURER_SPECIFIC_TYPE HCI_EIR_MANUFACTURER_SPECIFIC_TYPE /* 0xFF */ + +/* the following EIR tags are defined to OOB, not regular EIR data */ +#define BTM_EIR_OOB_BD_ADDR_TYPE HCI_EIR_OOB_BD_ADDR_TYPE /* 6 bytes */ +#define BTM_EIR_OOB_COD_TYPE HCI_EIR_OOB_COD_TYPE /* 3 bytes */ +#define BTM_EIR_OOB_SSP_HASH_C_TYPE HCI_EIR_OOB_SSP_HASH_C_TYPE /* 16 bytes */ +#define BTM_EIR_OOB_SSP_RAND_R_TYPE HCI_EIR_OOB_SSP_RAND_R_TYPE /* 16 bytes */ + +#define BTM_OOB_MANDATORY_SIZE 8 /* include 2 bytes length & 6 bytes bd_addr */ +#define BTM_OOB_DATA_LEN_SIZE 2 +#define BTM_OOB_BD_ADDR_SIZE 6 +#define BTM_OOB_COD_SIZE BT_OOB_COD_SIZE +#define BTM_OOB_HASH_C_SIZE BT_OOB_HASH_C_SIZE +#define BTM_OOB_RAND_R_SIZE BT_OOB_RAND_R_SIZE + + +#if BLE_INCLUDED == TRUE +#define BTM_BLE_SEC_NONE 0 +#define BTM_BLE_SEC_ENCRYPT 1 /* encrypt the link using current key */ +#define BTM_BLE_SEC_ENCRYPT_NO_MITM 2 +#define BTM_BLE_SEC_ENCRYPT_MITM 3 +typedef UINT8 tBTM_BLE_SEC_ACT; +#endif +/************************************************************************************************ +** BTM Services MACROS handle array of UINT32 bits for more than 32 services +*************************************************************************************************/ +/* Determine the number of UINT32's necessary for services */ +#define BTM_EIR_ARRAY_BITS 32 /* Number of bits in each array element */ +#define BTM_EIR_SERVICE_ARRAY_SIZE (((UINT32)BTM_EIR_MAX_SERVICES / BTM_EIR_ARRAY_BITS) + \ + (((UINT32)BTM_EIR_MAX_SERVICES % BTM_EIR_ARRAY_BITS) ? 1 : 0)) + +/* MACRO to set the service bit mask in a bit stream */ +#define BTM_EIR_SET_SERVICE(p, service) (((UINT32 *)(p))[(((UINT32)(service)) / BTM_EIR_ARRAY_BITS)] |= \ + ((UINT32)1 << (((UINT32)(service)) % BTM_EIR_ARRAY_BITS))) + + +/* MACRO to clear the service bit mask in a bit stream */ +#define BTM_EIR_CLR_SERVICE(p, service) (((UINT32 *)(p))[(((UINT32)(service)) / BTM_EIR_ARRAY_BITS)] &= \ + ~((UINT32)1 << (((UINT32)(service)) % BTM_EIR_ARRAY_BITS))) + +/* MACRO to check the service bit mask in a bit stream */ +#define BTM_EIR_HAS_SERVICE(p, service) ((((UINT32 *)(p))[(((UINT32)(service)) / BTM_EIR_ARRAY_BITS)] & \ + ((UINT32)1 << (((UINT32)(service)) % BTM_EIR_ARRAY_BITS))) >> (((UINT32)(service)) % BTM_EIR_ARRAY_BITS)) + +/* start of EIR in HCI buffer, 4 bytes = HCI Command(2) + Length(1) + FEC_Req(1) */ +#define BTM_HCI_EIR_OFFSET (BT_HDR_SIZE + 4) + +/*************************** +** Device Discovery Types +****************************/ +/* Definitions of the parameters passed to BTM_StartInquiry and +** BTM_SetPeriodicInquiryMode. +*/ +typedef struct /* contains the two device class condition fields */ +{ + DEV_CLASS dev_class; + DEV_CLASS dev_class_mask; +} tBTM_COD_COND; + + +typedef union /* contains the inquiry filter condition */ +{ + BD_ADDR bdaddr_cond; + tBTM_COD_COND cod_cond; +} tBTM_INQ_FILT_COND; + + +typedef struct /* contains the parameters passed to the inquiry functions */ +{ + UINT8 mode; /* general or limited */ + UINT8 duration; /* duration of the inquiry (1.28 sec increments) */ + UINT8 max_resps; /* maximum number of responses to return */ + BOOLEAN report_dup; /* report duplicated inquiry response with higher RSSI value */ + UINT8 filter_cond_type; /* new devices, BD ADDR, COD, or No filtering */ + tBTM_INQ_FILT_COND filter_cond; /* filter value based on filter cond type */ +#if (defined(BTA_HOST_INTERLEAVE_SEARCH) && BTA_HOST_INTERLEAVE_SEARCH == TRUE) + UINT8 intl_duration[4]; /*duration array storing the interleave scan's time portions*/ +#endif +} tBTM_INQ_PARMS; + +#define BTM_INQ_RESULT_BR 0x01 +#define BTM_INQ_RESULT_BLE 0x02 + +#if (BLE_INCLUDED == TRUE) +#define BTM_BLE_EVT_CONN_ADV 0x00 +#define BTM_BLE_EVT_CONN_DIR_ADV 0x01 +#define BTM_BLE_EVT_DISC_ADV 0x02 +#define BTM_BLE_EVT_NON_CONN_ADV 0x03 +#define BTM_BLE_EVT_SCAN_RSP 0x04 +typedef UINT8 tBTM_BLE_EVT_TYPE; +#endif + +/* These are the fields returned in each device's response to the inquiry. It +** is returned in the results callback if registered. +*/ +typedef struct +{ + UINT16 clock_offset; + BD_ADDR remote_bd_addr; + DEV_CLASS dev_class; + UINT8 page_scan_rep_mode; + UINT8 page_scan_per_mode; + UINT8 page_scan_mode; + INT8 rssi; /* Set to BTM_INQ_RES_IGNORE_RSSI if not valid */ + UINT32 eir_uuid[BTM_EIR_SERVICE_ARRAY_SIZE]; + BOOLEAN eir_complete_list; +#if (BLE_INCLUDED == TRUE) + tBT_DEVICE_TYPE device_type; + UINT8 inq_result_type; + UINT8 ble_addr_type; + tBTM_BLE_EVT_TYPE ble_evt_type; + UINT8 flag; +#endif +} tBTM_INQ_RESULTS; + + +/* This is the inquiry response information held in its database by BTM, and available +** to applications via BTM_InqDbRead, BTM_InqDbFirst, and BTM_InqDbNext. +*/ +typedef struct +{ + tBTM_INQ_RESULTS results; + + BOOLEAN appl_knows_rem_name; /* set by application if it knows the remote name of the peer device. + This is later used by application to determine if remote name request is + required to be done. Having the flag here avoid duplicate store of inquiry results */ +#if ( BLE_INCLUDED == TRUE) + UINT16 remote_name_len; + tBTM_BD_NAME remote_name; + UINT8 remote_name_state; + UINT8 remote_name_type; +#endif + +} tBTM_INQ_INFO; + + +/* Structure returned with inquiry complete callback */ +typedef struct +{ + tBTM_STATUS status; + UINT8 num_resp; /* Number of results from the current inquiry */ +} tBTM_INQUIRY_CMPL; + + +/* Structure returned with remote name request */ +typedef struct +{ + UINT16 status; + BD_ADDR bd_addr; + UINT16 length; + BD_NAME remote_bd_name; +} tBTM_REMOTE_DEV_NAME; + +typedef struct +{ + UINT8 pcm_intf_rate; /* PCM interface rate: 0: 128kbps, 1: 256 kbps; + 2:512 bps; 3: 1024kbps; 4: 2048kbps */ + UINT8 frame_type; /* frame type: 0: short; 1: long */ + UINT8 sync_mode; /* sync mode: 0: slave; 1: master */ + UINT8 clock_mode; /* clock mode: 0: slave; 1: master */ + +}tBTM_SCO_PCM_PARAM; + +/**************************************** +** Device Discovery Callback Functions +*****************************************/ +/* Callback function for asynchronous notifications when the BTM inquiry DB +** changes. First param is inquiry database, second is if added to or removed +** from the inquiry database. +*/ +typedef void (tBTM_INQ_DB_CHANGE_CB) (void *p1, BOOLEAN is_new); + +/* Callback function for notifications when the BTM gets inquiry response. +** First param is inquiry results database, second is pointer of EIR. +*/ +typedef void (tBTM_INQ_RESULTS_CB) (tBTM_INQ_RESULTS *p_inq_results, UINT8 *p_eir); + +/***************************************************************************** +** ACL CHANNEL MANAGEMENT +*****************************************************************************/ +/****************** +** ACL Constants +*******************/ + +/* ACL modes */ +#define BTM_ACL_MODE_NORMAL HCI_MODE_ACTIVE +#define BTM_ACL_MODE_HOLD HCI_MODE_HOLD +#define BTM_ACL_MODE_SNIFF HCI_MODE_SNIFF +#define BTM_ACL_MODE_PARK HCI_MODE_PARK + +/* Returned with structure in role switch callback (tBTM_ROLE_SWITCH_CMPL) */ +#define BTM_ROLE_MASTER HCI_ROLE_MASTER +#define BTM_ROLE_SLAVE HCI_ROLE_SLAVE +#define BTM_ROLE_UNDEFINED 0xff /* undefined value (error status) */ + +/* ACL Packet Types */ +#define BTM_ACL_PKT_TYPES_MASK_DM1 HCI_PKT_TYPES_MASK_DM1 +#define BTM_ACL_PKT_TYPES_MASK_DH1 HCI_PKT_TYPES_MASK_DH1 +#define BTM_ACL_PKT_TYPES_MASK_DM3 HCI_PKT_TYPES_MASK_DM3 +#define BTM_ACL_PKT_TYPES_MASK_DH3 HCI_PKT_TYPES_MASK_DH3 +#define BTM_ACL_PKT_TYPES_MASK_DM5 HCI_PKT_TYPES_MASK_DM5 +#define BTM_ACL_PKT_TYPES_MASK_DH5 HCI_PKT_TYPES_MASK_DH5 +#define BTM_ACL_PKT_TYPES_MASK_NO_2_DH1 HCI_PKT_TYPES_MASK_NO_2_DH1 +#define BTM_ACL_PKT_TYPES_MASK_NO_3_DH1 HCI_PKT_TYPES_MASK_NO_3_DH1 +#define BTM_ACL_PKT_TYPES_MASK_NO_2_DH3 HCI_PKT_TYPES_MASK_NO_2_DH3 +#define BTM_ACL_PKT_TYPES_MASK_NO_3_DH3 HCI_PKT_TYPES_MASK_NO_3_DH3 +#define BTM_ACL_PKT_TYPES_MASK_NO_2_DH5 HCI_PKT_TYPES_MASK_NO_2_DH5 +#define BTM_ACL_PKT_TYPES_MASK_NO_3_DH5 HCI_PKT_TYPES_MASK_NO_3_DH5 + +/*************** +** ACL Types +****************/ + +/* Structure returned with Role Switch information (in tBTM_CMPL_CB callback function) +** in response to BTM_SwitchRole call. +*/ +typedef struct +{ + UINT8 hci_status; /* HCI status returned with the event */ + UINT8 role; /* BTM_ROLE_MASTER or BTM_ROLE_SLAVE */ + BD_ADDR remote_bd_addr; /* Remote BD addr involved with the switch */ +} tBTM_ROLE_SWITCH_CMPL; + +/* Structure returned with QoS information (in tBTM_CMPL_CB callback function) +** in response to BTM_SetQoS call. +*/ +typedef struct +{ + FLOW_SPEC flow; + UINT16 handle; + UINT8 status; +} tBTM_QOS_SETUP_CMPL; + + +/* Structure returned with read RSSI event (in tBTM_CMPL_CB callback function) +** in response to BTM_ReadRSSI call. +*/ +typedef struct +{ + tBTM_STATUS status; + UINT8 hci_status; + INT8 rssi; + BD_ADDR rem_bda; +} tBTM_RSSI_RESULTS; + +/* Structure returned with read current TX power event (in tBTM_CMPL_CB callback function) +** in response to BTM_ReadTxPower call. +*/ +typedef struct +{ + tBTM_STATUS status; + UINT8 hci_status; + INT8 tx_power; + BD_ADDR rem_bda; +} tBTM_TX_POWER_RESULTS; + +/* Structure returned with read link quality event (in tBTM_CMPL_CB callback function) +** in response to BTM_ReadLinkQuality call. +*/ +typedef struct +{ + tBTM_STATUS status; + UINT8 hci_status; + UINT8 link_quality; + BD_ADDR rem_bda; +} tBTM_LINK_QUALITY_RESULTS; + +/* Structure returned with read inq tx power quality event (in tBTM_CMPL_CB callback function) +** in response to BTM_ReadInquiryRspTxPower call. +*/ +typedef struct +{ + tBTM_STATUS status; + UINT8 hci_status; + INT8 tx_power; +} tBTM_INQ_TXPWR_RESULTS; + +enum +{ + BTM_BL_CONN_EVT, + BTM_BL_DISCN_EVT, + BTM_BL_UPDATE_EVT, + BTM_BL_ROLE_CHG_EVT, + BTM_BL_COLLISION_EVT +}; +typedef UINT8 tBTM_BL_EVENT; +typedef UINT16 tBTM_BL_EVENT_MASK; + +#define BTM_BL_CONN_MASK 0x0001 +#define BTM_BL_DISCN_MASK 0x0002 +#define BTM_BL_UPDATE_MASK 0x0004 +#define BTM_BL_ROLE_CHG_MASK 0x0008 + +/* Device features mask definitions */ +#define BTM_FEATURE_BYTES_PER_PAGE HCI_FEATURE_BYTES_PER_PAGE +#define BTM_EXT_FEATURES_PAGE_MAX HCI_EXT_FEATURES_PAGE_MAX + +/* the data type associated with BTM_BL_CONN_EVT */ +typedef struct +{ + tBTM_BL_EVENT event; /* The event reported. */ + BD_ADDR_PTR p_bda; /* The address of the newly connected device */ + DEV_CLASS_PTR p_dc; /* The device class */ + BD_NAME_PTR p_bdn; /* The device name */ + UINT8 *p_features; /* pointer to the remote device's features page[0] (supported features page) */ +#if BLE_INCLUDED == TRUE + UINT16 handle; /* connection handle */ + tBT_TRANSPORT transport; /* link is LE or not */ +#endif +} tBTM_BL_CONN_DATA; + +/* the data type associated with BTM_BL_DISCN_EVT */ +typedef struct +{ + tBTM_BL_EVENT event; /* The event reported. */ + BD_ADDR_PTR p_bda; /* The address of the disconnected device */ +#if BLE_INCLUDED == TRUE + UINT16 handle; /* disconnected connection handle */ + tBT_TRANSPORT transport; /* link is LE link or not */ +#endif +} tBTM_BL_DISCN_DATA; + +/* Busy-Level shall have the inquiry_paging mask set when + * inquiry/paging is in progress, Else the number of ACL links */ +#define BTM_BL_INQUIRY_PAGING_MASK 0x10 +#define BTM_BL_INQUIRY_STARTED (BTM_BL_INQUIRY_PAGING_MASK | 0x1) +#define BTM_BL_INQUIRY_CANCELLED (BTM_BL_INQUIRY_PAGING_MASK | 0x2) +#define BTM_BL_INQUIRY_COMPLETE (BTM_BL_INQUIRY_PAGING_MASK | 0x3) +#define BTM_BL_PAGING_STARTED (BTM_BL_INQUIRY_PAGING_MASK | 0x4) +#define BTM_BL_PAGING_COMPLETE (BTM_BL_INQUIRY_PAGING_MASK | 0x5) +/* the data type associated with BTM_BL_UPDATE_EVT */ +typedef struct +{ + tBTM_BL_EVENT event; /* The event reported. */ + UINT8 busy_level;/* when paging or inquiring, level is 10. + * Otherwise, the number of ACL links. */ + UINT8 busy_level_flags; /* Notifies actual inquiry/page activities */ +} tBTM_BL_UPDATE_DATA; + +/* the data type associated with BTM_BL_ROLE_CHG_EVT */ +typedef struct +{ + tBTM_BL_EVENT event; /* The event reported. */ + BD_ADDR_PTR p_bda; /* The address of the peer connected device */ + UINT8 new_role; + UINT8 hci_status; /* HCI status returned with the event */ +} tBTM_BL_ROLE_CHG_DATA; + +typedef union +{ + tBTM_BL_EVENT event; /* The event reported. */ + tBTM_BL_CONN_DATA conn; /* The data associated with BTM_BL_CONN_EVT */ + tBTM_BL_DISCN_DATA discn; /* The data associated with BTM_BL_DISCN_EVT */ + tBTM_BL_UPDATE_DATA update; /* The data associated with BTM_BL_UPDATE_EVT */ + tBTM_BL_ROLE_CHG_DATA role_chg;/*The data associated with BTM_BL_ROLE_CHG_EVT */ +} tBTM_BL_EVENT_DATA; + +/* Callback function for notifications when the BTM busy level +** changes. +*/ +typedef void (tBTM_BL_CHANGE_CB) (tBTM_BL_EVENT_DATA *p_data); + +/*************************** +** ACL Callback Functions +****************************/ +/* Callback function for notifications when the BTM ACL connection DB +** changes. First param is BD address, second is if added or removed. +** Registered through BTM_AclRegisterForChanges call. +*/ +#if BLE_INCLUDED == TRUE +typedef void (tBTM_ACL_DB_CHANGE_CB) (BD_ADDR p_bda, DEV_CLASS p_dc, + BD_NAME p_bdn, UINT8 *features, + BOOLEAN is_new, UINT16 handle, + tBT_TRANSPORT transport); +#else +typedef void (tBTM_ACL_DB_CHANGE_CB) (BD_ADDR p_bda, DEV_CLASS p_dc, + BD_NAME p_bdn, UINT8 *features, + BOOLEAN is_new); +#endif +/***************************************************************************** +** SCO CHANNEL MANAGEMENT +*****************************************************************************/ +/****************** +** SCO Constants +*******************/ + +/* Define an invalid SCO index and an invalid HCI handle */ +#define BTM_INVALID_SCO_INDEX 0xFFFF +#define BTM_INVALID_HCI_HANDLE 0xFFFF + +/* Define an invalid SCO disconnect reason */ +#define BTM_INVALID_SCO_DISC_REASON 0xFFFF + +/* Define first active SCO index */ +#define BTM_FIRST_ACTIVE_SCO_INDEX BTM_MAX_SCO_LINKS + +/* Define SCO packet types used in APIs */ +#define BTM_SCO_PKT_TYPES_MASK_HV1 HCI_ESCO_PKT_TYPES_MASK_HV1 +#define BTM_SCO_PKT_TYPES_MASK_HV2 HCI_ESCO_PKT_TYPES_MASK_HV2 +#define BTM_SCO_PKT_TYPES_MASK_HV3 HCI_ESCO_PKT_TYPES_MASK_HV3 +#define BTM_SCO_PKT_TYPES_MASK_EV3 HCI_ESCO_PKT_TYPES_MASK_EV3 +#define BTM_SCO_PKT_TYPES_MASK_EV4 HCI_ESCO_PKT_TYPES_MASK_EV4 +#define BTM_SCO_PKT_TYPES_MASK_EV5 HCI_ESCO_PKT_TYPES_MASK_EV5 +#define BTM_SCO_PKT_TYPES_MASK_NO_2_EV3 HCI_ESCO_PKT_TYPES_MASK_NO_2_EV3 +#define BTM_SCO_PKT_TYPES_MASK_NO_3_EV3 HCI_ESCO_PKT_TYPES_MASK_NO_3_EV3 +#define BTM_SCO_PKT_TYPES_MASK_NO_2_EV5 HCI_ESCO_PKT_TYPES_MASK_NO_2_EV5 +#define BTM_SCO_PKT_TYPES_MASK_NO_3_EV5 HCI_ESCO_PKT_TYPES_MASK_NO_3_EV5 + +#define BTM_SCO_LINK_ONLY_MASK (BTM_SCO_PKT_TYPES_MASK_HV1 | \ + BTM_SCO_PKT_TYPES_MASK_HV2 | \ + BTM_SCO_PKT_TYPES_MASK_HV3) + +#define BTM_ESCO_LINK_ONLY_MASK (BTM_SCO_PKT_TYPES_MASK_EV3 | \ + BTM_SCO_PKT_TYPES_MASK_EV4 | \ + BTM_SCO_PKT_TYPES_MASK_EV5) + +#define BTM_SCO_LINK_ALL_PKT_MASK (BTM_SCO_LINK_ONLY_MASK | \ + BTM_ESCO_LINK_ONLY_MASK) + +#define BTM_VALID_SCO_ALL_PKT_TYPE HCI_VALID_SCO_ALL_PKT_TYPE + +/* Passed in BTM_CreateSco if the packet type parameter should be ignored */ +#define BTM_IGNORE_SCO_PKT_TYPE 0 + +/*************** +** SCO Types +****************/ +#define BTM_LINK_TYPE_SCO HCI_LINK_TYPE_SCO +#define BTM_LINK_TYPE_ESCO HCI_LINK_TYPE_ESCO +typedef UINT8 tBTM_SCO_TYPE; + + +/******************* +** SCO Routing Path +********************/ +#define BTM_SCO_ROUTE_PCM HCI_BRCM_SCO_ROUTE_PCM +#define BTM_SCO_ROUTE_HCI HCI_BRCM_SCO_ROUTE_HCI +typedef UINT8 tBTM_SCO_ROUTE_TYPE; + + +/******************* +** SCO Codec Types +********************/ +// TODO(google) This should use common definitions +// in hci/include/hci_audio.h +#define BTM_SCO_CODEC_NONE 0x0000 +#define BTM_SCO_CODEC_CVSD 0x0001 +#define BTM_SCO_CODEC_MSBC 0x0002 +typedef UINT16 tBTM_SCO_CODEC_TYPE; + + + +/******************* +** SCO Air Mode Types +********************/ +#define BTM_SCO_AIR_MODE_U_LAW 0 +#define BTM_SCO_AIR_MODE_A_LAW 1 +#define BTM_SCO_AIR_MODE_CVSD 2 +#define BTM_SCO_AIR_MODE_TRANSPNT 3 +typedef UINT8 tBTM_SCO_AIR_MODE_TYPE; + +/******************* +** SCO Voice Settings +********************/ +#define BTM_VOICE_SETTING_CVSD ((UINT16) (HCI_INP_CODING_LINEAR | \ + HCI_INP_DATA_FMT_2S_COMPLEMENT | \ + HCI_INP_SAMPLE_SIZE_16BIT | \ + HCI_AIR_CODING_FORMAT_CVSD)) + +#define BTM_VOICE_SETTING_TRANS ((UINT16) (HCI_INP_CODING_LINEAR | \ + HCI_INP_DATA_FMT_2S_COMPLEMENT | \ + HCI_INP_SAMPLE_SIZE_16BIT | \ + HCI_AIR_CODING_FORMAT_TRANSPNT)) + +/******************* +** SCO Data Status +********************/ +enum +{ + BTM_SCO_DATA_CORRECT, + BTM_SCO_DATA_PAR_ERR, + BTM_SCO_DATA_NONE, + BTM_SCO_DATA_PAR_LOST +}; +typedef UINT8 tBTM_SCO_DATA_FLAG; + +/*************************** +** SCO Callback Functions +****************************/ +typedef void (tBTM_SCO_CB) (UINT16 sco_inx); +typedef void (tBTM_SCO_DATA_CB) (UINT16 sco_inx, BT_HDR *p_data, tBTM_SCO_DATA_FLAG status); + +/****************** +** eSCO Constants +*******************/ +#define BTM_64KBITS_RATE 0x00001f40 /* 64 kbits/sec data rate */ + +/* Retransmission effort */ +#define BTM_ESCO_RETRANS_OFF 0 +#define BTM_ESCO_RETRANS_POWER 1 +#define BTM_ESCO_RETRANS_QUALITY 2 +#define BTM_ESCO_RETRANS_DONTCARE 0xff + +/* Max Latency Don't Care */ +#define BTM_ESCO_MAX_LAT_DONTCARE 0xffff + +/*************** +** eSCO Types +****************/ +/* tBTM_ESCO_CBACK event types */ +#define BTM_ESCO_CHG_EVT 1 +#define BTM_ESCO_CONN_REQ_EVT 2 +typedef UINT8 tBTM_ESCO_EVT; + +/* Passed into BTM_SetEScoMode() */ +typedef struct +{ + UINT32 tx_bw; + UINT32 rx_bw; + UINT16 max_latency; + UINT16 voice_contfmt; /* Voice Settings or Content Format */ + UINT16 packet_types; + UINT8 retrans_effort; +} tBTM_ESCO_PARAMS; + +typedef struct +{ + UINT16 max_latency; + UINT16 packet_types; + UINT8 retrans_effort; +} tBTM_CHG_ESCO_PARAMS; + +/* Returned by BTM_ReadEScoLinkParms() */ +typedef struct +{ + UINT16 rx_pkt_len; + UINT16 tx_pkt_len; + BD_ADDR bd_addr; + UINT8 link_type; /* BTM_LINK_TYPE_SCO or BTM_LINK_TYPE_ESCO */ + UINT8 tx_interval; + UINT8 retrans_window; + UINT8 air_mode; +} tBTM_ESCO_DATA; + +typedef struct +{ + UINT16 sco_inx; + UINT16 rx_pkt_len; + UINT16 tx_pkt_len; + BD_ADDR bd_addr; + UINT8 hci_status; + UINT8 tx_interval; + UINT8 retrans_window; +} tBTM_CHG_ESCO_EVT_DATA; + +typedef struct +{ + UINT16 sco_inx; + BD_ADDR bd_addr; + DEV_CLASS dev_class; + tBTM_SCO_TYPE link_type; +} tBTM_ESCO_CONN_REQ_EVT_DATA; + +typedef union +{ + tBTM_CHG_ESCO_EVT_DATA chg_evt; + tBTM_ESCO_CONN_REQ_EVT_DATA conn_evt; +} tBTM_ESCO_EVT_DATA; + +/*************************** +** eSCO Callback Functions +****************************/ +typedef void (tBTM_ESCO_CBACK) (tBTM_ESCO_EVT event, tBTM_ESCO_EVT_DATA *p_data); + + +/***************************************************************************** +** SECURITY MANAGEMENT +*****************************************************************************/ +/******************************* +** Security Manager Constants +********************************/ + +/* Security Mode (BTM_SetSecurityMode) */ +#define BTM_SEC_MODE_UNDEFINED 0 +#define BTM_SEC_MODE_NONE 1 +#define BTM_SEC_MODE_SERVICE 2 +#define BTM_SEC_MODE_LINK 3 +#define BTM_SEC_MODE_SP 4 +#define BTM_SEC_MODE_SP_DEBUG 5 +#define BTM_SEC_MODE_SC 6 + +/* Maximum Number of BTM Security Modes */ +#define BTM_SEC_MODES_MAX 7 + +/* Security Service Levels [bit mask] (BTM_SetSecurityLevel) +** Encryption should not be used without authentication +*/ +#define BTM_SEC_NONE 0x0000 /* Nothing required */ +#define BTM_SEC_IN_AUTHORIZE 0x0001 /* Inbound call requires authorization */ +#define BTM_SEC_IN_AUTHENTICATE 0x0002 /* Inbound call requires authentication */ +#define BTM_SEC_IN_ENCRYPT 0x0004 /* Inbound call requires encryption */ +#define BTM_SEC_OUT_AUTHORIZE 0x0008 /* Outbound call requires authorization */ +#define BTM_SEC_OUT_AUTHENTICATE 0x0010 /* Outbound call requires authentication */ +#define BTM_SEC_OUT_ENCRYPT 0x0020 /* Outbound call requires encryption */ +#define BTM_SEC_MODE4_LEVEL4 0x0040 /* Secure Connections Only Mode */ +#define BTM_SEC_FORCE_MASTER 0x0100 /* Need to switch connection to be master */ +#define BTM_SEC_ATTEMPT_MASTER 0x0200 /* Try to switch connection to be master */ +#define BTM_SEC_FORCE_SLAVE 0x0400 /* Need to switch connection to be master */ +#define BTM_SEC_ATTEMPT_SLAVE 0x0800 /* Try to switch connection to be slave */ +#define BTM_SEC_IN_MITM 0x1000 /* inbound Do man in the middle protection */ +#define BTM_SEC_OUT_MITM 0x2000 /* outbound Do man in the middle protection */ +#define BTM_SEC_IN_MIN_16_DIGIT_PIN 0x4000 /* enforce a minimum of 16 digit for sec mode 2 */ + +/* Security Flags [bit mask] (BTM_GetSecurityFlags) +*/ +#define BTM_SEC_FLAG_AUTHORIZED 0x01 +#define BTM_SEC_FLAG_AUTHENTICATED 0x02 +#define BTM_SEC_FLAG_ENCRYPTED 0x04 +#define BTM_SEC_FLAG_LKEY_KNOWN 0x10 +#define BTM_SEC_FLAG_LKEY_AUTHED 0x20 + +/* PIN types */ +#define BTM_PIN_TYPE_VARIABLE HCI_PIN_TYPE_VARIABLE +#define BTM_PIN_TYPE_FIXED HCI_PIN_TYPE_FIXED + +/* Link Key types used to generate the new link key. +** returned in link key notification callback function +*/ +#define BTM_LKEY_TYPE_COMBINATION HCI_LKEY_TYPE_COMBINATION +#define BTM_LKEY_TYPE_LOCAL_UNIT HCI_LKEY_TYPE_LOCAL_UNIT +#define BTM_LKEY_TYPE_REMOTE_UNIT HCI_LKEY_TYPE_REMOTE_UNIT +#define BTM_LKEY_TYPE_DEBUG_COMB HCI_LKEY_TYPE_DEBUG_COMB +#define BTM_LKEY_TYPE_UNAUTH_COMB HCI_LKEY_TYPE_UNAUTH_COMB +#define BTM_LKEY_TYPE_AUTH_COMB HCI_LKEY_TYPE_AUTH_COMB +#define BTM_LKEY_TYPE_CHANGED_COMB HCI_LKEY_TYPE_CHANGED_COMB + +#define BTM_LKEY_TYPE_UNAUTH_COMB_P_256 HCI_LKEY_TYPE_UNAUTH_COMB_P_256 +#define BTM_LKEY_TYPE_AUTH_COMB_P_256 HCI_LKEY_TYPE_AUTH_COMB_P_256 + +#define BTM_LTK_DERIVED_LKEY_OFFSET 0x20 /* "easy" requirements for LK derived from LTK */ +#define BTM_LKEY_TYPE_IGNORE 0xff /* used when event is response from + hci return link keys request */ + +typedef UINT8 tBTM_LINK_KEY_TYPE; + +/* Protocol level security (BTM_SetSecurityLevel) */ +#define BTM_SEC_PROTO_L2CAP 0 +#define BTM_SEC_PROTO_SDP 1 +#define BTM_SEC_PROTO_TCS 2 +#define BTM_SEC_PROTO_RFCOMM 3 +#define BTM_SEC_PROTO_OBEX 4 +#define BTM_SEC_PROTO_BNEP 5 +#define BTM_SEC_PROTO_HID 6 /* HID */ +#define BTM_SEC_PROTO_AVDT 7 +#define BTM_SEC_PROTO_MCA 8 + +/* Determine the number of UINT32's necessary for security services */ +#define BTM_SEC_ARRAY_BITS 32 /* Number of bits in each array element */ +#define BTM_SEC_SERVICE_ARRAY_SIZE (((UINT32)BTM_SEC_MAX_SERVICES / BTM_SEC_ARRAY_BITS) + \ + (((UINT32)BTM_SEC_MAX_SERVICES % BTM_SEC_ARRAY_BITS) ? 1 : 0)) + +/* Security service definitions (BTM_SetSecurityLevel) +** Used for Authorization APIs +*/ +#define BTM_SEC_SERVICE_SDP_SERVER 0 +#define BTM_SEC_SERVICE_SERIAL_PORT 1 +#define BTM_SEC_SERVICE_LAN_ACCESS 2 +#define BTM_SEC_SERVICE_DUN 3 +#define BTM_SEC_SERVICE_IRMC_SYNC 4 +#define BTM_SEC_SERVICE_IRMC_SYNC_CMD 5 +#define BTM_SEC_SERVICE_OBEX 6 +#define BTM_SEC_SERVICE_OBEX_FTP 7 +#define BTM_SEC_SERVICE_HEADSET 8 +#define BTM_SEC_SERVICE_CORDLESS 9 +#define BTM_SEC_SERVICE_INTERCOM 10 +#define BTM_SEC_SERVICE_FAX 11 +#define BTM_SEC_SERVICE_HEADSET_AG 12 +#define BTM_SEC_SERVICE_PNP_INFO 13 +#define BTM_SEC_SERVICE_GEN_NET 14 +#define BTM_SEC_SERVICE_GEN_FILE 15 +#define BTM_SEC_SERVICE_GEN_AUDIO 16 +#define BTM_SEC_SERVICE_GEN_TEL 17 +#define BTM_SEC_SERVICE_CTP_DATA 18 +#define BTM_SEC_SERVICE_HCRP_CTRL 19 +#define BTM_SEC_SERVICE_HCRP_DATA 20 +#define BTM_SEC_SERVICE_HCRP_NOTIF 21 +#define BTM_SEC_SERVICE_BPP_JOB 22 +#define BTM_SEC_SERVICE_BPP_STATUS 23 +#define BTM_SEC_SERVICE_BPP_REF 24 +#define BTM_SEC_SERVICE_BNEP_PANU 25 +#define BTM_SEC_SERVICE_BNEP_GN 26 +#define BTM_SEC_SERVICE_BNEP_NAP 27 +#define BTM_SEC_SERVICE_HF_HANDSFREE 28 +#define BTM_SEC_SERVICE_AG_HANDSFREE 29 +#define BTM_SEC_SERVICE_TE_PHONE_ACCESS 30 +#define BTM_SEC_SERVICE_ME_PHONE_ACCESS 31 + +#define BTM_SEC_SERVICE_HIDH_SEC_CTRL 32 +#define BTM_SEC_SERVICE_HIDH_NOSEC_CTRL 33 +#define BTM_SEC_SERVICE_HIDH_INTR 34 +#define BTM_SEC_SERVICE_BIP 35 +#define BTM_SEC_SERVICE_BIP_REF 36 +#define BTM_SEC_SERVICE_AVDTP 37 +#define BTM_SEC_SERVICE_AVDTP_NOSEC 38 +#define BTM_SEC_SERVICE_AVCTP 39 +#define BTM_SEC_SERVICE_SAP 40 +#define BTM_SEC_SERVICE_PBAP 41 +#define BTM_SEC_SERVICE_RFC_MUX 42 +#define BTM_SEC_SERVICE_AVCTP_BROWSE 43 +#define BTM_SEC_SERVICE_MAP 44 +#define BTM_SEC_SERVICE_MAP_NOTIF 45 +#define BTM_SEC_SERVICE_MCAP_CTRL 46 +#define BTM_SEC_SERVICE_MCAP_DATA 47 +#define BTM_SEC_SERVICE_HDP_SNK 48 +#define BTM_SEC_SERVICE_HDP_SRC 49 +#define BTM_SEC_SERVICE_ATT 50 + +/* Update these as services are added */ +#define BTM_SEC_SERVICE_FIRST_EMPTY 51 + +#ifndef BTM_SEC_MAX_SERVICES +#define BTM_SEC_MAX_SERVICES 65 +#endif + +/************************************************************************************************ +** Security Services MACROS handle array of UINT32 bits for more than 32 trusted services +*************************************************************************************************/ +/* MACRO to set the security service bit mask in a bit stream */ +#define BTM_SEC_SET_SERVICE(p, service) (((UINT32 *)(p))[(((UINT32)(service)) / BTM_SEC_ARRAY_BITS)] |= \ + ((UINT32)1 << (((UINT32)(service)) % BTM_SEC_ARRAY_BITS))) + + +/* MACRO to clear the security service bit mask in a bit stream */ +#define BTM_SEC_CLR_SERVICE(p, service) (((UINT32 *)(p))[(((UINT32)(service)) / BTM_SEC_ARRAY_BITS)] &= \ + ~((UINT32)1 << (((UINT32)(service)) % BTM_SEC_ARRAY_BITS))) + +/* MACRO to check the security service bit mask in a bit stream (Returns TRUE or FALSE) */ +#define BTM_SEC_IS_SERVICE_TRUSTED(p, service) (((((UINT32 *)(p))[(((UINT32)(service)) / BTM_SEC_ARRAY_BITS)]) & \ + (UINT32)(((UINT32)1 << (((UINT32)(service)) % BTM_SEC_ARRAY_BITS)))) ? TRUE : FALSE) + +/* MACRO to copy two trusted device bitmask */ +#define BTM_SEC_COPY_TRUSTED_DEVICE(p_src, p_dst) {UINT32 trst; for (trst = 0; trst < BTM_SEC_SERVICE_ARRAY_SIZE; trst++) \ + ((UINT32 *)(p_dst))[trst] = ((UINT32 *)(p_src))[trst];} + +/* MACRO to clear two trusted device bitmask */ +#define BTM_SEC_CLR_TRUSTED_DEVICE(p_dst) {UINT32 trst; for (trst = 0; trst < BTM_SEC_SERVICE_ARRAY_SIZE; trst++) \ + ((UINT32 *)(p_dst))[trst] = 0;} + +/* Following bits can be provided by host in the trusted_mask array */ +/* 0..31 bits of mask[0] (Least Significant Word) */ +#define BTM_SEC_TRUST_SDP_SERVER (1 << BTM_SEC_SERVICE_SDP_SERVER) +#define BTM_SEC_TRUST_SERIAL_PORT (1 << BTM_SEC_SERVICE_SERIAL_PORT) +#define BTM_SEC_TRUST_LAN_ACCESS (1 << BTM_SEC_SERVICE_LAN_ACCESS) +#define BTM_SEC_TRUST_DUN (1 << BTM_SEC_SERVICE_DUN) +#define BTM_SEC_TRUST_IRMC_SYNC (1 << BTM_SEC_SERVICE_IRMC_SYNC) +#define BTM_SEC_TRUST_IRMC_SYNC_CMD (1 << BTM_SEC_SERVICE_IRMC_SYNC_CMD) +#define BTM_SEC_TRUST_OBEX (1 << BTM_SEC_SERVICE_OBEX) +#define BTM_SEC_TRUST_OBEX_FTP (1 << BTM_SEC_SERVICE_OBEX_FTP) +#define BTM_SEC_TRUST_HEADSET (1 << BTM_SEC_SERVICE_HEADSET) +#define BTM_SEC_TRUST_CORDLESS (1 << BTM_SEC_SERVICE_CORDLESS) +#define BTM_SEC_TRUST_INTERCOM (1 << BTM_SEC_SERVICE_INTERCOM) +#define BTM_SEC_TRUST_FAX (1 << BTM_SEC_SERVICE_FAX) +#define BTM_SEC_TRUST_HEADSET_AG (1 << BTM_SEC_SERVICE_HEADSET_AG) +#define BTM_SEC_TRUST_PNP_INFO (1 << BTM_SEC_SERVICE_PNP_INFO) +#define BTM_SEC_TRUST_GEN_NET (1 << BTM_SEC_SERVICE_GEN_NET) +#define BTM_SEC_TRUST_GEN_FILE (1 << BTM_SEC_SERVICE_GEN_FILE) +#define BTM_SEC_TRUST_GEN_AUDIO (1 << BTM_SEC_SERVICE_GEN_AUDIO) +#define BTM_SEC_TRUST_GEN_TEL (1 << BTM_SEC_SERVICE_GEN_TEL) +#define BTM_SEC_TRUST_CTP_DATA (1 << BTM_SEC_SERVICE_CTP_DATA) +#define BTM_SEC_TRUST_HCRP_CTRL (1 << BTM_SEC_SERVICE_HCRP_CTRL) +#define BTM_SEC_TRUST_HCRP_DATA (1 << BTM_SEC_SERVICE_HCRP_DATA) +#define BTM_SEC_TRUST_HCRP_NOTIF (1 << BTM_SEC_SERVICE_HCRP_NOTIF) +#define BTM_SEC_TRUST_BPP_JOB (1 << BTM_SEC_SERVICE_JOB) +#define BTM_SEC_TRUST_BPP_STATUS (1 << BTM_SEC_SERVICE_STATUS) +#define BTM_SEC_TRUST_BPP_REF (1 << BTM_SEC_SERVICE_REF) +#define BTM_SEC_TRUST_BNEP_PANU (1 << BTM_SEC_SERVICE_BNEP_PANU) +#define BTM_SEC_TRUST_BNEP_GN (1 << BTM_SEC_SERVICE_BNEP_GN) +#define BTM_SEC_TRUST_BNEP_NAP (1 << BTM_SEC_SERVICE_BNEP_NAP) +#define BTM_SEC_TRUST_HFP_HF (1 << BTM_SEC_SERVICE_HF_HANDSFREE) +#define BTM_SEC_TRUST_HFP_AG (1 << BTM_SEC_SERVICE_AG_HANDSFREE) +#define BTM_SEC_TRUST_TE_PHONE_ACCESS (1 << BTM_SEC_SERVICE_TE_PHONE_ACCESS) +#define BTM_SEC_TRUST_ME_PHONE_ACCESS (1 << BTM_SEC_SERVICE_ME_PHONE_ACCESS) + +/* 0..31 bits of mask[1] (Most Significant Word) */ +#define BTM_SEC_TRUST_HIDH_CTRL (1 << (BTM_SEC_SERVICE_HIDH_SEC_CTRL - 32)) +#define BTM_SEC_TRUST_HIDH_NOSEC_CTRL (1 << (BTM_SEC_SERVICE_HIDH_NOSEC_CTRL - 32)) +#define BTM_SEC_TRUST_HIDH_INTR (1 << (BTM_SEC_SERVICE_HIDH_INTR - 32)) +#define BTM_SEC_TRUST_BIP (1 << (BTM_SEC_SERVICE_BIP - 32)) +#define BTM_SEC_TRUST_BIP_REF (1 << (BTM_SEC_SERVICE_BIP_REF - 32)) +#define BTM_SEC_TRUST_AVDTP (1 << (BTM_SEC_SERVICE_AVDTP - 32)) +#define BTM_SEC_TRUST_AVDTP_NOSEC (1 << (BTM_SEC_SERVICE_AVDTP_NOSEC - 32)) +#define BTM_SEC_TRUST_AVCTP (1 << (BTM_SEC_SERVICE_AVCTP - 32)) +#define BTM_SEC_TRUST_SAP (1 << (BTM_SEC_SERVICE_SAP - 32)) +#define BTM_SEC_TRUST_PBAP (1 << (BTM_SEC_SERVICE_PBAP - 32)) +#define BTM_SEC_TRUST_RFC_MUX (1 << (BTM_SEC_SERVICE_RFC_MUX - 32)) +#define BTM_SEC_TRUST_AVCTP_BROWSE (1 << (BTM_SEC_SERVICE_AVCTP_BROWSE - 32)) +#define BTM_SEC_TRUST_MAP (1 << (BTM_SEC_SERVICE_MAP - 32)) +#define BTM_SEC_TRUST_MAP_NOTIF (1 << (BTM_SEC_SERVICE_MAP_NOTIF - 32)) +#define BTM_SEC_TRUST_MCAP_CTRL (1 << (BTM_SEC_SERVICE_MCAP_CTRL - 32)) +#define BTM_SEC_TRUST_MCAP_DATA (1 << (BTM_SEC_SERVICE_MCAP_DATA - 32)) +#define BTM_SEC_TRUST_HDP_SNK (1 << (BTM_SEC_SERVICE_HDP_SNK - 32)) +#define BTM_SEC_TRUST_HDP_SRC (1 << (BTM_SEC_SERVICE_HDP_SRC - 32)) + +#define BTM_SEC_TRUST_ALL 0xFFFFFFFF /* for each array element */ + +/**************************************** +** Security Manager Callback Functions +*****************************************/ +/* Authorize device for service. Parameters are +** BD Address of remote +** Device Class of remote +** BD Name of remote +** Service name +** Service Id (NULL - unknown service or unused +** [BTM_SEC_SERVICE_NAME_LEN set to 0]) +** Is originator of the connection +** Result of the operation +*/ +typedef UINT8 (tBTM_AUTHORIZE_CALLBACK) (BD_ADDR bd_addr, DEV_CLASS dev_class, + tBTM_BD_NAME bd_name, UINT8 *service_name, + UINT8 service_id, BOOLEAN is_originator); + +/* Get PIN for the connection. Parameters are +** BD Address of remote +** Device Class of remote +** BD Name of remote +** Flag indicating the minimum pin code length to be 16 digits +*/ +typedef UINT8 (tBTM_PIN_CALLBACK) (BD_ADDR bd_addr, DEV_CLASS dev_class, + tBTM_BD_NAME bd_name, BOOLEAN min_16_digit); + +/* New Link Key for the connection. Parameters are +** BD Address of remote +** Link Key +** Key Type: Combination, Local Unit, or Remote Unit +*/ +typedef UINT8 (tBTM_LINK_KEY_CALLBACK) (BD_ADDR bd_addr, DEV_CLASS dev_class, + tBTM_BD_NAME bd_name, UINT8 *key, + UINT8 key_type); + + +/* Remote Name Resolved. Parameters are +** BD Address of remote +** BD Name of remote +*/ +typedef void (tBTM_RMT_NAME_CALLBACK) (BD_ADDR bd_addr, DEV_CLASS dc, + tBTM_BD_NAME bd_name); + + +/* Authentication complete for the connection. Parameters are +** BD Address of remote +** Device Class of remote +** BD Name of remote +** +*/ +typedef UINT8 (tBTM_AUTH_COMPLETE_CALLBACK) (BD_ADDR bd_addr, DEV_CLASS dev_class, + tBTM_BD_NAME bd_name, int result); + +enum +{ + BTM_SP_IO_REQ_EVT, /* received IO_CAPABILITY_REQUEST event */ + BTM_SP_IO_RSP_EVT, /* received IO_CAPABILITY_RESPONSE event */ + BTM_SP_CFM_REQ_EVT, /* received USER_CONFIRMATION_REQUEST event */ + BTM_SP_KEY_NOTIF_EVT, /* received USER_PASSKEY_NOTIFY event */ + BTM_SP_KEY_REQ_EVT, /* received USER_PASSKEY_REQUEST event */ + BTM_SP_KEYPRESS_EVT, /* received KEYPRESS_NOTIFY event */ + BTM_SP_LOC_OOB_EVT, /* received result for READ_LOCAL_OOB_DATA command */ + BTM_SP_RMT_OOB_EVT, /* received REMOTE_OOB_DATA_REQUEST event */ + BTM_SP_COMPLT_EVT, /* received SIMPLE_PAIRING_COMPLETE event */ + BTM_SP_UPGRADE_EVT /* check if the application wants to upgrade the link key */ +}; +typedef UINT8 tBTM_SP_EVT; + +#define BTM_IO_CAP_OUT 0 /* DisplayOnly */ +#define BTM_IO_CAP_IO 1 /* DisplayYesNo */ +#define BTM_IO_CAP_IN 2 /* KeyboardOnly */ +#define BTM_IO_CAP_NONE 3 /* NoInputNoOutput */ +#if BLE_INCLUDED == TRUE && SMP_INCLUDED == TRUE +#define BTM_IO_CAP_KBDISP 4 /* Keyboard display */ +#define BTM_IO_CAP_MAX 5 +#else +#define BTM_IO_CAP_MAX 4 +#endif + +typedef UINT8 tBTM_IO_CAP; + +#define BTM_MAX_PASSKEY_VAL (999999) +#define BTM_MIN_PASSKEY_VAL (0) + +#define BTM_AUTH_SP_NO 0 /* MITM Protection Not Required - Single Profile/non-bonding + Numeric comparison with automatic accept allowed */ +#define BTM_AUTH_SP_YES 1 /* MITM Protection Required - Single Profile/non-bonding + Use IO Capabilities to determine authentication procedure */ +#define BTM_AUTH_AP_NO 2 /* MITM Protection Not Required - All Profiles/dedicated bonding + Numeric comparison with automatic accept allowed */ +#define BTM_AUTH_AP_YES 3 /* MITM Protection Required - All Profiles/dedicated bonding + Use IO Capabilities to determine authentication procedure */ +#define BTM_AUTH_SPGB_NO 4 /* MITM Protection Not Required - Single Profiles/general bonding + Numeric comparison with automatic accept allowed */ +#define BTM_AUTH_SPGB_YES 5 /* MITM Protection Required - Single Profiles/general bonding + Use IO Capabilities to determine authentication procedure */ +#define BTM_AUTH_DD_BOND 2 /* this bit is ORed to the BTM_AUTH_SP_* when IO exchange for dedicated bonding */ +#define BTM_AUTH_GB_BIT 4 /* the genernal bonding bit */ +#define BTM_AUTH_BONDS 6 /* the general/dedicated bonding bits */ +#define BTM_AUTH_YN_BIT 1 /* this is the Yes or No bit */ + +#define BTM_BLE_INITIATOR_KEY_SIZE 15 +#define BTM_BLE_RESPONDER_KEY_SIZE 15 +#define BTM_BLE_MAX_KEY_SIZE 16 + +typedef UINT8 tBTM_AUTH_REQ; + +enum +{ + BTM_OOB_NONE, + BTM_OOB_PRESENT +#if BTM_OOB_INCLUDED == TRUE + ,BTM_OOB_UNKNOWN +#endif +}; +typedef UINT8 tBTM_OOB_DATA; + +/* data type for BTM_SP_IO_REQ_EVT */ +typedef struct +{ + BD_ADDR bd_addr; /* peer address */ + tBTM_IO_CAP io_cap; /* local IO capabilities */ + tBTM_OOB_DATA oob_data; /* OOB data present (locally) for the peer device */ + tBTM_AUTH_REQ auth_req; /* Authentication required (for local device) */ + BOOLEAN is_orig; /* TRUE, if local device initiated the SP process */ +} tBTM_SP_IO_REQ; + +/* data type for BTM_SP_IO_RSP_EVT */ +typedef struct +{ + BD_ADDR bd_addr; /* peer address */ + tBTM_IO_CAP io_cap; /* peer IO capabilities */ + tBTM_OOB_DATA oob_data; /* OOB data present at peer device for the local device */ + tBTM_AUTH_REQ auth_req; /* Authentication required for peer device */ +} tBTM_SP_IO_RSP; + +/* data type for BTM_SP_CFM_REQ_EVT */ +typedef struct +{ + BD_ADDR bd_addr; /* peer address */ + DEV_CLASS dev_class; /* peer CoD */ + tBTM_BD_NAME bd_name; /* peer device name */ + UINT32 num_val; /* the numeric value for comparison. If just_works, do not show this number to UI */ + BOOLEAN just_works; /* TRUE, if "Just Works" association model */ + tBTM_AUTH_REQ loc_auth_req; /* Authentication required for local device */ + tBTM_AUTH_REQ rmt_auth_req; /* Authentication required for peer device */ + tBTM_IO_CAP loc_io_caps; /* IO Capabilities of the local device */ + tBTM_IO_CAP rmt_io_caps; /* IO Capabilities of the remot device */ +} tBTM_SP_CFM_REQ; + +/* data type for BTM_SP_KEY_REQ_EVT */ +typedef struct +{ + BD_ADDR bd_addr; /* peer address */ + DEV_CLASS dev_class; /* peer CoD */ + tBTM_BD_NAME bd_name; /* peer device name */ +} tBTM_SP_KEY_REQ; + +/* data type for BTM_SP_KEY_NOTIF_EVT */ +typedef struct +{ + BD_ADDR bd_addr; /* peer address */ + DEV_CLASS dev_class; /* peer CoD */ + tBTM_BD_NAME bd_name; /* peer device name */ + UINT32 passkey; /* passkey */ +} tBTM_SP_KEY_NOTIF; + +enum +{ + BTM_SP_KEY_STARTED, /* 0 - passkey entry started */ + BTM_SP_KEY_ENTERED, /* 1 - passkey digit entered */ + BTM_SP_KEY_ERASED, /* 2 - passkey digit erased */ + BTM_SP_KEY_CLEARED, /* 3 - passkey cleared */ + BTM_SP_KEY_COMPLT, /* 4 - passkey entry completed */ + BTM_SP_KEY_OUT_OF_RANGE /* 5 - out of range */ +}; +typedef UINT8 tBTM_SP_KEY_TYPE; + +/* data type for BTM_SP_KEYPRESS_EVT */ +typedef struct +{ + BD_ADDR bd_addr; /* peer address */ + tBTM_SP_KEY_TYPE notif_type; +} tBTM_SP_KEYPRESS; + +/* data type for BTM_SP_LOC_OOB_EVT */ +typedef struct +{ + tBTM_STATUS status; /* */ + BT_OCTET16 c; /* Simple Pairing Hash C */ + BT_OCTET16 r; /* Simple Pairing Randomnizer R */ +} tBTM_SP_LOC_OOB; + +/* data type for BTM_SP_RMT_OOB_EVT */ +typedef struct +{ + BD_ADDR bd_addr; /* peer address */ + DEV_CLASS dev_class; /* peer CoD */ + tBTM_BD_NAME bd_name; /* peer device name */ +} tBTM_SP_RMT_OOB; + + +/* data type for BTM_SP_COMPLT_EVT */ +typedef struct +{ + BD_ADDR bd_addr; /* peer address */ + DEV_CLASS dev_class; /* peer CoD */ + tBTM_BD_NAME bd_name; /* peer device name */ + tBTM_STATUS status; /* status of the simple pairing process */ +} tBTM_SP_COMPLT; + +/* data type for BTM_SP_UPGRADE_EVT */ +typedef struct +{ + BD_ADDR bd_addr; /* peer address */ + BOOLEAN upgrade; /* TRUE, to upgrade the link key */ +} tBTM_SP_UPGRADE; + +typedef union +{ + tBTM_SP_IO_REQ io_req; /* BTM_SP_IO_REQ_EVT */ + tBTM_SP_IO_RSP io_rsp; /* BTM_SP_IO_RSP_EVT */ + tBTM_SP_CFM_REQ cfm_req; /* BTM_SP_CFM_REQ_EVT */ + tBTM_SP_KEY_NOTIF key_notif; /* BTM_SP_KEY_NOTIF_EVT */ + tBTM_SP_KEY_REQ key_req; /* BTM_SP_KEY_REQ_EVT */ + tBTM_SP_KEYPRESS key_press; /* BTM_SP_KEYPRESS_EVT */ + tBTM_SP_LOC_OOB loc_oob; /* BTM_SP_LOC_OOB_EVT */ + tBTM_SP_RMT_OOB rmt_oob; /* BTM_SP_RMT_OOB_EVT */ + tBTM_SP_COMPLT complt; /* BTM_SP_COMPLT_EVT */ + tBTM_SP_UPGRADE upgrade; /* BTM_SP_UPGRADE_EVT */ +} tBTM_SP_EVT_DATA; + +/* Simple Pairing Events. Called by the stack when Simple Pairing related +** events occur. +*/ +typedef UINT8 (tBTM_SP_CALLBACK) (tBTM_SP_EVT event, tBTM_SP_EVT_DATA *p_data); + + +typedef void (tBTM_MKEY_CALLBACK) (BD_ADDR bd_addr, UINT8 status, UINT8 key_flag) ; + +/* Encryption enabled/disabled complete: Optionally passed with BTM_SetEncryption. +** Parameters are +** BD Address of remote +** optional data passed in by BTM_SetEncryption +** tBTM_STATUS - result of the operation +*/ +typedef void (tBTM_SEC_CBACK) (BD_ADDR bd_addr, tBT_TRANSPORT trasnport, + void *p_ref_data, tBTM_STATUS result); + +/* Bond Cancel complete. Parameters are +** Result of the cancel operation +** +*/ +typedef void (tBTM_BOND_CANCEL_CMPL_CALLBACK) (tBTM_STATUS result); + +/* LE related event and data structure +*/ +#define BTM_LE_IO_REQ_EVT SMP_IO_CAP_REQ_EVT /* received IO_CAPABILITY_REQUEST event */ +#define BTM_LE_SEC_REQUEST_EVT SMP_SEC_REQUEST_EVT /* security request event */ +#define BTM_LE_KEY_NOTIF_EVT SMP_PASSKEY_NOTIF_EVT /* received USER_PASSKEY_NOTIFY event */ +#define BTM_LE_KEY_REQ_EVT SMP_PASSKEY_REQ_EVT /* received USER_PASSKEY_REQUEST event */ +#define BTM_LE_OOB_REQ_EVT SMP_OOB_REQ_EVT /* OOB data request event */ +#define BTM_LE_NC_REQ_EVT SMP_NC_REQ_EVT /* Numeric Comparison request event */ +#define BTM_LE_PR_KEYPR_NOT_EVT SMP_PEER_KEYPR_NOT_EVT /* Peer keypress notification recd event */ +/* SC OOB request event (both local and peer OOB data) can be expected in response */ +#define BTM_LE_SC_OOB_REQ_EVT SMP_SC_OOB_REQ_EVT +/* SC OOB local data set is created (as result of SMP_CrLocScOobData(...)) */ +#define BTM_LE_SC_LOC_OOB_EVT SMP_SC_LOC_OOB_DATA_UP_EVT +#define BTM_LE_BR_KEYS_REQ_EVT SMP_BR_KEYS_REQ_EVT /* SMP over BR keys request event */ +#define BTM_LE_COMPLT_EVT SMP_COMPLT_EVT /* SMP complete event */ +#define BTM_LE_LAST_FROM_SMP BTM_LE_BR_KEYS_REQ_EVT +#define BTM_LE_KEY_EVT BTM_LE_LAST_FROM_SMP + 1 /* KEY update event */ +typedef UINT8 tBTM_LE_EVT; + +#define BTM_LE_KEY_NONE 0 +#define BTM_LE_KEY_PENC SMP_SEC_KEY_TYPE_ENC /* encryption information of peer device */ +#define BTM_LE_KEY_PID SMP_SEC_KEY_TYPE_ID /* identity key of the peer device */ +#define BTM_LE_KEY_PCSRK SMP_SEC_KEY_TYPE_CSRK /* peer SRK */ +#define BTM_LE_KEY_PLK SMP_SEC_KEY_TYPE_LK +#define BTM_LE_KEY_LLK (SMP_SEC_KEY_TYPE_LK << 4) +#define BTM_LE_KEY_LENC (SMP_SEC_KEY_TYPE_ENC << 4) /* master role security information:div */ +#define BTM_LE_KEY_LID (SMP_SEC_KEY_TYPE_ID << 4) /* master device ID key */ +#define BTM_LE_KEY_LCSRK (SMP_SEC_KEY_TYPE_CSRK << 4) /* local CSRK has been deliver to peer */ +typedef UINT8 tBTM_LE_KEY_TYPE; + +#define BTM_LE_AUTH_REQ_NO_BOND SMP_AUTH_NO_BOND /* 0 */ +#define BTM_LE_AUTH_REQ_BOND SMP_AUTH_GEN_BOND /* 1 << 0 */ +#define BTM_LE_AUTH_REQ_MITM SMP_AUTH_YN_BIT /* 1 << 2 */ +typedef UINT8 tBTM_LE_AUTH_REQ; +#define BTM_LE_SC_SUPPORT_BIT SMP_SC_SUPPORT_BIT /* (1 << 3) */ +#define BTM_LE_KP_SUPPORT_BIT SMP_KP_SUPPORT_BIT /* (1 << 4) */ + +#define BTM_LE_AUTH_REQ_SC_ONLY SMP_AUTH_SC_ENC_ONLY /* 1 << 3 */ +#define BTM_LE_AUTH_REQ_SC_BOND SMP_AUTH_SC_GB /* 1001 */ +#define BTM_LE_AUTH_REQ_SC_MITM SMP_AUTH_SC_MITM_NB /* 1100 */ +#define BTM_LE_AUTH_REQ_SC_MITM_BOND SMP_AUTH_SC_MITM_GB /* 1101 */ +#define BTM_LE_AUTH_REQ_MASK SMP_AUTH_MASK /* 0x1D */ + +/* LE security level */ +#define BTM_LE_SEC_NONE SMP_SEC_NONE +#define BTM_LE_SEC_UNAUTHENTICATE SMP_SEC_UNAUTHENTICATE /* 1 */ +#define BTM_LE_SEC_AUTHENTICATED SMP_SEC_AUTHENTICATED /* 4 */ +typedef UINT8 tBTM_LE_SEC; + + +typedef struct +{ + tBTM_IO_CAP io_cap; /* local IO capabilities */ + UINT8 oob_data; /* OOB data present (locally) for the peer device */ + tBTM_LE_AUTH_REQ auth_req; /* Authentication request (for local device) contain bonding and MITM info */ + UINT8 max_key_size; /* max encryption key size */ + tBTM_LE_KEY_TYPE init_keys; /* keys to be distributed, bit mask */ + tBTM_LE_KEY_TYPE resp_keys; /* keys to be distributed, bit mask */ +} tBTM_LE_IO_REQ; + +#if BLE_INCLUDED == TRUE && SMP_INCLUDED == TRUE +/* data type for tBTM_LE_COMPLT */ +typedef struct +{ + UINT8 reason; + UINT8 sec_level; + BOOLEAN is_pair_cancel; + BOOLEAN smp_over_br; +}tBTM_LE_COMPLT; +#endif + +/* BLE encryption keys */ +typedef struct +{ + BT_OCTET16 ltk; + BT_OCTET8 rand; + UINT16 ediv; + UINT8 sec_level; + UINT8 key_size; +}tBTM_LE_PENC_KEYS; + +/* BLE CSRK keys */ +typedef struct +{ + UINT32 counter; + BT_OCTET16 csrk; + UINT8 sec_level; +}tBTM_LE_PCSRK_KEYS; + +/* BLE Encryption reproduction keys */ +typedef struct +{ + BT_OCTET16 ltk; + UINT16 div; + UINT8 key_size; + UINT8 sec_level; +}tBTM_LE_LENC_KEYS; + +/* BLE SRK keys */ +typedef struct +{ + UINT32 counter; + UINT16 div; + UINT8 sec_level; + BT_OCTET16 csrk; +}tBTM_LE_LCSRK_KEYS; + +typedef struct +{ + BT_OCTET16 irk; + tBLE_ADDR_TYPE addr_type; + BD_ADDR static_addr; +}tBTM_LE_PID_KEYS; + +typedef union +{ + tBTM_LE_PENC_KEYS penc_key; /* received peer encryption key */ + tBTM_LE_PCSRK_KEYS pcsrk_key; /* received peer device SRK */ + tBTM_LE_PID_KEYS pid_key; /* peer device ID key */ + tBTM_LE_LENC_KEYS lenc_key; /* local encryption reproduction keys LTK = = d1(ER,DIV,0)*/ + tBTM_LE_LCSRK_KEYS lcsrk_key; /* local device CSRK = d1(ER,DIV,1)*/ +}tBTM_LE_KEY_VALUE; + +typedef struct +{ + tBTM_LE_KEY_TYPE key_type; + tBTM_LE_KEY_VALUE *p_key_value; +}tBTM_LE_KEY; + +typedef union +{ + tBTM_LE_IO_REQ io_req; /* BTM_LE_IO_REQ_EVT */ + UINT32 key_notif; /* BTM_LE_KEY_NOTIF_EVT */ + /* BTM_LE_NC_REQ_EVT */ + /* no callback data for BTM_LE_KEY_REQ_EVT */ + /* and BTM_LE_OOB_REQ_EVT */ +#if BLE_INCLUDED == TRUE && SMP_INCLUDED == TRUE + tBTM_LE_COMPLT complt; /* BTM_LE_COMPLT_EVT */ + tSMP_OOB_DATA_TYPE req_oob_type; +#endif + tBTM_LE_KEY key; +} tBTM_LE_EVT_DATA; + +/* Simple Pairing Events. Called by the stack when Simple Pairing related +** events occur. +*/ +typedef UINT8 (tBTM_LE_CALLBACK) (tBTM_LE_EVT event, BD_ADDR bda, tBTM_LE_EVT_DATA *p_data); + +#define BTM_BLE_KEY_TYPE_ID 1 +#define BTM_BLE_KEY_TYPE_ER 2 +#define BTM_BLE_KEY_TYPE_COUNTER 3 //tobe obsolete + +typedef struct +{ + BT_OCTET16 ir; + BT_OCTET16 irk; + BT_OCTET16 dhk; + +}tBTM_BLE_LOCAL_ID_KEYS; + +typedef union +{ + tBTM_BLE_LOCAL_ID_KEYS id_keys; + BT_OCTET16 er; +}tBTM_BLE_LOCAL_KEYS; + + +/* New LE identity key for local device. +*/ +typedef void (tBTM_LE_KEY_CALLBACK) (UINT8 key_type, tBTM_BLE_LOCAL_KEYS *p_key); + + +/*************************** +** Security Manager Types +****************************/ +/* Structure that applications use to register with BTM_SecRegister */ +typedef struct +{ + tBTM_AUTHORIZE_CALLBACK *p_authorize_callback; + tBTM_PIN_CALLBACK *p_pin_callback; + tBTM_LINK_KEY_CALLBACK *p_link_key_callback; + tBTM_AUTH_COMPLETE_CALLBACK *p_auth_complete_callback; + tBTM_BOND_CANCEL_CMPL_CALLBACK *p_bond_cancel_cmpl_callback; + tBTM_SP_CALLBACK *p_sp_callback; +#if BLE_INCLUDED == TRUE +#if SMP_INCLUDED == TRUE + tBTM_LE_CALLBACK *p_le_callback; +#endif + tBTM_LE_KEY_CALLBACK *p_le_key_callback; +#endif +} tBTM_APPL_INFO; + +/* Callback function for when a link supervision timeout event occurs. +** This asynchronous event is enabled/disabled by calling BTM_RegForLstoEvt(). +*/ +typedef void (tBTM_LSTO_CBACK) (BD_ADDR remote_bda, UINT16 timeout); + +/***************************************************************************** +** POWER MANAGEMENT +*****************************************************************************/ +/**************************** +** Power Manager Constants +*****************************/ +/* BTM Power manager status codes */ +enum +{ + BTM_PM_STS_ACTIVE = HCI_MODE_ACTIVE, + BTM_PM_STS_HOLD = HCI_MODE_HOLD, + BTM_PM_STS_SNIFF = HCI_MODE_SNIFF, + BTM_PM_STS_PARK = HCI_MODE_PARK, + BTM_PM_STS_SSR, /* report the SSR parameters in HCI_SNIFF_SUB_RATE_EVT */ + BTM_PM_STS_PENDING, /* when waiting for status from controller */ + BTM_PM_STS_ERROR /* when HCI command status returns error */ +}; +typedef UINT8 tBTM_PM_STATUS; + +/* BTM Power manager modes */ +enum +{ + BTM_PM_MD_ACTIVE = BTM_PM_STS_ACTIVE, + BTM_PM_MD_HOLD = BTM_PM_STS_HOLD, + BTM_PM_MD_SNIFF = BTM_PM_STS_SNIFF, + BTM_PM_MD_PARK = BTM_PM_STS_PARK, + BTM_PM_MD_FORCE = 0x10 /* OR this to force ACL link to a certain mode */ +}; +typedef UINT8 tBTM_PM_MODE; + +#define BTM_PM_SET_ONLY_ID 0x80 + +/* Operation codes */ +#define BTM_PM_REG_SET 1 /* The module wants to set the desired power mode */ +#define BTM_PM_REG_NOTIF 2 /* The module wants to receive mode change event */ +#define BTM_PM_DEREG 4 /* The module does not want to involve with PM anymore */ + +/************************ +** Power Manager Types +*************************/ +typedef struct +{ + UINT16 max; + UINT16 min; + UINT16 attempt; + UINT16 timeout; + tBTM_PM_MODE mode; +} tBTM_PM_PWR_MD; + +/************************************* +** Power Manager Callback Functions +**************************************/ +typedef void (tBTM_PM_STATUS_CBACK) (BD_ADDR p_bda, tBTM_PM_STATUS status, + UINT16 value, UINT8 hci_status); + + +/************************ +** Stored Linkkey Types +*************************/ +#define BTM_CB_EVT_DELETE_STORED_LINK_KEYS 4 + +typedef struct +{ + UINT8 event; + UINT8 status; + UINT16 num_keys; + +} tBTM_DELETE_STORED_LINK_KEY_COMPLETE; + +/* MIP evnets, callbacks */ +enum +{ + BTM_MIP_MODE_CHG_EVT, + BTM_MIP_DISCONNECT_EVT, + BTM_MIP_PKTS_COMPL_EVT, + BTM_MIP_RXDATA_EVT +}; +typedef UINT8 tBTM_MIP_EVT; + +typedef struct +{ + tBTM_MIP_EVT event; + BD_ADDR bd_addr; + UINT16 mip_id; +} tBTM_MIP_MODE_CHANGE; + +typedef struct +{ + tBTM_MIP_EVT event; + UINT16 mip_id; + UINT8 disc_reason; +} tBTM_MIP_CONN_TIMEOUT; + +#define BTM_MIP_MAX_RX_LEN 17 + +typedef struct +{ + tBTM_MIP_EVT event; + UINT16 mip_id; + UINT8 rx_len; + UINT8 rx_data[BTM_MIP_MAX_RX_LEN]; +} tBTM_MIP_RXDATA; + +typedef struct +{ + tBTM_MIP_EVT event; + BD_ADDR bd_addr; + UINT8 data[11]; /* data[0] shows Vender-specific device type */ +} tBTM_MIP_EIR_HANDSHAKE; + +typedef struct +{ + tBTM_MIP_EVT event; + UINT16 num_sent; /* Number of packets completed at the controller */ +} tBTM_MIP_PKTS_COMPL; + +typedef union +{ + tBTM_MIP_EVT event; + tBTM_MIP_MODE_CHANGE mod_chg; + tBTM_MIP_CONN_TIMEOUT conn_tmo; + tBTM_MIP_EIR_HANDSHAKE eir; + tBTM_MIP_PKTS_COMPL completed; + tBTM_MIP_RXDATA rxdata; +} tBTM_MIP_EVENT_DATA; + +/* MIP event callback function */ +typedef void (tBTM_MIP_EVENTS_CB) (tBTM_MIP_EVT event, tBTM_MIP_EVENT_DATA data); + +/* MIP Device query callback function */ +typedef BOOLEAN (tBTM_MIP_QUERY_CB) (BD_ADDR dev_addr, UINT8 *p_mode, LINK_KEY link_key); + +#define BTM_CONTRL_ACTIVE 1 /* ACL link on, SCO link ongoing, sniff mode */ +#define BTM_CONTRL_SCAN 2 /* Scan state - paging/inquiry/trying to connect*/ +#define BTM_CONTRL_IDLE 3 /* Idle state - page scan, LE advt, inquiry scan */ + +typedef UINT8 tBTM_CONTRL_STATE; + +/***************************************************************************** +** EXTERNAL FUNCTION DECLARATIONS +*****************************************************************************/ +/* +#ifdef __cplusplus +extern "C" { +#endif +*/ +/***************************************************************************** +** DEVICE CONTROL and COMMON FUNCTIONS +*****************************************************************************/ + +/******************************************************************************* +** +** Function BTM_DeviceReset +** +** Description This function is called to reset the controller.The Callback function +** if provided is called when startup of the device has +** completed. +** +** Returns void +** +*******************************************************************************/ +//extern +void BTM_DeviceReset (tBTM_CMPL_CB *p_cb); + + +/******************************************************************************* +** +** Function BTM_IsDeviceUp +** +** Description This function is called to check if the device is up. +** +** Returns TRUE if device is up, else FALSE +** +*******************************************************************************/ +//extern +BOOLEAN BTM_IsDeviceUp (void); + + +/******************************************************************************* +** +** Function BTM_SetLocalDeviceName +** +** Description This function is called to set the local device name. +** +** Returns BTM_CMD_STARTED if successful, otherwise an error +** +*******************************************************************************/ +//extern +tBTM_STATUS BTM_SetLocalDeviceName (char *p_name); + +/******************************************************************************* +** +** Function BTM_SetDeviceClass +** +** Description This function is called to set the local device class +** +** Returns BTM_SUCCESS if successful, otherwise an error +** +*******************************************************************************/ +//extern +tBTM_STATUS BTM_SetDeviceClass (DEV_CLASS dev_class); + + +/******************************************************************************* +** +** Function BTM_ReadLocalDeviceName +** +** Description This function is called to read the local device name. +** +** Returns status of the operation +** If success, BTM_SUCCESS is returned and p_name points stored +** local device name +** If BTM doesn't store local device name, BTM_NO_RESOURCES is +** is returned and p_name is set to NULL +** +*******************************************************************************/ +//extern +tBTM_STATUS BTM_ReadLocalDeviceName (char **p_name); + +/******************************************************************************* +** +** Function BTM_ReadLocalDeviceNameFromController +** +** Description Get local device name from controller. Do not use cached +** name (used to get chip-id prior to btm reset complete). +** +** Returns BTM_CMD_STARTED if successful, otherwise an error +** +*******************************************************************************/ +//extern +tBTM_STATUS BTM_ReadLocalDeviceNameFromController (tBTM_CMPL_CB *p_rln_cmpl_cback); + +/******************************************************************************* +** +** Function BTM_ReadDeviceClass +** +** Description This function is called to read the local device class +** +** Returns pointer to the device class +** +*******************************************************************************/ +//extern +UINT8 *BTM_ReadDeviceClass (void); + + +/******************************************************************************* +** +** Function BTM_ReadLocalFeatures +** +** Description This function is called to read the local features +** +** Returns pointer to the local features string +** +*******************************************************************************/ +//extern +UINT8 *BTM_ReadLocalFeatures (void); + +/******************************************************************************* +** +** Function BTM_RegisterForDeviceStatusNotif +** +** Description This function is called to register for device status +** change notifications. +** +** Returns pointer to previous caller's callback function or NULL if first +** registration. +** +*******************************************************************************/ +//extern +tBTM_DEV_STATUS_CB *BTM_RegisterForDeviceStatusNotif (tBTM_DEV_STATUS_CB *p_cb); + + +/******************************************************************************* +** +** Function BTM_RegisterForVSEvents +** +** Description This function is called to register/deregister for vendor +** specific HCI events. +** +** If is_register=TRUE, then the function will be registered; +** if is_register=FALSE, then the function will be deregistered. +** +** Returns BTM_SUCCESS if successful, +** BTM_BUSY if maximum number of callbacks have already been +** registered. +** +*******************************************************************************/ +//extern +tBTM_STATUS BTM_RegisterForVSEvents (tBTM_VS_EVT_CB *p_cb, BOOLEAN is_register); + + +/******************************************************************************* +** +** Function BTM_VendorSpecificCommand +** +** Description Send a vendor specific HCI command to the controller. +** +** Returns +** BTM_SUCCESS Command sent. Does not expect command complete +** event. (command cmpl callback param is NULL) +** BTM_CMD_STARTED Command sent. Waiting for command cmpl event. +** BTM_BUSY Command not sent. Waiting for cmd cmpl event for +** prior command. +** +*******************************************************************************/ +//extern +tBTM_STATUS BTM_VendorSpecificCommand(UINT16 opcode, + UINT8 param_len, + UINT8 *p_param_buf, + tBTM_VSC_CMPL_CB *p_cb); + + +/******************************************************************************* +** +** Function BTM_AllocateSCN +** +** Description Look through the Server Channel Numbers for a free one to be +** used with an RFCOMM connection. +** +** Returns Allocated SCN number or 0 if none. +** +*******************************************************************************/ +//extern +UINT8 BTM_AllocateSCN(void); + +// btla-specific ++ +/******************************************************************************* +** +** Function BTM_TryAllocateSCN +** +** Description Try to allocate a fixed server channel +** +** Returns Returns TRUE if server channel was available +** +*******************************************************************************/ +//extern +BOOLEAN BTM_TryAllocateSCN(UINT8 scn); +// btla-specific -- + + +/******************************************************************************* +** +** Function BTM_FreeSCN +** +** Description Free the specified SCN. +** +** Returns TRUE if successful, FALSE if SCN is not in use or invalid +** +*******************************************************************************/ +//extern +BOOLEAN BTM_FreeSCN(UINT8 scn); + + +/******************************************************************************* +** +** Function BTM_SetTraceLevel +** +** Description This function sets the trace level for BTM. If called with +** a value of 0xFF, it simply returns the current trace level. +** +** Returns The new or current trace level +** +*******************************************************************************/ +//extern +UINT8 BTM_SetTraceLevel (UINT8 new_level); + + +/******************************************************************************* +** +** Function BTM_WritePageTimeout +** +** Description Send HCI Wite Page Timeout. +** +** Returns +** BTM_SUCCESS Command sent. +** BTM_NO_RESOURCES If out of resources to send the command. +** +*******************************************************************************/ +//extern +tBTM_STATUS BTM_WritePageTimeout(UINT16 timeout); + +/******************************************************************************* +** +** Function BTM_WriteVoiceSettings +** +** Description Send HCI Write Voice Settings command. +** See hcidefs.h for settings bitmask values. +** +** Returns +** BTM_SUCCESS Command sent. +** BTM_NO_RESOURCES If out of resources to send the command. +** +** +*******************************************************************************/ +//extern +tBTM_STATUS BTM_WriteVoiceSettings(UINT16 settings); + +/******************************************************************************* +** +** Function BTM_EnableTestMode +** +** Description Send HCI the enable device under test command. +** +** Note: Controller can only be taken out of this mode by +** resetting the controller. +** +** Returns +** BTM_SUCCESS Command sent. +** BTM_NO_RESOURCES If out of resources to send the command. +** +** +*******************************************************************************/ +//extern +tBTM_STATUS BTM_EnableTestMode(void); + + +/***************************************************************************** +** DEVICE DISCOVERY FUNCTIONS - Inquiry, Remote Name, Discovery, Class of Device +*****************************************************************************/ + +/******************************************************************************* +** +** Function BTM_SetDiscoverability +** +** Description This function is called to set the device into or out of +** discoverable mode. Discoverable mode means inquiry +** scans are enabled. If a value of '0' is entered for window or +** interval, the default values are used. +** +** Returns BTM_SUCCESS if successful +** BTM_BUSY if a setting of the filter is already in progress +** BTM_NO_RESOURCES if couldn't get a memory pool buffer +** BTM_ILLEGAL_VALUE if a bad parameter was detected +** BTM_WRONG_MODE if the device is not up. +** +*******************************************************************************/ +//extern +tBTM_STATUS BTM_SetDiscoverability (UINT16 inq_mode, UINT16 window, + UINT16 interval); + + +/******************************************************************************* +** +** Function BTM_ReadDiscoverability +** +** Description This function is called to read the current discoverability +** mode of the device. +** +** Output Params: p_window - current inquiry scan duration +** p_interval - current inquiry scan interval +** +** Returns BTM_NON_DISCOVERABLE, BTM_LIMITED_DISCOVERABLE, or +** BTM_GENERAL_DISCOVERABLE +** +*******************************************************************************/ +//extern +UINT16 BTM_ReadDiscoverability (UINT16 *p_window, + UINT16 *p_interval); + + +/******************************************************************************* +** +** Function BTM_SetPeriodicInquiryMode +** +** Description This function is called to set the device periodic inquiry mode. +** If the duration is zero, the periodic inquiry mode is cancelled. +** +** Parameters: p_inqparms - pointer to the inquiry information +** mode - GENERAL or LIMITED inquiry +** duration - length in 1.28 sec intervals (If '0', the inquiry is CANCELLED) +** max_resps - maximum amount of devices to search for before ending the inquiry +** filter_cond_type - BTM_CLR_INQUIRY_FILTER, BTM_FILTER_COND_DEVICE_CLASS, or +** BTM_FILTER_COND_BD_ADDR +** filter_cond - value for the filter (based on filter_cond_type) +** +** max_delay - maximum amount of time between successive inquiries +** min_delay - minimum amount of time between successive inquiries +** p_results_cb - callback returning pointer to results (tBTM_INQ_RESULTS) +** +** Returns BTM_CMD_STARTED if successfully started +** BTM_ILLEGAL_VALUE if a bad parameter is detected +** BTM_NO_RESOURCES if could not allocate a message buffer +** BTM_SUCCESS - if cancelling the periodic inquiry +** BTM_BUSY - if an inquiry is already active +** BTM_WRONG_MODE if the device is not up. +** +*******************************************************************************/ +//extern +tBTM_STATUS BTM_SetPeriodicInquiryMode (tBTM_INQ_PARMS *p_inqparms, + UINT16 max_delay, UINT16 min_delay, + tBTM_INQ_RESULTS_CB *p_results_cb); + + +/******************************************************************************* +** +** Function BTM_StartInquiry +** +** Description This function is called to start an inquiry. +** +** Parameters: p_inqparms - pointer to the inquiry information +** mode - GENERAL or LIMITED inquiry +** duration - length in 1.28 sec intervals (If '0', the inquiry is CANCELLED) +** max_resps - maximum amount of devices to search for before ending the inquiry +** filter_cond_type - BTM_CLR_INQUIRY_FILTER, BTM_FILTER_COND_DEVICE_CLASS, or +** BTM_FILTER_COND_BD_ADDR +** filter_cond - value for the filter (based on filter_cond_type) +** +** p_results_cb - Pointer to the callback routine which gets called +** upon receipt of an inquiry result. If this field is +** NULL, the application is not notified. +** +** p_cmpl_cb - Pointer to the callback routine which gets called +** upon completion. If this field is NULL, the +** application is not notified when completed. +** Returns tBTM_STATUS +** BTM_CMD_STARTED if successfully initiated +** BTM_BUSY if already in progress +** BTM_ILLEGAL_VALUE if parameter(s) are out of range +** BTM_NO_RESOURCES if could not allocate resources to start the command +** BTM_WRONG_MODE if the device is not up. +** +*******************************************************************************/ +//extern +tBTM_STATUS BTM_StartInquiry (tBTM_INQ_PARMS *p_inqparms, + tBTM_INQ_RESULTS_CB *p_results_cb, + tBTM_CMPL_CB *p_cmpl_cb); + + +/******************************************************************************* +** +** Function BTM_IsInquiryActive +** +** Description This function returns a bit mask of the current inquiry state +** +** Returns BTM_INQUIRY_INACTIVE if inactive (0) +** BTM_LIMITED_INQUIRY_ACTIVE if a limted inquiry is active +** BTM_GENERAL_INQUIRY_ACTIVE if a general inquiry is active +** BTM_PERIODIC_INQUIRY_ACTIVE if a periodic inquiry is active +** +*******************************************************************************/ +//extern +UINT16 BTM_IsInquiryActive (void); + + +/******************************************************************************* +** +** Function BTM_CancelInquiry +** +** Description This function cancels an inquiry if active +** +** Returns BTM_SUCCESS if successful +** BTM_NO_RESOURCES if could not allocate a message buffer +** BTM_WRONG_MODE if the device is not up. +** +*******************************************************************************/ +//extern +tBTM_STATUS BTM_CancelInquiry(void); + + +/******************************************************************************* +** +** Function BTM_CancelPeriodicInquiry +** +** Description This function cancels a periodic inquiry +** +** Returns +** BTM_NO_RESOURCES if could not allocate a message buffer +** BTM_SUCCESS - if cancelling the periodic inquiry +** BTM_WRONG_MODE if the device is not up. +** +*******************************************************************************/ +//extern +tBTM_STATUS BTM_CancelPeriodicInquiry(void); + + +/******************************************************************************* +** +** Function BTM_SetConnectability +** +** Description This function is called to set the device into or out of +** connectable mode. Discoverable mode means page scans enabled. +** +** Returns BTM_SUCCESS if successful +** BTM_ILLEGAL_VALUE if a bad parameter is detected +** BTM_NO_RESOURCES if could not allocate a message buffer +** BTM_WRONG_MODE if the device is not up. +** +*******************************************************************************/ +//extern +tBTM_STATUS BTM_SetConnectability (UINT16 page_mode, UINT16 window, + UINT16 interval); + + +/******************************************************************************* +** +** Function BTM_ReadConnectability +** +** Description This function is called to read the current discoverability +** mode of the device. +** Output Params p_window - current page scan duration +** p_interval - current time between page scans +** +** Returns BTM_NON_CONNECTABLE or BTM_CONNECTABLE +** +*******************************************************************************/ +//extern +UINT16 BTM_ReadConnectability (UINT16 *p_window, UINT16 *p_interval); + + +/******************************************************************************* +** +** Function BTM_SetInquiryMode +** +** Description This function is called to set standard, with RSSI +** mode or extended of the inquiry for local device. +** +** Input Params: BTM_INQ_RESULT_STANDARD, BTM_INQ_RESULT_WITH_RSSI or +** BTM_INQ_RESULT_EXTENDED +** +** Returns BTM_SUCCESS if successful +** BTM_NO_RESOURCES if couldn't get a memory pool buffer +** BTM_ILLEGAL_VALUE if a bad parameter was detected +** BTM_WRONG_MODE if the device is not up. +** +*******************************************************************************/ +//extern +tBTM_STATUS BTM_SetInquiryMode (UINT8 mode); + +/******************************************************************************* +** +** Function BTM_SetInquiryScanType +** +** Description This function is called to set the iquiry scan-type to +** standard or interlaced. +** +** Input Params: BTM_SCAN_TYPE_STANDARD or BTM_SCAN_TYPE_INTERLACED +** +** Returns BTM_SUCCESS if successful +** BTM_MODE_UNSUPPORTED if not a 1.2 device +** BTM_WRONG_MODE if the device is not up. +** +*******************************************************************************/ +//extern +tBTM_STATUS BTM_SetInquiryScanType (UINT16 scan_type); + +/******************************************************************************* +** +** Function BTM_SetPageScanType +** +** Description This function is called to set the page scan-type to +** standard or interlaced. +** +** Input Params: BTM_SCAN_TYPE_STANDARD or BTM_SCAN_TYPE_INTERLACED +** +** Returns BTM_SUCCESS if successful +** BTM_MODE_UNSUPPORTED if not a 1.2 device +** BTM_WRONG_MODE if the device is not up. +** +*******************************************************************************/ + +//extern +tBTM_STATUS BTM_SetPageScanType (UINT16 scan_type); + +/******************************************************************************* +** +** Function BTM_ReadRemoteDeviceName +** +** Description This function initiates a remote device HCI command to the +** controller and calls the callback when the process has completed. +** +** Input Params: remote_bda - device address of name to retrieve +** p_cb - callback function called when BTM_CMD_STARTED +** is returned. +** A pointer to tBTM_REMOTE_DEV_NAME is passed to the +** callback. +** +** Returns +** BTM_CMD_STARTED is returned if the request was successfully sent +** to HCI. +** BTM_BUSY if already in progress +** BTM_UNKNOWN_ADDR if device address is bad +** BTM_NO_RESOURCES if could not allocate resources to start the command +** BTM_WRONG_MODE if the device is not up. +** +*******************************************************************************/ +//extern +tBTM_STATUS BTM_ReadRemoteDeviceName (BD_ADDR remote_bda, + tBTM_CMPL_CB *p_cb, + tBT_TRANSPORT transport); + + +/******************************************************************************* +** +** Function BTM_CancelRemoteDeviceName +** +** Description This function initiates the cancel request for the specified +** remote device. +** +** Input Params: None +** +** Returns +** BTM_CMD_STARTED is returned if the request was successfully sent +** to HCI. +** BTM_NO_RESOURCES if could not allocate resources to start the command +** BTM_WRONG_MODE if there is not an active remote name request. +** +*******************************************************************************/ +//extern +tBTM_STATUS BTM_CancelRemoteDeviceName (void); + +/******************************************************************************* +** +** Function BTM_ReadRemoteVersion +** +** Description This function is called to read a remote device's version +** +** Returns BTM_SUCCESS if successful, otherwise an error +** +*******************************************************************************/ +//extern +tBTM_STATUS BTM_ReadRemoteVersion (BD_ADDR addr, + UINT8 *lmp_version, + UINT16 *manufacturer, + UINT16 *lmp_sub_version); + +/******************************************************************************* +** +** Function BTM_ReadRemoteFeatures +** +** Description This function is called to read a remote device's +** supported features mask (features mask located at page 0) +** +** Note: The size of device features mask page is +** BTM_FEATURE_BYTES_PER_PAGE bytes. +** +** Returns pointer to the remote supported features mask +** +*******************************************************************************/ +//extern +UINT8 *BTM_ReadRemoteFeatures (BD_ADDR addr); + +/******************************************************************************* +** +** Function BTM_ReadRemoteExtendedFeatures +** +** Description This function is called to read a specific extended features +** page of the remote device +** +** Note1: The size of device features mask page is +** BTM_FEATURE_BYTES_PER_PAGE bytes. +** Note2: The valid device features mask page number depends on +** the remote device capabilities. It is expected to be in the +** range [0 - BTM_EXT_FEATURES_PAGE_MAX]. + +** Returns pointer to the remote extended features mask +** or NULL if page_number is not valid +** +*******************************************************************************/ +//extern +UINT8 *BTM_ReadRemoteExtendedFeatures (BD_ADDR addr, UINT8 page_number); + +/******************************************************************************* +** +** Function BTM_ReadNumberRemoteFeaturesPages +** +** Description This function is called to retrieve the number of feature pages +** read from the remote device +** +** Returns number of features pages read from the remote device +** +*******************************************************************************/ +//extern +UINT8 BTM_ReadNumberRemoteFeaturesPages (BD_ADDR addr); + +/******************************************************************************* +** +** Function BTM_ReadAllRemoteFeatures +** +** Description This function is called to read all features of the remote device +** +** Returns pointer to the byte[0] of the page[0] of the remote device +** feature mask. +** +** Note: the function returns the pointer to the array of the size +** BTM_FEATURE_BYTES_PER_PAGE * (BTM_EXT_FEATURES_PAGE_MAX + 1). +** +*******************************************************************************/ +//extern +UINT8 *BTM_ReadAllRemoteFeatures (BD_ADDR addr); + +/******************************************************************************* +** +** Function BTM_InqDbRead +** +** Description This function looks through the inquiry database for a match +** based on Bluetooth Device Address. This is the application's +** interface to get the inquiry details of a specific BD address. +** +** Returns pointer to entry, or NULL if not found +** +*******************************************************************************/ +//extern +tBTM_INQ_INFO *BTM_InqDbRead (BD_ADDR p_bda); + + +/******************************************************************************* +** +** Function BTM_InqDbFirst +** +** Description This function looks through the inquiry database for the first +** used entry, and returns that. This is used in conjunction with +** BTM_InqDbNext by applications as a way to walk through the +** inquiry database. +** +** Returns pointer to first in-use entry, or NULL if DB is empty +** +*******************************************************************************/ +//extern +tBTM_INQ_INFO *BTM_InqDbFirst (void); + + +/******************************************************************************* +** +** Function BTM_InqDbNext +** +** Description This function looks through the inquiry database for the next +** used entry, and returns that. If the input parameter is NULL, +** the first entry is returned. +** +** Returns pointer to next in-use entry, or NULL if no more found. +** +*******************************************************************************/ +//extern +tBTM_INQ_INFO *BTM_InqDbNext (tBTM_INQ_INFO *p_cur); + + +/******************************************************************************* +** +** Function BTM_ClearInqDb +** +** Description This function is called to clear out a device or all devices +** from the inquiry database. +** +** Parameter p_bda - (input) BD_ADDR -> Address of device to clear +** (NULL clears all entries) +** +** Returns BTM_BUSY if an inquiry, get remote name, or event filter +** is active, otherwise BTM_SUCCESS +** +*******************************************************************************/ +//extern +tBTM_STATUS BTM_ClearInqDb (BD_ADDR p_bda); + +/******************************************************************************* +** +** Function BTM_ReadInquiryRspTxPower +** +** Description This command will read the inquiry Transmit Power level used +** to transmit the FHS and EIR data packets. +** This can be used directly in the Tx Power Level EIR data type. +** +** Returns BTM_SUCCESS if successful +** +*******************************************************************************/ +//extern +tBTM_STATUS BTM_ReadInquiryRspTxPower (tBTM_CMPL_CB *p_cb); + +#if SDP_INCLUDED == TRUE +/******************************************************************************* +** +** Function BTM_StartDiscovery +** +** Description This function is called by an application (or profile) +** when it wants to trigger an service discovery using the +** BTM's discovery database. +** +** Returns tBTM_STATUS +** BTM_CMD_STARTED if the discovery was initiated +** BTM_BUSY if one is already in progress +** BTM_UNKNOWN_ADDR if no addresses are in the INQ DB +** BTM_ERR_PROCESSING if err initiating the command +** +*******************************************************************************/ +//extern +tBTM_STATUS BTM_StartDiscovery (tBTM_CMPL_CB *p_cmpl_cb, + BD_ADDR_PTR p_rem_addr); + + +/******************************************************************************* +** +** Function BTM_FindAttribute +** +** Description This function is called by an application (or profile) +** when it wants to see if an attribute exists in the BTM +** discovery database. +** +** Returns Pointer to matching record, or NULL +** +*******************************************************************************/ +//extern +tSDP_DISC_REC *BTM_FindAttribute (UINT16 attr_id, + tSDP_DISC_REC *p_start_rec); + + +/******************************************************************************* +** +** Function BTM_FindService +** +** Description This function is called by an application (or profile) +** when it wants to see if a service exists in the BTM +** discovery database. +** +** Returns Pointer to matching record, or NULL +** +*******************************************************************************/ +//extern +tSDP_DISC_REC *BTM_FindService (UINT16 service_uuid, + tSDP_DISC_REC *p_start_rec); + + +/******************************************************************************* +** +** Function BTM_SetDiscoveryParams +** +** Description This function is called to set the BTM default discovery parameters. +** These UUID and attribute filters are used during the call to +** BTM_StartDiscovery. +** +** Returns void +** +*******************************************************************************/ +//extern +void BTM_SetDiscoveryParams (UINT16 num_uuid, tSDP_UUID *p_uuid_list, + UINT16 num_attr, UINT16 *p_attr_list); +#endif /*SDP_INCLUDED*/ + +/***************************************************************************** +** ACL CHANNEL MANAGEMENT FUNCTIONS +*****************************************************************************/ +/******************************************************************************* +** +** Function BTM_SetLinkPolicy +** +** Description Create and send HCI "Write Policy Set" command +** +** Returns BTM_CMD_STARTED if successfully initiated, otherwise error +** +*******************************************************************************/ +//extern +tBTM_STATUS BTM_SetLinkPolicy (BD_ADDR remote_bda, + UINT16 *settings); + +/******************************************************************************* +** +** Function BTM_SetDefaultLinkPolicy +** +** Description Set the default value for HCI "Write Policy Set" command +** to use when an ACL link is created. +** +** Returns void +** +*******************************************************************************/ +//extern +void BTM_SetDefaultLinkPolicy (UINT16 settings); + + +/******************************************************************************* +** +** Function BTM_SetDefaultLinkSuperTout +** +** Description Set the default value for HCI "Write Link Supervision Timeout" +** command to use when an ACL link is created. +** +** Returns void +** +*******************************************************************************/ +//extern +void BTM_SetDefaultLinkSuperTout (UINT16 timeout); + + +/******************************************************************************* +** +** Function BTM_SetLinkSuperTout +** +** Description Create and send HCI "Write Link Supervision Timeout" command +** +** Returns BTM_CMD_STARTED if successfully initiated, otherwise error +** +*******************************************************************************/ +//extern +tBTM_STATUS BTM_SetLinkSuperTout (BD_ADDR remote_bda, + UINT16 timeout); +/******************************************************************************* +** +** Function BTM_GetLinkSuperTout +** +** Description Read the link supervision timeout value of the connection +** +** Returns status of the operation +** +*******************************************************************************/ +//extern +tBTM_STATUS BTM_GetLinkSuperTout (BD_ADDR remote_bda, + UINT16 *p_timeout); + +/******************************************************************************* +** +** Function BTM_IsAclConnectionUp +** +** Description This function is called to check if an ACL connection exists +** to a specific remote BD Address. +** +** Returns TRUE if connection is up, else FALSE. +** +*******************************************************************************/ +//extern +BOOLEAN BTM_IsAclConnectionUp (BD_ADDR remote_bda, tBT_TRANSPORT transport); + + +/******************************************************************************* +** +** Function BTM_GetRole +** +** Description This function is called to get the role of the local device +** for the ACL connection with the specified remote device +** +** Returns BTM_SUCCESS if connection exists. +** BTM_UNKNOWN_ADDR if no active link with bd addr specified +** +*******************************************************************************/ +//extern +tBTM_STATUS BTM_GetRole (BD_ADDR remote_bd_addr, UINT8 *p_role); + + + +/******************************************************************************* +** +** Function BTM_SwitchRole +** +** Description This function is called to switch role between master and +** slave. If role is already set it will do nothing. If the +** command was initiated, the callback function is called upon +** completion. +** +** Returns BTM_SUCCESS if already in specified role. +** BTM_CMD_STARTED if command issued to controller. +** BTM_NO_RESOURCES if couldn't allocate memory to issue command +** BTM_UNKNOWN_ADDR if no active link with bd addr specified +** BTM_MODE_UNSUPPORTED if local device does not support role switching +** +*******************************************************************************/ +//extern +tBTM_STATUS BTM_SwitchRole (BD_ADDR remote_bd_addr, + UINT8 new_role, + tBTM_CMPL_CB *p_cb); + +/******************************************************************************* +** +** Function BTM_ReadRSSI +** +** Description This function is called to read the link policy settings. +** The address of link policy results are returned in the callback. +** (tBTM_RSSI_RESULTS) +** +** Returns BTM_CMD_STARTED if command issued to controller. +** BTM_NO_RESOURCES if couldn't allocate memory to issue command +** BTM_UNKNOWN_ADDR if no active link with bd addr specified +** BTM_BUSY if command is already in progress +** +*******************************************************************************/ +//extern +tBTM_STATUS BTM_ReadRSSI (BD_ADDR remote_bda, tBTM_CMPL_CB *p_cb); + + +/******************************************************************************* +** +** Function BTM_ReadTxPower +** +** Description This function is called to read the current connection +** TX power of the connection. The TX power level results +** are returned in the callback. +** (tBTM_RSSI_RESULTS) +** +** Returns BTM_CMD_STARTED if command issued to controller. +** BTM_NO_RESOURCES if couldn't allocate memory to issue command +** BTM_UNKNOWN_ADDR if no active link with bd addr specified +** BTM_BUSY if command is already in progress +** +*******************************************************************************/ +//extern +tBTM_STATUS BTM_ReadTxPower (BD_ADDR remote_bda, + tBT_TRANSPORT transport, tBTM_CMPL_CB *p_cb); + +/******************************************************************************* +** +** Function BTM_ReadLinkQuality +** +** Description This function is called to read the link quality. +** The value of the link quality is returned in the callback. +** (tBTM_LINK_QUALITY_RESULTS) +** +** Returns BTM_CMD_STARTED if command issued to controller. +** BTM_NO_RESOURCES if couldn't allocate memory to issue command +** BTM_UNKNOWN_ADDR if no active link with bd addr specified +** BTM_BUSY if command is already in progress +** +*******************************************************************************/ +//extern +tBTM_STATUS BTM_ReadLinkQuality (BD_ADDR remote_bda, tBTM_CMPL_CB *p_cb); + +/******************************************************************************* +** +** Function BTM_RegBusyLevelNotif +** +** Description This function is called to register a callback to receive +** busy level change events. +** +** Returns BTM_SUCCESS if successfully registered, otherwise error +** +*******************************************************************************/ +//extern +tBTM_STATUS BTM_RegBusyLevelNotif (tBTM_BL_CHANGE_CB *p_cb, UINT8 *p_level, + tBTM_BL_EVENT_MASK evt_mask); + +/******************************************************************************* +** +** Function BTM_AclRegisterForChanges +** +** Description This function is called to register a callback to receive +** ACL database change events, i.e. new connection or removed. +** +** Returns BTM_SUCCESS if successfully initiated, otherwise error +** +*******************************************************************************/ +//extern +tBTM_STATUS BTM_AclRegisterForChanges (tBTM_ACL_DB_CHANGE_CB *p_cb); + +/******************************************************************************* +** +** Function BTM_GetNumAclLinks +** +** Description This function is called to count the number of +** ACL links that are active. +** +** Returns UINT16 Number of active ACL links +** +*******************************************************************************/ +//extern +UINT16 BTM_GetNumAclLinks (void); + +/******************************************************************************* +** +** Function BTM_SetQoS +** +** Description This function is called to setup QoS +** +** Returns BTM_CMD_STARTED if successfully initiated, otherwise error +** +*******************************************************************************/ +//extern +tBTM_STATUS BTM_SetQoS(BD_ADDR bd, FLOW_SPEC *p_flow, + tBTM_CMPL_CB *p_cb); + + +/***************************************************************************** +** (e)SCO CHANNEL MANAGEMENT FUNCTIONS +*****************************************************************************/ +/******************************************************************************* +** +** Function BTM_CreateSco +** +** Description This function is called to create an SCO connection. If the +** "is_orig" flag is TRUE, the connection will be originated, +** otherwise BTM will wait for the other side to connect. +** +** Returns BTM_UNKNOWN_ADDR if the ACL connection is not up +** BTM_BUSY if another SCO being set up to +** the same BD address +** BTM_NO_RESOURCES if the max SCO limit has been reached +** BTM_CMD_STARTED if the connection establishment is started. +** In this case, "*p_sco_inx" is filled in +** with the sco index used for the connection. +** +*******************************************************************************/ +//extern +tBTM_STATUS BTM_CreateSco (BD_ADDR remote_bda, BOOLEAN is_orig, + UINT16 pkt_types, UINT16 *p_sco_inx, + tBTM_SCO_CB *p_conn_cb, + tBTM_SCO_CB *p_disc_cb); + + +/******************************************************************************* +** +** Function BTM_RemoveSco +** +** Description This function is called to remove a specific SCO connection. +** +** Returns BTM_CMD_STARTED if successfully initiated, otherwise error +** +*******************************************************************************/ +//extern +tBTM_STATUS BTM_RemoveSco (UINT16 sco_inx); + + +/******************************************************************************* +** +** Function BTM_SetScoPacketTypes +** +** Description This function is called to set the packet types used for +** a specific SCO connection, +** +** Parameters pkt_types - One or more of the following +** BTM_SCO_PKT_TYPES_MASK_HV1 +** BTM_SCO_PKT_TYPES_MASK_HV2 +** BTM_SCO_PKT_TYPES_MASK_HV3 +** BTM_SCO_PKT_TYPES_MASK_EV3 +** BTM_SCO_PKT_TYPES_MASK_EV4 +** BTM_SCO_PKT_TYPES_MASK_EV5 +** +** BTM_SCO_LINK_ALL_MASK - enables all supported types +** +** Returns BTM_CMD_STARTED if successfully initiated, otherwise error +** +*******************************************************************************/ +//extern +tBTM_STATUS BTM_SetScoPacketTypes (UINT16 sco_inx, UINT16 pkt_types); + + +/******************************************************************************* +** +** Function BTM_ReadScoPacketTypes +** +** Description This function is read the packet types used for a specific +** SCO connection. +** +** Returns One or more of the following (bitmask) +** BTM_SCO_PKT_TYPES_MASK_HV1 +** BTM_SCO_PKT_TYPES_MASK_HV2 +** BTM_SCO_PKT_TYPES_MASK_HV3 +** BTM_SCO_PKT_TYPES_MASK_EV3 +** BTM_SCO_PKT_TYPES_MASK_EV4 +** BTM_SCO_PKT_TYPES_MASK_EV5 +** +** Returns packet types supported for the connection +** +*******************************************************************************/ +//extern +UINT16 BTM_ReadScoPacketTypes (UINT16 sco_inx); + + +/******************************************************************************* +** +** Function BTM_ReadDeviceScoPacketTypes +** +** Description This function is read the SCO packet types that +** the device supports. +** +** Returns packet types supported by the device. +** +*******************************************************************************/ +//extern +UINT16 BTM_ReadDeviceScoPacketTypes (void); + + +/******************************************************************************* +** +** Function BTM_ReadScoHandle +** +** Description This function is used to read the HCI handle used for a specific +** SCO connection, +** +** Returns handle for the connection, or 0xFFFF if invalid SCO index. +** +*******************************************************************************/ +//extern +UINT16 BTM_ReadScoHandle (UINT16 sco_inx); + + +/******************************************************************************* +** +** Function BTM_ReadScoBdAddr +** +** Description This function is read the remote BD Address for a specific +** SCO connection, +** +** Returns pointer to BD address or NULL if not known +** +*******************************************************************************/ +//extern +UINT8 *BTM_ReadScoBdAddr (UINT16 sco_inx); + + +/******************************************************************************* +** +** Function BTM_ReadScoDiscReason +** +** Description This function is returns the reason why an (e)SCO connection +** has been removed. It contains the value until read, or until +** another (e)SCO connection has disconnected. +** +** Returns HCI reason or BTM_INVALID_SCO_DISC_REASON if not set. +** +*******************************************************************************/ +//extern +UINT16 BTM_ReadScoDiscReason (void); + + +/******************************************************************************* +** +** Function BTM_SetEScoMode +** +** Description This function sets up the negotiated parameters for SCO or +** eSCO, and sets as the default mode used for calls to +** BTM_CreateSco. It can be called only when there are no +** active (e)SCO links. +** +** Returns BTM_SUCCESS if the successful. +** BTM_BUSY if there are one or more active (e)SCO links. +** +*******************************************************************************/ +//extern +tBTM_STATUS BTM_SetEScoMode (tBTM_SCO_TYPE sco_mode, + tBTM_ESCO_PARAMS *p_parms); + +/******************************************************************************* +** +** Function BTM_SetWBSCodec +** +** Description This function sends command to the controller to setup +** WBS codec for the upcoming eSCO connection. +** +** Returns BTM_SUCCESS. +** +** +*******************************************************************************/ +//extern +tBTM_STATUS BTM_SetWBSCodec (tBTM_SCO_CODEC_TYPE codec_type); + +/******************************************************************************* +** +** Function BTM_RegForEScoEvts +** +** Description This function registers a SCO event callback with the +** specified instance. It should be used to received +** connection indication events and change of link parameter +** events. +** +** Returns BTM_SUCCESS if the successful. +** BTM_ILLEGAL_VALUE if there is an illegal sco_inx +** +*******************************************************************************/ +//extern +tBTM_STATUS BTM_RegForEScoEvts (UINT16 sco_inx, + tBTM_ESCO_CBACK *p_esco_cback); + +/******************************************************************************* +** +** Function BTM_ReadEScoLinkParms +** +** Description This function returns the current eSCO link parameters for +** the specified handle. This can be called anytime a connection +** is active, but is typically called after receiving the SCO +** opened callback. +** +** Note: If called over a 1.1 controller, only the packet types +** field has meaning. +** Note: If the upper layer doesn't know the current sco index, +** BTM_FIRST_ACTIVE_SCO_INDEX can be used as the first parameter to +** find the first active SCO index +** +** Returns BTM_SUCCESS if returned data is valid connection. +** BTM_ILLEGAL_VALUE if no connection for specified sco_inx. +** BTM_MODE_UNSUPPORTED if local controller does not support +** 1.2 specification. +** +*******************************************************************************/ +//extern +tBTM_STATUS BTM_ReadEScoLinkParms (UINT16 sco_inx, + tBTM_ESCO_DATA *p_parms); + +/******************************************************************************* +** +** Function BTM_ChangeEScoLinkParms +** +** Description This function requests renegotiation of the parameters on +** the current eSCO Link. If any of the changes are accepted +** by the controllers, the BTM_ESCO_CHG_EVT event is sent in +** the tBTM_ESCO_CBACK function with the current settings of +** the link. The callback is registered through the call to +** BTM_SetEScoMode. +** +** +** Returns BTM_CMD_STARTED if command is successfully initiated. +** BTM_ILLEGAL_VALUE if no connection for specified sco_inx. +** BTM_NO_RESOURCES - not enough resources to initiate command. +** BTM_MODE_UNSUPPORTED if local controller does not support +** 1.2 specification. +** +*******************************************************************************/ +//extern +tBTM_STATUS BTM_ChangeEScoLinkParms (UINT16 sco_inx, + tBTM_CHG_ESCO_PARAMS *p_parms); + +/******************************************************************************* +** +** Function BTM_EScoConnRsp +** +** Description This function is called upon receipt of an (e)SCO connection +** request event (BTM_ESCO_CONN_REQ_EVT) to accept or reject +** the request. Parameters used to negotiate eSCO links. +** If p_parms is NULL, then values set through BTM_SetEScoMode +** are used. +** If the link type of the incoming request is SCO, then only +** the tx_bw, max_latency, content format, and packet_types are +** valid. The hci_status parameter should be +** ([0x0] to accept, [0x0d..0x0f] to reject) +** +** +** Returns void +** +*******************************************************************************/ +//extern +void BTM_EScoConnRsp (UINT16 sco_inx, UINT8 hci_status, + tBTM_ESCO_PARAMS *p_parms); + +/******************************************************************************* +** +** Function BTM_GetNumScoLinks +** +** Description This function returns the number of active SCO links. +** +** Returns UINT8 +** +*******************************************************************************/ +//extern +UINT8 BTM_GetNumScoLinks (void); + +/***************************************************************************** +** SECURITY MANAGEMENT FUNCTIONS +*****************************************************************************/ +/******************************************************************************* +** +** Function BTM_SecRegister +** +** Description Application manager calls this function to register for +** security services. There can be one and only one application +** saving link keys. BTM allows only first registration. +** +** Returns TRUE if registered OK, else FALSE +** +*******************************************************************************/ +//extern +BOOLEAN BTM_SecRegister (tBTM_APPL_INFO *p_cb_info); + +/******************************************************************************* +** +** Function BTM_SecRegisterLinkKeyNotificationCallback +** +** Description Profiles can register to be notified when a new Link Key +** is generated per connection. +** +** Returns TRUE if registered OK, else FALSE +** +*******************************************************************************/ +//extern +BOOLEAN BTM_SecRegisterLinkKeyNotificationCallback( + tBTM_LINK_KEY_CALLBACK *p_callback); + +/******************************************************************************* +** +** Function BTM_SecAddRmtNameNotifyCallback +** +** Description Profiles can register to be notified when name of the +** remote device is resolved (up to BTM_SEC_MAX_RMT_NAME_CALLBACKS). +** +** Returns TRUE if registered OK, else FALSE +** +*******************************************************************************/ +//extern +BOOLEAN BTM_SecAddRmtNameNotifyCallback (tBTM_RMT_NAME_CALLBACK *p_callback); + + +/******************************************************************************* +** +** Function BTM_SecDeleteRmtNameNotifyCallback +** +** Description A profile can deregister notification when a new Link Key +** is generated per connection. +** +** Returns TRUE if OK, else FALSE +** +*******************************************************************************/ +//extern +BOOLEAN BTM_SecDeleteRmtNameNotifyCallback (tBTM_RMT_NAME_CALLBACK *p_callback); + +/******************************************************************************* +** +** Function BTM_GetSecurityFlags +** +** Description Get security flags for the device +** +** Returns BOOLEAN TRUE or FALSE is device found +** +*******************************************************************************/ +//extern +BOOLEAN BTM_GetSecurityFlags (BD_ADDR bd_addr, UINT8 * p_sec_flags); + +/******************************************************************************* +** +** Function BTM_GetSecurityFlagsByTransport +** +** Description Get security flags for the device on a particular transport +** +** Parameters bd_addr: BD address of remote device +** p_sec_flags : Out parameter to be filled with security flags for the connection +** transport : Physical transport of the connection (BR/EDR or LE) +** +** Returns BOOLEAN TRUE or FALSE is device found +** +*******************************************************************************/ +//extern +BOOLEAN BTM_GetSecurityFlagsByTransport (BD_ADDR bd_addr, + UINT8 * p_sec_flags, tBT_TRANSPORT transport); + +/******************************************************************************* +** +** Function BTM_ReadTrustedMask +** +** Description Get trusted mask for the device +** +** Returns NULL, if the device record is not found. +** otherwise, the trusted mask +** +*******************************************************************************/ +//extern +UINT32 * BTM_ReadTrustedMask (BD_ADDR bd_addr); + +/******************************************************************************* +** +** Function BTM_SetPinType +** +** Description Set PIN type for the device. +** +** Returns void +** +*******************************************************************************/ +//extern +void BTM_SetPinType (UINT8 pin_type, PIN_CODE pin_code, UINT8 pin_code_len); + + +/******************************************************************************* +** +** Function BTM_SetPairableMode +** +** Description Enable or disable pairing +** +** Parameters allow_pairing - (TRUE or FALSE) whether or not the device +** allows pairing. +** connect_only_paired - (TRUE or FALSE) whether or not to +** only allow paired devices to connect. +** +** Returns void +** +*******************************************************************************/ +//extern +void BTM_SetPairableMode (BOOLEAN allow_pairing, BOOLEAN connect_only_paired); + +/******************************************************************************* +** +** Function BTM_SetSecureConnectionsOnly +** +** Description Enable or disable default treatment for Mode 4 Level 0 services +** +** Parameter secure_connections_only_mode - (TRUE or FALSE) +** TRUE means that the device should treat Mode 4 Level 0 services as +** services of other levels. +** FALSE means that the device should provide default treatment for +** Mode 4 Level 0 services. +** +** Returns void +** +*******************************************************************************/ +//extern +void BTM_SetSecureConnectionsOnly (BOOLEAN secure_connections_only_mode); + +/******************************************************************************* +** +** Function BTM_SetSecurityLevel +** +** Description Register service security level with Security Manager. Each +** service must register its requirements regardless of the +** security level that is used. This API is called once for originators +** nad again for acceptors of connections. +** +** Returns TRUE if registered OK, else FALSE +** +*******************************************************************************/ +//extern +BOOLEAN BTM_SetSecurityLevel (BOOLEAN is_originator, char *p_name, + UINT8 service_id, UINT16 sec_level, + UINT16 psm, UINT32 mx_proto_id, + UINT32 mx_chan_id); + +/******************************************************************************* +** +** Function BTM_SetOutService +** +** Description This function is called to set the service for +** outgoing connection. +** +** Returns void +** +*******************************************************************************/ +//extern +void BTM_SetOutService(BD_ADDR bd_addr, UINT8 service_id, UINT32 mx_chan_id); + +/******************************************************************************* +** +** Function BTM_SecClrService +** +** Description Removes specified service record(s) from the security database. +** All service records with the specified name are removed. +** Typically used only by devices with limited RAM so that it can +** reuse an old security service record. +** records (except SDP). +** +** Returns Number of records that were freed. +** +*******************************************************************************/ +//extern +UINT8 BTM_SecClrService (UINT8 service_id); + +/******************************************************************************* +** +** Function BTM_SecAddDevice +** +** Description Add/modify device. This function will be normally called +** during host startup to restore all required information +** stored in the NVRAM. +** dev_class, bd_name, link_key, and features are NULL if unknown +** +** Returns TRUE if added OK, else FALSE +** +*******************************************************************************/ +//extern +BOOLEAN BTM_SecAddDevice (BD_ADDR bd_addr, DEV_CLASS dev_class, + BD_NAME bd_name, UINT8 *features, + UINT32 trusted_mask[], LINK_KEY link_key, + UINT8 key_type, tBTM_IO_CAP io_cap, UINT8 pin_length); + + +/******************************************************************************* +** +** Function BTM_SecDeleteDevice +** +** Description Free resources associated with the device. +** +** Returns TRUE if rmoved OK, FALSE if not found +** +*******************************************************************************/ +//extern +BOOLEAN BTM_SecDeleteDevice (BD_ADDR bd_addr); + + +/******************************************************************************* +** +** Function BTM_SecGetDeviceLinkKey +** +** Description This function is called to obtain link key for the device +** it returns BTM_SUCCESS if link key is available, or +** BTM_UNKNOWN_ADDR if Security Manager does not know about +** the device or device record does not contain link key info +** +** Returns BTM_SUCCESS if successful, otherwise error code +** +*******************************************************************************/ +//extern +tBTM_STATUS BTM_SecGetDeviceLinkKey (BD_ADDR bd_addr, + LINK_KEY link_key); + + +/******************************************************************************* +** +** Function BTM_SecGetDeviceLinkKeyType +** +** Description This function is called to obtain link key type for the +** device. +** it returns BTM_SUCCESS if link key is available, or +** BTM_UNKNOWN_ADDR if Security Manager does not know about +** the device or device record does not contain link key info +** +** Returns BTM_LKEY_TYPE_IGNORE if link key is unknown, link type +** otherwise. +** +*******************************************************************************/ +//extern +tBTM_LINK_KEY_TYPE BTM_SecGetDeviceLinkKeyType (BD_ADDR bd_addr); + + +/******************************************************************************* +** +** Function BTM_PINCodeReply +** +** Description This function is called after Security Manager submitted +** PIN code request to the UI. +** +** Parameters: bd_addr - Address of the device for which PIN was requested +** res - result of the operation BTM_SUCCESS if success +** pin_len - length in bytes of the PIN Code +** p_pin - pointer to array with the PIN Code +** trusted_mask - bitwise OR of trusted services (array of UINT32) +** +** Returns void +** +*******************************************************************************/ +//extern +void BTM_PINCodeReply (BD_ADDR bd_addr, UINT8 res, UINT8 pin_len, + UINT8 *p_pin, UINT32 trusted_mask[]); + + +/******************************************************************************* +** +** Function BTM_SecBond +** +** Description This function is called to perform bonding with peer device. +** +** Parameters: bd_addr - Address of the device to bond +** pin_len - length in bytes of the PIN Code +** p_pin - pointer to array with the PIN Code +** trusted_mask - bitwise OR of trusted services (array of UINT32) + +** Returns BTM_CMD_STARTED if successfully initiated, otherwise error +** +*******************************************************************************/ +//extern +tBTM_STATUS BTM_SecBond (BD_ADDR bd_addr, + UINT8 pin_len, UINT8 *p_pin, + UINT32 trusted_mask[]); + +/******************************************************************************* +** +** Function BTM_SecBondByTransport +** +** Description This function is called to perform bonding by designated transport +** +** Parameters: bd_addr - Address of the device to bond +** pin_len - length in bytes of the PIN Code +** p_pin - pointer to array with the PIN Code +** trusted_mask - bitwise OR of trusted services (array of UINT32) +** transport : Physical transport to use for bonding (BR/EDR or LE) +** +** Returns BTM_CMD_STARTED if successfully initiated, otherwise error +** +*******************************************************************************/ +//extern +tBTM_STATUS BTM_SecBondByTransport (BD_ADDR bd_addr, + tBT_TRANSPORT transport, + UINT8 pin_len, UINT8 *p_pin, + UINT32 trusted_mask[]); + +/******************************************************************************* +** +** Function BTM_SecBondCancel +** +** Description This function is called to cancel ongoing bonding process +** with peer device. +** +** Returns BTM_CMD_STARTED if successfully initiated, otherwise error +** +*******************************************************************************/ +//extern +tBTM_STATUS BTM_SecBondCancel (BD_ADDR bd_addr); + +/******************************************************************************* +** +** Function BTM_SetEncryption +** +** Description This function is called to ensure that connection is +** encrypted. Should be called only on an open connection. +** Typically only needed for connections that first want to +** bring up unencrypted links, then later encrypt them. +** +** Parameters: bd_addr - Address of the peer device +** p_callback - Pointer to callback function called if +** this function returns PENDING after required +** procedures are completed. Can be set to NULL +** if status is not desired. +** p_ref_data - pointer to any data the caller wishes to receive +** in the callback function upon completion. +* can be set to NULL if not used. +** +** Returns BTM_SUCCESS - already encrypted +** BTM_PENDING - command will be returned in the callback +** BTM_WRONG_MODE- connection not up. +** BTM_BUSY - security procedures are currently active +** BTM_MODE_UNSUPPORTED - if security manager not linked in. +** +*******************************************************************************/ +//extern +tBTM_STATUS BTM_SetEncryption (BD_ADDR bd_addr, tBT_TRANSPORT transport, + tBTM_SEC_CBACK *p_callback, void *p_ref_data); + +/******************************************************************************* +** +** Function BTM_ConfirmReqReply +** +** Description This function is called to confirm the numeric value for +** Simple Pairing in response to BTM_SP_CFM_REQ_EVT +** +** Parameters: res - result of the operation BTM_SUCCESS if success +** bd_addr - Address of the peer device +** +*******************************************************************************/ +//extern +void BTM_ConfirmReqReply(tBTM_STATUS res, BD_ADDR bd_addr); + +/******************************************************************************* +** +** Function BTM_PasskeyReqReply +** +** Description This function is called to provide the passkey for +** Simple Pairing in response to BTM_SP_KEY_REQ_EVT +** +** Parameters: res - result of the operation BTM_SUCCESS if success +** bd_addr - Address of the peer device +** passkey - numeric value in the range of 0 - 999999(0xF423F). +** +*******************************************************************************/ +//extern +void BTM_PasskeyReqReply(tBTM_STATUS res, BD_ADDR bd_addr, UINT32 passkey); + +/******************************************************************************* +** +** Function BTM_SendKeypressNotif +** +** Description This function is used during the passkey entry model +** by a device with KeyboardOnly IO capabilities +** (very likely to be a HID Device). +** It is called by a HID Device to inform the remote device when +** a key has been entered or erased. +** +** Parameters: bd_addr - Address of the peer device +** type - notification type +** +*******************************************************************************/ +//extern +void BTM_SendKeypressNotif(BD_ADDR bd_addr, tBTM_SP_KEY_TYPE type); + +/******************************************************************************* +** +** Function BTM_IoCapRsp +** +** Description This function is called in response to BTM_SP_IO_REQ_EVT +** When the event data io_req.oob_data is set to BTM_OOB_UNKNOWN +** by the tBTM_SP_CALLBACK implementation, this function is +** called to provide the actual response +** +** Parameters: bd_addr - Address of the peer device +** io_cap - The IO capability of local device. +** oob - BTM_OOB_NONE or BTM_OOB_PRESENT. +** auth_req- MITM protection required or not. +** +*******************************************************************************/ +//extern +void BTM_IoCapRsp(BD_ADDR bd_addr, tBTM_IO_CAP io_cap, + tBTM_OOB_DATA oob, tBTM_AUTH_REQ auth_req); + +/******************************************************************************* +** +** Function BTM_ReadLocalOobData +** +** Description This function is called to read the local OOB data from +** LM +** +*******************************************************************************/ +//extern +tBTM_STATUS BTM_ReadLocalOobData(void); + +/******************************************************************************* +** +** Function BTM_RemoteOobDataReply +** +** Description This function is called to provide the remote OOB data for +** Simple Pairing in response to BTM_SP_RMT_OOB_EVT +** +** Parameters: bd_addr - Address of the peer device +** c - simple pairing Hash C. +** r - simple pairing Randomizer C. +** +*******************************************************************************/ +//extern +void BTM_RemoteOobDataReply(tBTM_STATUS res, BD_ADDR bd_addr, + BT_OCTET16 c, BT_OCTET16 r); + +/******************************************************************************* +** +** Function BTM_BuildOobData +** +** Description This function is called to build the OOB data payload to +** be sent over OOB (non-Bluetooth) link +** +** Parameters: p_data - the location for OOB data +** max_len - p_data size. +** c - simple pairing Hash C. +** r - simple pairing Randomizer C. +** name_len- 0, local device name would not be included. +** otherwise, the local device name is included for +** up to this specified length +** +** Returns Number of bytes in p_data. +** +*******************************************************************************/ +//extern +UINT16 BTM_BuildOobData(UINT8 *p_data, UINT16 max_len, BT_OCTET16 c, + BT_OCTET16 r, UINT8 name_len); + +/******************************************************************************* +** +** Function BTM_BothEndsSupportSecureConnections +** +** Description This function is called to check if both the local device and the peer device +** specified by bd_addr support BR/EDR Secure Connections. +** +** Parameters: bd_addr - address of the peer +** +** Returns TRUE if BR/EDR Secure Connections are supported by both local +** and the remote device. +** else FALSE. +** +*******************************************************************************/ +//extern +BOOLEAN BTM_BothEndsSupportSecureConnections(BD_ADDR bd_addr); + +/******************************************************************************* +** +** Function BTM_PeerSupportsSecureConnections +** +** Description This function is called to check if the peer supports +** BR/EDR Secure Connections. +** +** Parameters: bd_addr - address of the peer +** +** Returns TRUE if BR/EDR Secure Connections are supported by the peer, +** else FALSE. +** +*******************************************************************************/ +//extern +BOOLEAN BTM_PeerSupportsSecureConnections(BD_ADDR bd_addr); + +/******************************************************************************* +** +** Function BTM_ReadOobData +** +** Description This function is called to parse the OOB data payload +** received over OOB (non-Bluetooth) link +** +** Parameters: p_data - the location for OOB data +** eir_tag - The associated EIR tag to read the data. +** *p_len(output) - the length of the data with the given tag. +** +** Returns the beginning of the data with the given tag. +** NULL, if the tag is not found. +** +*******************************************************************************/ +//extern +UINT8 * BTM_ReadOobData(UINT8 *p_data, UINT8 eir_tag, UINT8 *p_len); + +/******************************************************************************* +** +** Function BTM_SecReadDevName +** +** Description Looks for the device name in the security database for the +** specified BD address. +** +** Returns Pointer to the name or NULL +** +*******************************************************************************/ +//extern +char *BTM_SecReadDevName (BD_ADDR bd_addr); + + +/***************************************************************************** +** POWER MANAGEMENT FUNCTIONS +*****************************************************************************/ +/******************************************************************************* +** +** Function BTM_PmRegister +** +** Description register or deregister with power manager +** +** Returns BTM_SUCCESS if successful, +** BTM_NO_RESOURCES if no room to hold registration +** BTM_ILLEGAL_VALUE +** +*******************************************************************************/ +//extern +tBTM_STATUS BTM_PmRegister (UINT8 mask, UINT8 *p_pm_id, + tBTM_PM_STATUS_CBACK *p_cb); + + +/******************************************************************************* +** +** Function BTM_SetPowerMode +** +** Description store the mode in control block or +** alter ACL connection behavior. +** +** Returns BTM_SUCCESS if successful, +** BTM_UNKNOWN_ADDR if bd addr is not active or bad +** +*******************************************************************************/ +//extern +tBTM_STATUS BTM_SetPowerMode (UINT8 pm_id, BD_ADDR remote_bda, + tBTM_PM_PWR_MD *p_mode); + + +/******************************************************************************* +** +** Function BTM_ReadPowerMode +** +** Description This returns the current mode for a specific +** ACL connection. +** +** Input Param remote_bda - device address of desired ACL connection +** +** Output Param p_mode - address where the current mode is copied into. +** BTM_ACL_MODE_NORMAL +** BTM_ACL_MODE_HOLD +** BTM_ACL_MODE_SNIFF +** BTM_ACL_MODE_PARK +** (valid only if return code is BTM_SUCCESS) +** +** Returns BTM_SUCCESS if successful, +** BTM_UNKNOWN_ADDR if bd addr is not active or bad +** +*******************************************************************************/ +//extern +tBTM_STATUS BTM_ReadPowerMode (BD_ADDR remote_bda, + tBTM_PM_MODE *p_mode); + +/******************************************************************************* +** +** Function BTM_SetSsrParams +** +** Description This sends the given SSR parameters for the given ACL +** connection if it is in ACTIVE mode. +** +** Input Param remote_bda - device address of desired ACL connection +** max_lat - maximum latency (in 0.625ms)(0-0xFFFE) +** min_rmt_to - minimum remote timeout +** min_loc_to - minimum local timeout +** +** +** Returns BTM_SUCCESS if the HCI command is issued successful, +** BTM_UNKNOWN_ADDR if bd addr is not active or bad +** BTM_CMD_STORED if the command is stored +** +*******************************************************************************/ +//extern +tBTM_STATUS BTM_SetSsrParams (BD_ADDR remote_bda, UINT16 max_lat, + UINT16 min_rmt_to, UINT16 min_loc_to); + +/******************************************************************************* +** +** Function BTM_GetHCIConnHandle +** +** Description This function is called to get the handle for an ACL connection +** to a specific remote BD Address. +** +** Returns the handle of the connection, or 0xFFFF if none. +** +*******************************************************************************/ +//extern +UINT16 BTM_GetHCIConnHandle (BD_ADDR remote_bda, tBT_TRANSPORT transport); + +/******************************************************************************* +** +** Function BTM_DeleteStoredLinkKey +** +** Description This function is called to delete link key for the specified +** device addresses from the NVRAM storage attached to the Bluetooth +** controller. +** +** Parameters: bd_addr - Addresses of the devices +** p_cb - Call back function to be called to return +** the results +** +*******************************************************************************/ +//extern +tBTM_STATUS BTM_DeleteStoredLinkKey(BD_ADDR bd_addr, tBTM_CMPL_CB *p_cb); + +/******************************************************************************* +** +** Function BTM_WriteEIR +** +** Description This function is called to write EIR data to controller. +** +** Parameters p_buff - allocated HCI command buffer including extended +** inquriry response +** +** Returns BTM_SUCCESS - if successful +** BTM_MODE_UNSUPPORTED - if local device cannot support it +** +*******************************************************************************/ +//extern +tBTM_STATUS BTM_WriteEIR( BT_HDR * p_buff ); + +/******************************************************************************* +** +** Function BTM_CheckEirData +** +** Description This function is called to get EIR data from significant part. +** +** Parameters p_eir - pointer of EIR significant part +** type - finding EIR data type +** p_length - return the length of EIR data +** +** Returns pointer of EIR data +** +*******************************************************************************/ +//extern +UINT8 *BTM_CheckEirData( UINT8 *p_eir, UINT8 type, UINT8 *p_length ); + +/******************************************************************************* +** +** Function BTM_HasEirService +** +** Description This function is called to know if UUID in bit map of UUID. +** +** Parameters p_eir_uuid - bit map of UUID list +** uuid16 - UUID 16-bit +** +** Returns TRUE - if found +** FALSE - if not found +** +*******************************************************************************/ +//extern +BOOLEAN BTM_HasEirService( UINT32 *p_eir_uuid, UINT16 uuid16 ); + +/******************************************************************************* +** +** Function BTM_HasInquiryEirService +** +** Description This function is called to know if UUID in bit map of UUID list. +** +** Parameters p_results - inquiry results +** uuid16 - UUID 16-bit +** +** Returns BTM_EIR_FOUND - if found +** BTM_EIR_NOT_FOUND - if not found and it is complete list +** BTM_EIR_UNKNOWN - if not found and it is not complete list +** +*******************************************************************************/ +//extern +tBTM_EIR_SEARCH_RESULT BTM_HasInquiryEirService( tBTM_INQ_RESULTS *p_results, + UINT16 uuid16 ); + +/******************************************************************************* +** +** Function BTM_AddEirService +** +** Description This function is called to add a service in bit map of UUID list. +** +** Parameters p_eir_uuid - bit mask of UUID list for EIR +** uuid16 - UUID 16-bit +** +** Returns None +** +*******************************************************************************/ +//extern +void BTM_AddEirService( UINT32 *p_eir_uuid, UINT16 uuid16 ); + +/******************************************************************************* +** +** Function BTM_RemoveEirService +** +** Description This function is called to remove a service in bit map of UUID list. +** +** Parameters p_eir_uuid - bit mask of UUID list for EIR +** uuid16 - UUID 16-bit +** +** Returns None +** +*******************************************************************************/ +//extern +void BTM_RemoveEirService( UINT32 *p_eir_uuid, UINT16 uuid16 ); + +/******************************************************************************* +** +** Function BTM_GetEirSupportedServices +** +** Description This function is called to get UUID list from bit map of UUID list. +** +** Parameters p_eir_uuid - bit mask of UUID list for EIR +** p - reference of current pointer of EIR +** max_num_uuid16 - max number of UUID can be written in EIR +** num_uuid16 - number of UUID have been written in EIR +** +** Returns BTM_EIR_MORE_16BITS_UUID_TYPE, if it has more than max +** BTM_EIR_COMPLETE_16BITS_UUID_TYPE, otherwise +** +*******************************************************************************/ +//extern +UINT8 BTM_GetEirSupportedServices( UINT32 *p_eir_uuid, UINT8 **p, + UINT8 max_num_uuid16, UINT8 *p_num_uuid16); + +/******************************************************************************* +** +** Function BTM_GetEirUuidList +** +** Description This function parses EIR and returns UUID list. +** +** Parameters p_eir - EIR +** uuid_size - LEN_UUID_16, LEN_UUID_32, LEN_UUID_128 +** p_num_uuid - return number of UUID in found list +** p_uuid_list - return UUID 16-bit list +** max_num_uuid - maximum number of UUID to be returned +** +** Returns 0 - if not found +** BTM_EIR_COMPLETE_16BITS_UUID_TYPE +** BTM_EIR_MORE_16BITS_UUID_TYPE +** BTM_EIR_COMPLETE_32BITS_UUID_TYPE +** BTM_EIR_MORE_32BITS_UUID_TYPE +** BTM_EIR_COMPLETE_128BITS_UUID_TYPE +** BTM_EIR_MORE_128BITS_UUID_TYPE +** +*******************************************************************************/ +//extern +UINT8 BTM_GetEirUuidList( UINT8 *p_eir, UINT8 uuid_size, UINT8 *p_num_uuid, + UINT8 *p_uuid_list, UINT8 max_num_uuid); + +/***************************************************************************** +** SCO OVER HCI +*****************************************************************************/ +/******************************************************************************* +** +** Function BTM_ConfigScoPath +** +** Description This function enable/disable SCO over HCI and registers SCO +** data callback if SCO over HCI is enabled. +** +** Parameter path: SCO or HCI +** p_sco_data_cb: callback function or SCO data if path is set +** to transport. +** p_pcm_param: pointer to the PCM interface parameter. If a NULL +** pointer is used, PCM parameter maintained in +** the control block will be used; otherwise update +** control block value. +** err_data_rpt: Lisbon feature to enable the erronous data report +** or not. +** +** Returns BTM_SUCCESS if the successful. +** BTM_NO_RESOURCES: no rsource to start the command. +** BTM_ILLEGAL_VALUE: invalid callback function pointer. +** BTM_CMD_STARTED :Command sent. Waiting for command cmpl event. +** +** +*******************************************************************************/ +//extern +tBTM_STATUS BTM_ConfigScoPath (tBTM_SCO_ROUTE_TYPE path, + tBTM_SCO_DATA_CB *p_sco_data_cb, + tBTM_SCO_PCM_PARAM *p_pcm_param, + BOOLEAN err_data_rpt); + +/******************************************************************************* +** +** Function BTM_WriteScoData +** +** Description This function write SCO data to a specified instance. The data +** to be written p_buf needs to carry an offset of +** HCI_SCO_PREAMBLE_SIZE bytes, and the data length can not +** exceed BTM_SCO_DATA_SIZE_MAX bytes, whose default value is set +** to 60 and is configurable. Data longer than the maximum bytes +** will be truncated. +** +** Returns BTM_SUCCESS: data write is successful +** BTM_ILLEGAL_VALUE: SCO data contains illegal offset value. +** BTM_SCO_BAD_LENGTH: SCO data length exceeds the max SCO packet +** size. +** BTM_NO_RESOURCES: no resources. +** BTM_UNKNOWN_ADDR: unknown SCO connection handle, or SCO is not +** routed via HCI. +** +** +*******************************************************************************/ +//extern +tBTM_STATUS BTM_WriteScoData (UINT16 sco_inx, BT_HDR *p_buf); + +/******************************************************************************* +** +** Function BTM_SetARCMode +** +** Description Send Audio Routing Control command. +** +** Returns void +** +*******************************************************************************/ +//extern +void BTM_SetARCMode (UINT8 iface, UINT8 arc_mode, tBTM_VSC_CMPL_CB *p_arc_cb); + + +/******************************************************************************* +** +** Function BTM_PCM2Setup_Write +** +** Description Send PCM2_Setup write command. +** +** Returns void +** +*******************************************************************************/ +//extern +void BTM_PCM2Setup_Write (BOOLEAN clk_master, tBTM_VSC_CMPL_CB *p_arc_cb); + + +/******************************************************************************* +** +** Function BTM_PM_ReadControllerState +** +** Description This function is called to obtain the controller state +** +** Returns Controller state (BTM_CONTRL_ACTIVE, BTM_CONTRL_SCAN, and BTM_CONTRL_IDLE) +** +*******************************************************************************/ +//extern +tBTM_CONTRL_STATE BTM_PM_ReadControllerState(void); +/* +#ifdef __cplusplus +} +#endif +*/ + +#endif /* BTM_API_H */ diff --git a/components/bt/bluedroid/stack/include/btm_ble_api.h b/components/bt/bluedroid/stack/include/btm_ble_api.h new file mode 100755 index 0000000000..ce55ef6c58 --- /dev/null +++ b/components/bt/bluedroid/stack/include/btm_ble_api.h @@ -0,0 +1,1924 @@ +/****************************************************************************** + * + * Copyright (C) 1999-2012 Broadcom Corporation + * + * 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 Bluetooth Manager (BTM) API function external + * definitions. + * + ******************************************************************************/ +#ifndef BTM_BLE_API_H +#define BTM_BLE_API_H + +#include "bt_defs.h" +#include "btm_api.h" +#include "gki.h" +#include "bt_common_types.h" + +#define CHANNEL_MAP_LEN 5 +typedef UINT8 tBTM_BLE_CHNL_MAP[CHANNEL_MAP_LEN]; + +/* 0x00-0x04 only used for set advertising parameter command */ +#define BTM_BLE_CONNECT_EVT 0x00 /* 0x00-0x04 only used for set advertising + parameter command */ +#define BTM_BLE_CONNECT_DIR_EVT 0x01 /* Connectable directed advertising */ +#define BTM_BLE_DISCOVER_EVT 0x02 /* Scannable undirected advertising */ +#define BTM_BLE_NON_CONNECT_EVT 0x03 /* Non connectable undirected advertising */ +#define BTM_BLE_CONNECT_LO_DUTY_DIR_EVT 0x04 /* Connectable low duty + cycle directed advertising */ + /* 0x00 - 0x05 can be received on adv event type */ +#define BTM_BLE_SCAN_RSP_EVT 0x04 +#define BTM_BLE_SCAN_REQ_EVT 0x05 +#define BTM_BLE_UNKNOWN_EVT 0xff + +#define BTM_BLE_UNKNOWN_EVT 0xff + +typedef UINT8 tBTM_BLE_EVT; +typedef UINT8 tBTM_BLE_CONN_MODE; + +typedef UINT32 tBTM_BLE_REF_VALUE; + +#define BTM_BLE_SCAN_MODE_PASS 0 +#define BTM_BLE_SCAN_MODE_ACTI 1 +#define BTM_BLE_SCAN_MODE_NONE 0xff +typedef UINT8 tBLE_SCAN_MODE; + +#define BTM_BLE_BATCH_SCAN_MODE_DISABLE 0 +#define BTM_BLE_BATCH_SCAN_MODE_PASS 1 +#define BTM_BLE_BATCH_SCAN_MODE_ACTI 2 +#define BTM_BLE_BATCH_SCAN_MODE_PASS_ACTI 3 + +typedef UINT8 tBTM_BLE_BATCH_SCAN_MODE; + +/* advertising channel map */ +#define BTM_BLE_ADV_CHNL_37 (0x01 << 0) +#define BTM_BLE_ADV_CHNL_38 (0x01 << 1) +#define BTM_BLE_ADV_CHNL_39 (0x01 << 2) +typedef UINT8 tBTM_BLE_ADV_CHNL_MAP; + +/*d efault advertising channel map */ +#ifndef BTM_BLE_DEFAULT_ADV_CHNL_MAP +#define BTM_BLE_DEFAULT_ADV_CHNL_MAP (BTM_BLE_ADV_CHNL_37| BTM_BLE_ADV_CHNL_38| BTM_BLE_ADV_CHNL_39) +#endif + +/* advertising filter policy */ +#define AP_SCAN_CONN_ALL 0x00 /* default */ +#define AP_SCAN_WL_CONN_ALL 0x01 +#define AP_SCAN_ALL_CONN_WL 0x02 +#define AP_SCAN_CONN_WL 0x03 +#define AP_SCAN_CONN_POLICY_MAX 0x04 +typedef UINT8 tBTM_BLE_AFP; + +/* default advertising filter policy */ +#ifndef BTM_BLE_DEFAULT_AFP +#define BTM_BLE_DEFAULT_AFP AP_SCAN_CONN_ALL +#endif + +/* scanning filter policy */ +#define SP_ADV_ALL 0x00 /* 0: accept adv packet from all, directed adv pkt not directed */ + /* to local device is ignored */ +#define SP_ADV_WL 0x01 /* 1: accept adv packet from device in white list, directed adv */ + /* packet not directed to local device is ignored */ +#define SP_ADV_ALL_RPA_DIR_ADV 0x02 /* 2: accept adv packet from all, directed adv pkt */ + /* not directed to me is ignored except direct adv with RPA */ +#define SP_ADV_WL_RPA_DIR_ADV 0x03 /* 3: accept adv packet from device in white list, directed */ + /* adv pkt not directed to me is ignored except direct adv */ + /* with RPA */ +typedef UINT8 tBTM_BLE_SFP; + +#ifndef BTM_BLE_DEFAULT_SFP +#define BTM_BLE_DEFAULT_SFP SP_ADV_ALL +#endif + +/* adv parameter boundary values */ +#define BTM_BLE_ADV_INT_MIN 0x0020 +#define BTM_BLE_ADV_INT_MAX 0x4000 + +/* Full scan boundary values */ +#define BTM_BLE_ADV_SCAN_FULL_MIN 0x00 +#define BTM_BLE_ADV_SCAN_FULL_MAX 0x64 + +/* Partial scan boundary values */ +#define BTM_BLE_ADV_SCAN_TRUNC_MIN BTM_BLE_ADV_SCAN_FULL_MIN +#define BTM_BLE_ADV_SCAN_TRUNC_MAX BTM_BLE_ADV_SCAN_FULL_MAX + +/* Threshold values */ +#define BTM_BLE_ADV_SCAN_THR_MIN BTM_BLE_ADV_SCAN_FULL_MIN +#define BTM_BLE_ADV_SCAN_THR_MAX BTM_BLE_ADV_SCAN_FULL_MAX + +/* connection parameter boundary values */ +#define BTM_BLE_SCAN_INT_MIN 0x0004 +#define BTM_BLE_SCAN_INT_MAX 0x4000 +#define BTM_BLE_SCAN_WIN_MIN 0x0004 +#define BTM_BLE_SCAN_WIN_MAX 0x4000 +#define BTM_BLE_EXT_SCAN_INT_MAX 0x00FFFFFF +#define BTM_BLE_EXT_SCAN_WIN_MAX 0xFFFF +#define BTM_BLE_CONN_INT_MIN 0x0006 +#define BTM_BLE_CONN_INT_MAX 0x0C80 +#define BTM_BLE_CONN_LATENCY_MAX 500 +#define BTM_BLE_CONN_SUP_TOUT_MIN 0x000A +#define BTM_BLE_CONN_SUP_TOUT_MAX 0x0C80 +#define BTM_BLE_CONN_PARAM_UNDEF 0xffff /* use this value when a specific value not to be overwritten */ +#define BTM_BLE_SCAN_PARAM_UNDEF 0xffffffff + +/* default connection parameters if not configured, use GAP recommend value for auto/selective connection */ +/* default scan interval */ +#ifndef BTM_BLE_SCAN_FAST_INT +#define BTM_BLE_SCAN_FAST_INT 96 /* 30 ~ 60 ms (use 60) = 96 *0.625 */ +#endif +/* default scan window for background connection, applicable for auto connection or selective conenction */ +#ifndef BTM_BLE_SCAN_FAST_WIN +#define BTM_BLE_SCAN_FAST_WIN 48 /* 30 ms = 48 *0.625 */ +#endif + +/* default scan paramter used in reduced power cycle (background scanning) */ +#ifndef BTM_BLE_SCAN_SLOW_INT_1 +#define BTM_BLE_SCAN_SLOW_INT_1 2048 /* 1.28 s = 2048 *0.625 */ +#endif +#ifndef BTM_BLE_SCAN_SLOW_WIN_1 +#define BTM_BLE_SCAN_SLOW_WIN_1 48 /* 30 ms = 48 *0.625 */ +#endif + +/* default scan paramter used in reduced power cycle (background scanning) */ +#ifndef BTM_BLE_SCAN_SLOW_INT_2 +#define BTM_BLE_SCAN_SLOW_INT_2 4096 /* 2.56 s = 4096 *0.625 */ +#endif +#ifndef BTM_BLE_SCAN_SLOW_WIN_2 +#define BTM_BLE_SCAN_SLOW_WIN_2 36 /* 22.5 ms = 36 *0.625 */ +#endif + +/* default connection interval min */ +#ifndef BTM_BLE_CONN_INT_MIN_DEF +#define BTM_BLE_CONN_INT_MIN_DEF 24 /* recommended min: 30ms = 24 * 1.25 */ +#endif + +/* default connectino interval max */ +#ifndef BTM_BLE_CONN_INT_MAX_DEF +#define BTM_BLE_CONN_INT_MAX_DEF 40 /* recommended max: 50 ms = 56 * 1.25 */ +#endif + +/* default slave latency */ +#ifndef BTM_BLE_CONN_SLAVE_LATENCY_DEF +#define BTM_BLE_CONN_SLAVE_LATENCY_DEF 0 /* 0 */ +#endif + +/* default supervision timeout */ +#ifndef BTM_BLE_CONN_TIMEOUT_DEF +#define BTM_BLE_CONN_TIMEOUT_DEF 2000 +#endif + +/* minimum acceptable connection interval */ +#ifndef BTM_BLE_CONN_INT_MIN_LIMIT +#define BTM_BLE_CONN_INT_MIN_LIMIT 0x0009 +#endif + +#define BTM_BLE_DIR_CONN_FALLBACK_UNDIR 1 +#define BTM_BLE_DIR_CONN_FALLBACK_NO_ADV 2 + +#ifndef BTM_BLE_DIR_CONN_FALLBACK +#define BTM_BLE_DIR_CONN_FALLBACK BTM_BLE_DIR_CONN_FALLBACK_UNDIR +#endif + +#define BTM_CMAC_TLEN_SIZE 8 /* 64 bits */ +#define BTM_BLE_AUTH_SIGN_LEN 12 /* BLE data signature length 8 Bytes + 4 bytes counter*/ +typedef UINT8 BLE_SIGNATURE[BTM_BLE_AUTH_SIGN_LEN]; /* Device address */ + +#ifndef BTM_BLE_HOST_SUPPORT +#define BTM_BLE_HOST_SUPPORT 0x01 +#endif + +#ifndef BTM_BLE_SIMULTANEOUS_HOST +#define BTM_BLE_SIMULTANEOUS_HOST 0x01 +#endif + +/* Appearance Values Reported with BTM_BLE_AD_TYPE_APPEARANCE */ +#define BTM_BLE_APPEARANCE_UKNOWN 0x0000 +#define BTM_BLE_APPEARANCE_GENERIC_PHONE 0x0040 +#define BTM_BLE_APPEARANCE_GENERIC_COMPUTER 0x0080 +#define BTM_BLE_APPEARANCE_GENERIC_WATCH 0x00C0 +#define BTM_BLE_APPEARANCE_SPORTS_WATCH 0x00C1 +#define BTM_BLE_APPEARANCE_GENERIC_CLOCK 0x0100 +#define BTM_BLE_APPEARANCE_GENERIC_DISPLAY 0x0140 +#define BTM_BLE_APPEARANCE_GENERIC_REMOTE 0x0180 +#define BTM_BLE_APPEARANCE_GENERIC_EYEGLASSES 0x01C0 +#define BTM_BLE_APPEARANCE_GENERIC_TAG 0x0200 +#define BTM_BLE_APPEARANCE_GENERIC_KEYRING 0x0240 +#define BTM_BLE_APPEARANCE_GENERIC_MEDIA_PLAYER 0x0280 +#define BTM_BLE_APPEARANCE_GENERIC_BARCODE_SCANNER 0x02C0 +#define BTM_BLE_APPEARANCE_GENERIC_THERMOMETER 0x0300 +#define BTM_BLE_APPEARANCE_THERMOMETER_EAR 0x0301 +#define BTM_BLE_APPEARANCE_GENERIC_HEART_RATE 0x0340 +#define BTM_BLE_APPEARANCE_HEART_RATE_BELT 0x0341 +#define BTM_BLE_APPEARANCE_GENERIC_BLOOD_PRESSURE 0x0380 +#define BTM_BLE_APPEARANCE_BLOOD_PRESSURE_ARM 0x0381 +#define BTM_BLE_APPEARANCE_BLOOD_PRESSURE_WRIST 0x0382 +#define BTM_BLE_APPEARANCE_GENERIC_HID 0x03C0 +#define BTM_BLE_APPEARANCE_HID_KEYBOARD 0x03C1 +#define BTM_BLE_APPEARANCE_HID_MOUSE 0x03C2 +#define BTM_BLE_APPEARANCE_HID_JOYSTICK 0x03C3 +#define BTM_BLE_APPEARANCE_HID_GAMEPAD 0x03C4 +#define BTM_BLE_APPEARANCE_HID_DIGITIZER_TABLET 0x03C5 +#define BTM_BLE_APPEARANCE_HID_CARD_READER 0x03C6 +#define BTM_BLE_APPEARANCE_HID_DIGITAL_PEN 0x03C7 +#define BTM_BLE_APPEARANCE_HID_BARCODE_SCANNER 0x03C8 +#define BTM_BLE_APPEARANCE_GENERIC_GLUCOSE 0x0400 +#define BTM_BLE_APPEARANCE_GENERIC_WALKING 0x0440 +#define BTM_BLE_APPEARANCE_WALKING_IN_SHOE 0x0441 +#define BTM_BLE_APPEARANCE_WALKING_ON_SHOE 0x0442 +#define BTM_BLE_APPEARANCE_WALKING_ON_HIP 0x0443 +#define BTM_BLE_APPEARANCE_GENERIC_CYCLING 0x0480 +#define BTM_BLE_APPEARANCE_CYCLING_COMPUTER 0x0481 +#define BTM_BLE_APPEARANCE_CYCLING_SPEED 0x0482 +#define BTM_BLE_APPEARANCE_CYCLING_CADENCE 0x0483 +#define BTM_BLE_APPEARANCE_CYCLING_POWER 0x0484 +#define BTM_BLE_APPEARANCE_CYCLING_SPEED_CADENCE 0x0485 +#define BTM_BLE_APPEARANCE_GENERIC_PULSE_OXIMETER 0x0C40 +#define BTM_BLE_APPEARANCE_PULSE_OXIMETER_FINGERTIP 0x0C41 +#define BTM_BLE_APPEARANCE_PULSE_OXIMETER_WRIST 0x0C42 +#define BTM_BLE_APPEARANCE_GENERIC_WEIGHT 0x0C80 +#define BTM_BLE_APPEARANCE_GENERIC_OUTDOOR_SPORTS 0x1440 +#define BTM_BLE_APPEARANCE_OUTDOOR_SPORTS_LOCATION 0x1441 +#define BTM_BLE_APPEARANCE_OUTDOOR_SPORTS_LOCATION_AND_NAV 0x1442 +#define BTM_BLE_APPEARANCE_OUTDOOR_SPORTS_LOCATION_POD 0x1443 +#define BTM_BLE_APPEARANCE_OUTDOOR_SPORTS_LOCATION_POD_AND_NAV 0x1444 + + +/* Structure returned with Rand/Encrypt complete callback */ +typedef struct +{ + UINT8 status; + UINT8 param_len; + UINT16 opcode; + UINT8 param_buf[BT_OCTET16_LEN]; +} tBTM_RAND_ENC; + +/* General callback function for notifying an application that a synchronous +** BTM function is complete. The pointer contains the address of any returned data. +*/ +typedef void (tBTM_RAND_ENC_CB) (tBTM_RAND_ENC *p1); + +#define BTM_BLE_FILTER_TARGET_SCANNER 0x01 +#define BTM_BLE_FILTER_TARGET_ADVR 0x00 + +#define BTM_BLE_POLICY_BLACK_ALL 0x00 /* relevant to both */ +#define BTM_BLE_POLICY_ALLOW_SCAN 0x01 /* relevant to advertiser */ +#define BTM_BLE_POLICY_ALLOW_CONN 0x02 /* relevant to advertiser */ +#define BTM_BLE_POLICY_WHITE_ALL 0x03 /* relevant to both */ + +/* ADV data flag bit definition used for BTM_BLE_AD_TYPE_FLAG */ +#define BTM_BLE_LIMIT_DISC_FLAG (0x01 << 0) +#define BTM_BLE_GEN_DISC_FLAG (0x01 << 1) +#define BTM_BLE_BREDR_NOT_SPT (0x01 << 2) +/* 4.1 spec adv flag for simultaneous BR/EDR+LE connection support */ +#define BTM_BLE_DMT_CONTROLLER_SPT (0x01 << 3) +#define BTM_BLE_DMT_HOST_SPT (0x01 << 4) +#define BTM_BLE_NON_LIMIT_DISC_FLAG (0x00 ) /* lowest bit unset */ +#define BTM_BLE_ADV_FLAG_MASK (BTM_BLE_LIMIT_DISC_FLAG | BTM_BLE_BREDR_NOT_SPT | BTM_BLE_GEN_DISC_FLAG) +#define BTM_BLE_LIMIT_DISC_MASK (BTM_BLE_LIMIT_DISC_FLAG ) + +#define BTM_BLE_AD_BIT_DEV_NAME (0x00000001 << 0) +#define BTM_BLE_AD_BIT_FLAGS (0x00000001 << 1) +#define BTM_BLE_AD_BIT_MANU (0x00000001 << 2) +#define BTM_BLE_AD_BIT_TX_PWR (0x00000001 << 3) +#define BTM_BLE_AD_BIT_INT_RANGE (0x00000001 << 5) +#define BTM_BLE_AD_BIT_SERVICE (0x00000001 << 6) +#define BTM_BLE_AD_BIT_SERVICE_SOL (0x00000001 << 7) +#define BTM_BLE_AD_BIT_SERVICE_DATA (0x00000001 << 8) +#define BTM_BLE_AD_BIT_SIGN_DATA (0x00000001 << 9) +#define BTM_BLE_AD_BIT_SERVICE_128SOL (0x00000001 << 10) +#define BTM_BLE_AD_BIT_APPEARANCE (0x00000001 << 11) +#define BTM_BLE_AD_BIT_PUBLIC_ADDR (0x00000001 << 12) +#define BTM_BLE_AD_BIT_RANDOM_ADDR (0x00000001 << 13) +#define BTM_BLE_AD_BIT_SERVICE_32 (0x00000001 << 4) +#define BTM_BLE_AD_BIT_SERVICE_32SOL (0x00000001 << 14) +#define BTM_BLE_AD_BIT_PROPRIETARY (0x00000001 << 15) +#define BTM_BLE_AD_BIT_SERVICE_128 (0x00000001 << 16) /*128-bit Service UUIDs*/ + +typedef UINT32 tBTM_BLE_AD_MASK; + +#define BTM_BLE_AD_TYPE_FLAG HCI_EIR_FLAGS_TYPE /* 0x01 */ +#define BTM_BLE_AD_TYPE_16SRV_PART HCI_EIR_MORE_16BITS_UUID_TYPE /* 0x02 */ +#define BTM_BLE_AD_TYPE_16SRV_CMPL HCI_EIR_COMPLETE_16BITS_UUID_TYPE /* 0x03 */ +#define BTM_BLE_AD_TYPE_32SRV_PART HCI_EIR_MORE_32BITS_UUID_TYPE /* 0x04 */ +#define BTM_BLE_AD_TYPE_32SRV_CMPL HCI_EIR_COMPLETE_32BITS_UUID_TYPE /* 0x05 */ +#define BTM_BLE_AD_TYPE_128SRV_PART HCI_EIR_MORE_128BITS_UUID_TYPE /* 0x06 */ +#define BTM_BLE_AD_TYPE_128SRV_CMPL HCI_EIR_COMPLETE_128BITS_UUID_TYPE /* 0x07 */ +#define BTM_BLE_AD_TYPE_NAME_SHORT HCI_EIR_SHORTENED_LOCAL_NAME_TYPE /* 0x08 */ +#define BTM_BLE_AD_TYPE_NAME_CMPL HCI_EIR_COMPLETE_LOCAL_NAME_TYPE /* 0x09 */ +#define BTM_BLE_AD_TYPE_TX_PWR HCI_EIR_TX_POWER_LEVEL_TYPE /* 0x0A */ +#define BTM_BLE_AD_TYPE_DEV_CLASS 0x0D +#define BTM_BLE_AD_TYPE_SM_TK 0x10 +#define BTM_BLE_AD_TYPE_SM_OOB_FLAG 0x11 +#define BTM_BLE_AD_TYPE_INT_RANGE 0x12 +#define BTM_BLE_AD_TYPE_SOL_SRV_UUID 0x14 +#define BTM_BLE_AD_TYPE_128SOL_SRV_UUID 0x15 +#define BTM_BLE_AD_TYPE_SERVICE_DATA 0x16 +#define BTM_BLE_AD_TYPE_PUBLIC_TARGET 0x17 +#define BTM_BLE_AD_TYPE_RANDOM_TARGET 0x18 +#define BTM_BLE_AD_TYPE_APPEARANCE 0x19 +#define BTM_BLE_AD_TYPE_ADV_INT 0x1a +#define BTM_BLE_AD_TYPE_32SOL_SRV_UUID 0x1b +#define BTM_BLE_AD_TYPE_32SERVICE_DATA 0x1c +#define BTM_BLE_AD_TYPE_128SERVICE_DATA 0x1d + +#define BTM_BLE_AD_TYPE_MANU HCI_EIR_MANUFACTURER_SPECIFIC_TYPE /* 0xff */ +typedef UINT8 tBTM_BLE_AD_TYPE; + +/* Security settings used with L2CAP LE COC */ +#define BTM_SEC_LE_LINK_ENCRYPTED 0x01 +#define BTM_SEC_LE_LINK_PAIRED_WITHOUT_MITM 0x02 +#define BTM_SEC_LE_LINK_PAIRED_WITH_MITM 0x04 + +/* Min/max Preferred number of payload octets that the local Controller + should include in a single Link Layer Data Channel PDU. */ +#define BTM_BLE_DATA_SIZE_MAX 0x00fb +#define BTM_BLE_DATA_SIZE_MIN 0x001b + +/* Preferred maximum number of microseconds that the local Controller + should use to transmit a single Link Layer Data Channel PDU. */ +#define BTM_BLE_DATA_TX_TIME_MIN 0x0148 +#define BTM_BLE_DATA_TX_TIME_MAX 0x0848 + +/* adv tx power level */ +#define BTM_BLE_ADV_TX_POWER_MIN 0 /* minimum tx power */ +#define BTM_BLE_ADV_TX_POWER_LOW 1 /* low tx power */ +#define BTM_BLE_ADV_TX_POWER_MID 2 /* middle tx power */ +#define BTM_BLE_ADV_TX_POWER_UPPER 3 /* upper tx power */ +#define BTM_BLE_ADV_TX_POWER_MAX 4 /* maximum tx power */ +typedef UINT8 tBTM_BLE_ADV_TX_POWER; + +/* adv tx power in dBm */ +typedef struct +{ + UINT8 adv_inst_max; /* max adv instance supported in controller */ + UINT8 rpa_offloading; + UINT16 tot_scan_results_strg; + UINT8 max_irk_list_sz; + UINT8 filter_support; + UINT8 max_filter; + UINT8 energy_support; + BOOLEAN values_read; + UINT16 version_supported; + UINT16 total_trackable_advertisers; + UINT8 extended_scan_support; + UINT8 debug_logging_supported; +}tBTM_BLE_VSC_CB; + +/* slave preferred connection interval range */ +typedef struct +{ + UINT16 low; + UINT16 hi; + +}tBTM_BLE_INT_RANGE; + +/* Service tag supported in the device */ +typedef struct +{ + UINT8 num_service; + BOOLEAN list_cmpl; + UINT16 *p_uuid; +}tBTM_BLE_SERVICE; + +/* 32 bits Service supported in the device */ +typedef struct +{ + UINT8 num_service; + BOOLEAN list_cmpl; + UINT32 *p_uuid; +}tBTM_BLE_32SERVICE; + +/* 128 bits Service supported in the device */ +typedef struct +{ + BOOLEAN list_cmpl; + UINT8 uuid128[MAX_UUID_SIZE]; +}tBTM_BLE_128SERVICE; + +typedef struct +{ + UINT8 len; + UINT8 *p_val; +}tBTM_BLE_MANU; + + +typedef struct +{ + tBT_UUID service_uuid; + UINT8 len; + UINT8 *p_val; +}tBTM_BLE_SERVICE_DATA; + +typedef struct +{ + UINT8 adv_type; + UINT8 len; + UINT8 *p_val; /* number of len byte */ +}tBTM_BLE_PROP_ELEM; + +typedef struct +{ + UINT8 num_elem; + tBTM_BLE_PROP_ELEM *p_elem; +}tBTM_BLE_PROPRIETARY; + +typedef struct +{ + tBTM_BLE_INT_RANGE int_range; /* slave prefered conn interval range */ + tBTM_BLE_MANU *p_manu; /* manufactuer data */ + tBTM_BLE_SERVICE *p_services; /* services */ + tBTM_BLE_128SERVICE *p_services_128b; /* 128 bits service */ + tBTM_BLE_32SERVICE *p_service_32b; /* 32 bits Service UUID */ + tBTM_BLE_SERVICE *p_sol_services; /* 16 bits services Solicitation UUIDs */ + tBTM_BLE_32SERVICE *p_sol_service_32b; /* List of 32 bit Service Solicitation UUIDs */ + tBTM_BLE_128SERVICE *p_sol_service_128b; /* List of 128 bit Service Solicitation UUIDs */ + tBTM_BLE_PROPRIETARY *p_proprietary; + tBTM_BLE_SERVICE_DATA *p_service_data; /* service data */ + UINT16 appearance; + UINT8 flag; + UINT8 tx_power; +}tBTM_BLE_ADV_DATA; + +#ifndef BTM_BLE_MULTI_ADV_MAX +#define BTM_BLE_MULTI_ADV_MAX 16 /* controller returned adv_inst_max should be less + than this number */ +#endif + +#define BTM_BLE_MULTI_ADV_INVALID 0 + +#define BTM_BLE_MULTI_ADV_ENB_EVT 1 +#define BTM_BLE_MULTI_ADV_DISABLE_EVT 2 +#define BTM_BLE_MULTI_ADV_PARAM_EVT 3 +#define BTM_BLE_MULTI_ADV_DATA_EVT 4 +typedef UINT8 tBTM_BLE_MULTI_ADV_EVT; + +#define BTM_BLE_MULTI_ADV_DEFAULT_STD 0 + +typedef struct +{ + UINT16 adv_int_min; + UINT16 adv_int_max; + UINT8 adv_type; + tBTM_BLE_ADV_CHNL_MAP channel_map; + tBTM_BLE_AFP adv_filter_policy; + tBTM_BLE_ADV_TX_POWER tx_power; +}tBTM_BLE_ADV_PARAMS; + +typedef struct +{ + UINT8 *p_sub_code; /* dynamic array to store sub code */ + UINT8 *p_inst_id; /* dynamic array to store instance id */ + UINT8 pending_idx; + UINT8 next_idx; +}tBTM_BLE_MULTI_ADV_OPQ; + +typedef void (tBTM_BLE_MULTI_ADV_CBACK)(tBTM_BLE_MULTI_ADV_EVT evt, UINT8 inst_id, + void *p_ref, tBTM_STATUS status); + +typedef struct +{ + UINT8 inst_id; + BOOLEAN in_use; + UINT8 adv_evt; + BD_ADDR rpa; + TIMER_LIST_ENT raddr_timer_ent; + tBTM_BLE_MULTI_ADV_CBACK *p_cback; + void *p_ref; + UINT8 index; +}tBTM_BLE_MULTI_ADV_INST; + +typedef struct +{ + UINT8 inst_index_queue[BTM_BLE_MULTI_ADV_MAX]; + int front; + int rear; +}tBTM_BLE_MULTI_ADV_INST_IDX_Q; + +typedef struct +{ + tBTM_BLE_MULTI_ADV_INST *p_adv_inst; /* dynamic array to store adv instance */ + tBTM_BLE_MULTI_ADV_OPQ op_q; +}tBTM_BLE_MULTI_ADV_CB; + +typedef UINT8 tGATT_IF; + +typedef void (tBTM_BLE_SCAN_THRESHOLD_CBACK)(tBTM_BLE_REF_VALUE ref_value); +typedef void (tBTM_BLE_SCAN_REP_CBACK)(tBTM_BLE_REF_VALUE ref_value, UINT8 report_format, + UINT8 num_records, UINT16 total_len, + UINT8* p_rep_data, UINT8 status); +typedef void (tBTM_BLE_SCAN_SETUP_CBACK)(UINT8 evt, tBTM_BLE_REF_VALUE ref_value, UINT8 status); + +#ifndef BTM_BLE_BATCH_SCAN_MAX +#define BTM_BLE_BATCH_SCAN_MAX 5 +#endif + +#ifndef BTM_BLE_BATCH_REP_MAIN_Q_SIZE +#define BTM_BLE_BATCH_REP_MAIN_Q_SIZE 2 +#endif + +typedef enum +{ + BTM_BLE_SCAN_INVALID_STATE=0, + BTM_BLE_SCAN_ENABLE_CALLED=1, + BTM_BLE_SCAN_ENABLED_STATE=2, + BTM_BLE_SCAN_DISABLE_CALLED=3, + BTM_BLE_SCAN_DISABLED_STATE=4 +}tBTM_BLE_BATCH_SCAN_STATE; + +enum +{ + BTM_BLE_DISCARD_OLD_ITEMS, + BTM_BLE_DISCARD_LOWER_RSSI_ITEMS +}; +typedef UINT8 tBTM_BLE_DISCARD_RULE; + +typedef struct +{ + UINT8 sub_code[BTM_BLE_BATCH_SCAN_MAX]; + tBTM_BLE_BATCH_SCAN_STATE cur_state[BTM_BLE_BATCH_SCAN_MAX]; + tBTM_BLE_REF_VALUE ref_value[BTM_BLE_BATCH_SCAN_MAX]; + UINT8 pending_idx; + UINT8 next_idx; +}tBTM_BLE_BATCH_SCAN_OPQ; + +typedef struct +{ + UINT8 rep_mode[BTM_BLE_BATCH_REP_MAIN_Q_SIZE]; + tBTM_BLE_REF_VALUE ref_value[BTM_BLE_BATCH_REP_MAIN_Q_SIZE]; + UINT8 num_records[BTM_BLE_BATCH_REP_MAIN_Q_SIZE]; + UINT16 data_len[BTM_BLE_BATCH_REP_MAIN_Q_SIZE]; + UINT8 *p_data[BTM_BLE_BATCH_REP_MAIN_Q_SIZE]; + UINT8 pending_idx; + UINT8 next_idx; +}tBTM_BLE_BATCH_SCAN_REP_Q; + +typedef struct +{ + tBTM_BLE_BATCH_SCAN_STATE cur_state; + tBTM_BLE_BATCH_SCAN_MODE scan_mode; + UINT32 scan_interval; + UINT32 scan_window; + tBLE_ADDR_TYPE addr_type; + tBTM_BLE_DISCARD_RULE discard_rule; + tBTM_BLE_BATCH_SCAN_OPQ op_q; + tBTM_BLE_BATCH_SCAN_REP_Q main_rep_q; + tBTM_BLE_SCAN_SETUP_CBACK *p_setup_cback; + tBTM_BLE_SCAN_THRESHOLD_CBACK *p_thres_cback; + tBTM_BLE_SCAN_REP_CBACK *p_scan_rep_cback; + tBTM_BLE_REF_VALUE ref_value; +}tBTM_BLE_BATCH_SCAN_CB; + +/* filter selection bit index */ +#define BTM_BLE_PF_ADDR_FILTER 0 +#define BTM_BLE_PF_SRVC_DATA 1 +#define BTM_BLE_PF_SRVC_UUID 2 +#define BTM_BLE_PF_SRVC_SOL_UUID 3 +#define BTM_BLE_PF_LOCAL_NAME 4 +#define BTM_BLE_PF_MANU_DATA 5 +#define BTM_BLE_PF_SRVC_DATA_PATTERN 6 +#define BTM_BLE_PF_TYPE_ALL 7 /* when passed in payload filter type all, only clear action is applicable */ +#define BTM_BLE_PF_TYPE_MAX 8 + +/* max number of filter spot for different filter type */ +#ifndef BTM_BLE_MAX_UUID_FILTER +#define BTM_BLE_MAX_UUID_FILTER 8 +#endif +#ifndef BTM_BLE_MAX_ADDR_FILTER +#define BTM_BLE_MAX_ADDR_FILTER 8 +#endif +#ifndef BTM_BLE_PF_STR_COND_MAX +#define BTM_BLE_PF_STR_COND_MAX 4 /* apply to manu data , or local name */ +#endif +#ifndef BTM_BLE_PF_STR_LEN_MAX +#define BTM_BLE_PF_STR_LEN_MAX 29 /* match for first 29 bytes */ +#endif + +typedef UINT8 tBTM_BLE_PF_COND_TYPE; + +#define BTM_BLE_PF_LOGIC_OR 0 +#define BTM_BLE_PF_LOGIC_AND 1 +typedef UINT8 tBTM_BLE_PF_LOGIC_TYPE; + +#define BTM_BLE_PF_ENABLE 1 +#define BTM_BLE_PF_CONFIG 2 +typedef UINT8 tBTM_BLE_PF_ACTION; + +typedef UINT8 tBTM_BLE_PF_FILT_INDEX; + +typedef UINT8 tBTM_BLE_PF_AVBL_SPACE; + +#define BTM_BLE_PF_BRDCAST_ADDR_FILT 1 +#define BTM_BLE_PF_SERV_DATA_CHG_FILT 2 +#define BTM_BLE_PF_SERV_UUID 4 +#define BTM_BLE_PF_SERV_SOLC_UUID 8 +#define BTM_BLE_PF_LOC_NAME_CHECK 16 +#define BTM_BLE_PF_MANUF_NAME_CHECK 32 +#define BTM_BLE_PF_SERV_DATA_CHECK 64 +typedef UINT16 tBTM_BLE_PF_FEAT_SEL; + +#define BTM_BLE_PF_LIST_LOGIC_OR 1 +#define BTM_BLE_PF_LIST_LOGIC_AND 2 +typedef UINT16 tBTM_BLE_PF_LIST_LOGIC_TYPE; + +#define BTM_BLE_PF_FILT_LOGIC_OR 0 +#define BTM_BLE_PF_FILT_LOGIC_AND 1 +typedef UINT16 tBTM_BLE_PF_FILT_LOGIC_TYPE; + +typedef UINT8 tBTM_BLE_PF_RSSI_THRESHOLD; +typedef UINT8 tBTM_BLE_PF_DELIVERY_MODE; +typedef UINT16 tBTM_BLE_PF_TIMEOUT; +typedef UINT8 tBTM_BLE_PF_TIMEOUT_CNT; +typedef UINT16 tBTM_BLE_PF_ADV_TRACK_ENTRIES; + +typedef struct +{ + tBTM_BLE_PF_FEAT_SEL feat_seln; + tBTM_BLE_PF_LIST_LOGIC_TYPE logic_type; + tBTM_BLE_PF_FILT_LOGIC_TYPE filt_logic_type; + tBTM_BLE_PF_RSSI_THRESHOLD rssi_high_thres; + tBTM_BLE_PF_RSSI_THRESHOLD rssi_low_thres; + tBTM_BLE_PF_DELIVERY_MODE dely_mode; + tBTM_BLE_PF_TIMEOUT found_timeout; + tBTM_BLE_PF_TIMEOUT lost_timeout; + tBTM_BLE_PF_TIMEOUT_CNT found_timeout_cnt; + tBTM_BLE_PF_ADV_TRACK_ENTRIES num_of_tracking_entries; +}tBTM_BLE_PF_FILT_PARAMS; + +enum +{ + BTM_BLE_SCAN_COND_ADD, + BTM_BLE_SCAN_COND_DELETE, + BTM_BLE_SCAN_COND_CLEAR = 2 +}; +typedef UINT8 tBTM_BLE_SCAN_COND_OP; + +enum +{ + BTM_BLE_FILT_ENABLE_DISABLE = 1, + BTM_BLE_FILT_CFG = 2, + BTM_BLE_FILT_ADV_PARAM = 3 +}; + +typedef UINT8 tBTM_BLE_FILT_CB_EVT; + +/* BLE adv payload filtering config complete callback */ +typedef void (tBTM_BLE_PF_CFG_CBACK)(tBTM_BLE_PF_ACTION action, tBTM_BLE_SCAN_COND_OP cfg_op, + tBTM_BLE_PF_AVBL_SPACE avbl_space, tBTM_STATUS status, + tBTM_BLE_REF_VALUE ref_value); + +typedef void (tBTM_BLE_PF_CMPL_CBACK) (tBTM_BLE_PF_CFG_CBACK); + +/* BLE adv payload filtering status setup complete callback */ +typedef void (tBTM_BLE_PF_STATUS_CBACK) (UINT8 action, tBTM_STATUS status, + tBTM_BLE_REF_VALUE ref_value); + +/* BLE adv payload filtering param setup complete callback */ +typedef void (tBTM_BLE_PF_PARAM_CBACK) (tBTM_BLE_PF_ACTION action_type, + tBTM_BLE_PF_AVBL_SPACE avbl_space, + tBTM_BLE_REF_VALUE ref_value, tBTM_STATUS status); + +typedef union +{ + UINT16 uuid16_mask; + UINT32 uuid32_mask; + UINT8 uuid128_mask[LEN_UUID_128]; +}tBTM_BLE_PF_COND_MASK; + +typedef struct +{ + tBLE_BD_ADDR *p_target_addr; /* target address, if NULL, generic UUID filter */ + tBT_UUID uuid; /* UUID condition */ + tBTM_BLE_PF_LOGIC_TYPE cond_logic; /* AND/OR */ + tBTM_BLE_PF_COND_MASK *p_uuid_mask; /* UUID mask */ +}tBTM_BLE_PF_UUID_COND; + +typedef struct +{ + UINT8 data_len; /* <= 20 bytes */ + UINT8 *p_data; +}tBTM_BLE_PF_LOCAL_NAME_COND; + +typedef struct +{ + UINT16 company_id; /* company ID */ + UINT8 data_len; /* <= 20 bytes */ + UINT8 *p_pattern; + UINT16 company_id_mask; /* UUID value mask */ + UINT8 *p_pattern_mask; /* Manufacturer data matching mask, + same length as data pattern, + set to all 0xff, match exact data */ +}tBTM_BLE_PF_MANU_COND; + +typedef struct +{ + UINT16 uuid; /* service ID */ + UINT8 data_len; /* <= 20 bytes */ + UINT8 *p_pattern; + UINT8 *p_pattern_mask; /* Service data matching mask, same length as data pattern, + set to all 0xff, match exact data */ +}tBTM_BLE_PF_SRVC_PATTERN_COND; + + +typedef union +{ + tBLE_BD_ADDR target_addr; + tBTM_BLE_PF_LOCAL_NAME_COND local_name; /* lcoal name filtering */ + tBTM_BLE_PF_MANU_COND manu_data; /* manufactuer data filtering */ + tBTM_BLE_PF_UUID_COND srvc_uuid; /* service UUID filtering */ + tBTM_BLE_PF_UUID_COND solicitate_uuid; /* solicitated service UUID filtering */ + tBTM_BLE_PF_SRVC_PATTERN_COND srvc_data; /* service data pattern */ +}tBTM_BLE_PF_COND_PARAM; + +typedef struct +{ + UINT8 action_ocf[BTM_BLE_PF_TYPE_MAX]; + tBTM_BLE_REF_VALUE ref_value[BTM_BLE_PF_TYPE_MAX]; + tBTM_BLE_PF_PARAM_CBACK *p_filt_param_cback[BTM_BLE_PF_TYPE_MAX]; + tBTM_BLE_PF_CFG_CBACK *p_scan_cfg_cback[BTM_BLE_PF_TYPE_MAX]; + UINT8 cb_evt[BTM_BLE_PF_TYPE_MAX]; + UINT8 pending_idx; + UINT8 next_idx; +}tBTM_BLE_ADV_FILTER_ADV_OPQ; + +#define BTM_BLE_MAX_FILTER_COUNTER (BTM_BLE_MAX_ADDR_FILTER + 1) /* per device filter + one generic filter indexed by 0 */ + +#ifndef BTM_CS_IRK_LIST_MAX +#define BTM_CS_IRK_LIST_MAX 0x20 +#endif + +typedef struct +{ + BOOLEAN in_use; + BD_ADDR bd_addr; + UINT8 pf_counter[BTM_BLE_PF_TYPE_MAX]; /* number of filter indexed by tBTM_BLE_PF_COND_TYPE */ +}tBTM_BLE_PF_COUNT; + +typedef struct +{ + BOOLEAN enable; + UINT8 op_type; + tBTM_BLE_PF_COUNT *p_addr_filter_count; /* per BDA filter array */ + tBLE_BD_ADDR cur_filter_target; + tBTM_BLE_PF_STATUS_CBACK *p_filt_stat_cback; + tBTM_BLE_ADV_FILTER_ADV_OPQ op_q; +}tBTM_BLE_ADV_FILTER_CB; + +/* Sub codes */ +#define BTM_BLE_META_PF_ENABLE 0x00 +#define BTM_BLE_META_PF_FEAT_SEL 0x01 +#define BTM_BLE_META_PF_ADDR 0x02 +#define BTM_BLE_META_PF_UUID 0x03 +#define BTM_BLE_META_PF_SOL_UUID 0x04 +#define BTM_BLE_META_PF_LOCAL_NAME 0x05 +#define BTM_BLE_META_PF_MANU_DATA 0x06 +#define BTM_BLE_META_PF_SRVC_DATA 0x07 +#define BTM_BLE_META_PF_ALL 0x08 + +typedef UINT8 BTM_BLE_ADV_STATE; +typedef UINT8 BTM_BLE_ADV_INFO_PRESENT; +typedef UINT8 BTM_BLE_RSSI_VALUE; +typedef UINT16 BTM_BLE_ADV_INFO_TIMESTAMP; + +/* These are the fields returned in each device adv packet. It +** is returned in the results callback if registered. +*/ +typedef struct +{ + UINT8 conn_mode; + tBTM_BLE_AD_MASK ad_mask; /* mask of the valid adv data field */ + UINT8 flag; + UINT8 tx_power_level; + UINT8 remote_name_len; + UINT8 *p_remote_name; + tBTM_BLE_SERVICE service; +} tBTM_BLE_INQ_DATA; + +enum +{ + BTM_BLE_CONN_NONE, + BTM_BLE_CONN_AUTO, + BTM_BLE_CONN_SELECTIVE +}; +typedef UINT8 tBTM_BLE_CONN_TYPE; + +#define ADV_INFO_PRESENT 0x00 +#define NO_ADV_INFO_PRESENT 0x01 + +typedef btgatt_track_adv_info_t tBTM_BLE_TRACK_ADV_DATA; + +typedef void (tBTM_BLE_TRACK_ADV_CBACK)(tBTM_BLE_TRACK_ADV_DATA *p_track_adv_data); + +typedef UINT8 tBTM_BLE_TRACK_ADV_EVT; + +typedef struct +{ + tBTM_BLE_REF_VALUE ref_value; + tBTM_BLE_TRACK_ADV_CBACK *p_track_cback; +}tBTM_BLE_ADV_TRACK_CB; + +enum +{ + BTM_BLE_TRACK_ADV_ADD, + BTM_BLE_TRACK_ADV_REMOVE +}; + +typedef UINT8 tBTM_BLE_TRACK_ADV_ACTION; + +#define BTM_BLE_MULTI_ADV_INVALID 0 + +#define BTM_BLE_BATCH_SCAN_ENABLE_EVT 1 +#define BTM_BLE_BATCH_SCAN_CFG_STRG_EVT 2 +#define BTM_BLE_BATCH_SCAN_READ_REPTS_EVT 3 +#define BTM_BLE_BATCH_SCAN_THR_EVT 4 +#define BTM_BLE_BATCH_SCAN_PARAM_EVT 5 +#define BTM_BLE_BATCH_SCAN_DISABLE_EVT 6 + +typedef UINT8 tBTM_BLE_BATCH_SCAN_EVT; + +typedef UINT32 tBTM_BLE_TX_TIME_MS; +typedef UINT32 tBTM_BLE_RX_TIME_MS; +typedef UINT32 tBTM_BLE_IDLE_TIME_MS; +typedef UINT32 tBTM_BLE_ENERGY_USED; + +typedef void (tBTM_BLE_ENERGY_INFO_CBACK)(tBTM_BLE_TX_TIME_MS tx_time, tBTM_BLE_RX_TIME_MS rx_time, + tBTM_BLE_IDLE_TIME_MS idle_time, + tBTM_BLE_ENERGY_USED energy_used, + tBTM_STATUS status); + +typedef struct +{ + tBTM_BLE_ENERGY_INFO_CBACK *p_ener_cback; +}tBTM_BLE_ENERGY_INFO_CB; + +typedef BOOLEAN (tBTM_BLE_SEL_CBACK)(BD_ADDR random_bda, UINT8 *p_remote_name); +typedef void (tBTM_BLE_CTRL_FEATURES_CBACK)(tBTM_STATUS status); + +/* callback function for SMP signing algorithm, signed data in little endian order with tlen bits long */ +typedef void (tBTM_BLE_SIGN_CBACK)(void *p_ref_data, UINT8 *p_signing_data); +typedef void (tBTM_BLE_VERIFY_CBACK)(void *p_ref_data, BOOLEAN match); +/* random address set complete callback */ +typedef void (tBTM_BLE_RANDOM_SET_CBACK) (BD_ADDR random_bda); + +typedef void (tBTM_BLE_SCAN_REQ_CBACK)(BD_ADDR remote_bda, tBLE_ADDR_TYPE addr_type, UINT8 adv_evt); +typedef void (*tBLE_SCAN_PARAM_SETUP_CBACK)(tGATT_IF client_if, tBTM_STATUS status); + +tBTM_BLE_SCAN_SETUP_CBACK bta_ble_scan_setup_cb; + +/***************************************************************************** +** EXTERNAL FUNCTION DECLARATIONS +*****************************************************************************/ +/* +#ifdef __cplusplus +extern "C" { +#endif +*/ +/******************************************************************************* +** +** Function BTM_SecAddBleDevice +** +** Description Add/modify device. This function will be normally called +** during host startup to restore all required information +** for a LE device stored in the NVRAM. +** +** Parameters: bd_addr - BD address of the peer +** bd_name - Name of the peer device. NULL if unknown. +** dev_type - Remote device's device type. +** addr_type - LE device address type. +** +** Returns TRUE if added OK, else FALSE +** +*******************************************************************************/ +//extern +BOOLEAN BTM_SecAddBleDevice (BD_ADDR bd_addr, BD_NAME bd_name, + tBT_DEVICE_TYPE dev_type, tBLE_ADDR_TYPE addr_type); + +/******************************************************************************* +** +** Function BTM_SecAddBleKey +** +** Description Add/modify LE device information. This function will be +** normally called during host startup to restore all required +** information stored in the NVRAM. +** +** Parameters: bd_addr - BD address of the peer +** p_le_key - LE key values. +** key_type - LE SMP key type. +* +** Returns TRUE if added OK, else FALSE +** +*******************************************************************************/ +//extern +BOOLEAN BTM_SecAddBleKey (BD_ADDR bd_addr, tBTM_LE_KEY_VALUE *p_le_key, + tBTM_LE_KEY_TYPE key_type); + +/******************************************************************************* +** +** Function BTM_BleSetAdvParams +** +** Description This function is called to set advertising parameters. +** +** Parameters: None. +** +** Returns void +** +*******************************************************************************/ +//extern +tBTM_STATUS BTM_BleSetAdvParams(UINT16 adv_int_min, UINT16 adv_int_max, + tBLE_BD_ADDR *p_dir_bda, tBTM_BLE_ADV_CHNL_MAP chnl_map); + +/******************************************************************************* +** +** Function BTM_BleWriteAdvData +** +** Description This function is called to write advertising data. +** +** Parameters: None. +** +** Returns void +** +*******************************************************************************/ +//extern +tBTM_STATUS BTM_BleWriteAdvData(tBTM_BLE_AD_MASK data_mask, + tBTM_BLE_ADV_DATA *p_data); + +BOOLEAN BTM_BleSetRandAddress(BD_ADDR rand_addr); + + +/******************************************************************************* +** +** Function BTM_BleSetAdvParams +** +** Description This function is called to set advertising parameters. +** +** Parameters adv_int_min: minimum advertising interval +** adv_int_max: maximum advertising interval +** p_dir_bda: connectable direct initiator's LE device address +** chnl_map: advertising channel map. +** +** Returns void +** +*******************************************************************************/ +//extern +void BTM_BleReadAdvParams (UINT16 *adv_int_min, UINT16 *adv_int_max, + tBLE_BD_ADDR *p_dir_bda, tBTM_BLE_ADV_CHNL_MAP *p_chnl_map); + +/******************************************************************************* +** +** Function BTM_BleObtainVendorCapabilities +** +** Description This function is called to obatin vendor capabilties +** +** Parameters p_cmn_vsc_cb - Returns the vednor capabilities +** +** Returns void +** +*******************************************************************************/ +//extern +void BTM_BleObtainVendorCapabilities(tBTM_BLE_VSC_CB *p_cmn_vsc_cb); + +/******************************************************************************* +** +** Function BTM_BleSetScanParams +** +** Description This function is called to set Scan parameters. +** +** Parameters client_if - Client IF value +** scan_interval - Scan interval +** scan_window - Scan window +** scan_type - Scan type +** scan_setup_status_cback - Scan setup status callback +** +** Returns void +** +*******************************************************************************/ +//extern +void BTM_BleSetScanParams(tGATT_IF client_if, UINT32 scan_interval, + UINT32 scan_window, tBLE_SCAN_MODE scan_type, + tBLE_SCAN_PARAM_SETUP_CBACK scan_setup_status_cback); + +/******************************************************************************* +** +** Function BTM_BleGetVendorCapabilities +** +** Description This function reads local LE features +** +** Parameters p_cmn_vsc_cb : Locala LE capability structure +** +** Returns void +** +*******************************************************************************/ +//extern +void BTM_BleGetVendorCapabilities(tBTM_BLE_VSC_CB *p_cmn_vsc_cb); +/******************************************************************************* +** +** Function BTM_BleSetStorageConfig +** +** Description This function is called to setup storage configuration and setup callbacks. +** +** Parameters UINT8 batch_scan_full_max -Batch scan full maximum + UINT8 batch_scan_trunc_max - Batch scan truncated value maximum + UINT8 batch_scan_notify_threshold - Threshold value + tBTM_BLE_SCAN_SETUP_CBACK *p_setup_cback - Setup callback + tBTM_BLE_SCAN_THRESHOLD_CBACK *p_thres_cback -Threshold callback + void *p_ref - Reference value +** +** Returns tBTM_STATUS +** +*******************************************************************************/ +//extern +tBTM_STATUS BTM_BleSetStorageConfig(UINT8 batch_scan_full_max, + UINT8 batch_scan_trunc_max, + UINT8 batch_scan_notify_threshold, + tBTM_BLE_SCAN_SETUP_CBACK *p_setup_cback, + tBTM_BLE_SCAN_THRESHOLD_CBACK *p_thres_cback, + tBTM_BLE_SCAN_REP_CBACK* p_cback, + tBTM_BLE_REF_VALUE ref_value); + +/******************************************************************************* +** +** Function BTM_BleEnableBatchScan +** +** Description This function is called to enable batch scan +** +** Parameters tBTM_BLE_BATCH_SCAN_MODE scan_mode - Batch scan mode + UINT32 scan_interval -Scan interval + UINT32 scan_window - Scan window value + tBLE_ADDR_TYPE addr_type - Address type + tBTM_BLE_DISCARD_RULE discard_rule - Data discard rules +** +** Returns tBTM_STATUS +** +*******************************************************************************/ +//extern +tBTM_STATUS BTM_BleEnableBatchScan(tBTM_BLE_BATCH_SCAN_MODE scan_mode, + UINT32 scan_interval, UINT32 scan_window, + tBTM_BLE_DISCARD_RULE discard_rule, + tBLE_ADDR_TYPE addr_type, + tBTM_BLE_REF_VALUE ref_value); + +/******************************************************************************* +** +** Function BTM_BleDisableBatchScan +** +** Description This function is called to disable batch scanning +** +** Parameters void +** +** Returns void +** +*******************************************************************************/ +//extern +tBTM_STATUS BTM_BleDisableBatchScan(tBTM_BLE_REF_VALUE ref_value); + +/******************************************************************************* +** +** Function BTM_BleReadScanReports +** +** Description This function is called to read batch scan reports +** +** Parameters tBLE_SCAN_MODE scan_mode - Scan mode report to be read out + tBTM_BLE_SCAN_REP_CBACK* p_cback - Reports callback +** +** Returns tBTM_STATUS +** +*******************************************************************************/ +//extern +tBTM_STATUS BTM_BleReadScanReports(tBLE_SCAN_MODE scan_mode, + tBTM_BLE_REF_VALUE ref_value); + +/******************************************************************************* +** +** Function BTM_BleTrackAdvertiser +** +** Description This function is called to read batch scan reports +** +** Parameters p_track_cback - Tracking callback +** ref_value - Reference value +** +** Returns tBTM_STATUS +** +*******************************************************************************/ +//extern +tBTM_STATUS BTM_BleTrackAdvertiser(tBTM_BLE_TRACK_ADV_CBACK *p_track_cback, + tBTM_BLE_REF_VALUE ref_value); + +/******************************************************************************* +** +** Function BTM_BleWriteScanRsp +** +** Description This function is called to write LE scan response. +** +** Parameters: p_scan_rsp: scan response. +** +** Returns status +** +*******************************************************************************/ +//extern +tBTM_STATUS BTM_BleWriteScanRsp(tBTM_BLE_AD_MASK data_mask, + tBTM_BLE_ADV_DATA *p_data); + +/******************************************************************************* +** +** Function BTM_BleObserve +** +** Description This procedure keep the device listening for advertising +** events from a broadcast device. +** +** Parameters start: start or stop observe. +** +** Returns void +** +*******************************************************************************/ +//extern +tBTM_STATUS BTM_BleObserve(BOOLEAN start, UINT8 duration, + tBTM_INQ_RESULTS_CB *p_results_cb, tBTM_CMPL_CB *p_cmpl_cb); + + +/******************************************************************************* +** +** Function BTM_GetDeviceIDRoot +** +** Description This function is called to read the local device identity +** root. +** +** Returns void +** the local device ER is copied into er +** +*******************************************************************************/ +//extern +void BTM_GetDeviceIDRoot (BT_OCTET16 ir); + +/******************************************************************************* +** +** Function BTM_GetDeviceEncRoot +** +** Description This function is called to read the local device encryption +** root. +** +** Returns void +** the local device ER is copied into er +** +*******************************************************************************/ +//extern +void BTM_GetDeviceEncRoot (BT_OCTET16 er); + +/******************************************************************************* +** +** Function BTM_GetDeviceDHK +** +** Description This function is called to read the local device DHK. +** +** Returns void +** the local device DHK is copied into dhk +** +*******************************************************************************/ +//extern +void BTM_GetDeviceDHK (BT_OCTET16 dhk); + +/******************************************************************************* +** +** Function BTM_SecurityGrant +** +** Description This function is called to grant security process. +** +** Parameters bd_addr - peer device bd address. +** res - result of the operation BTM_SUCCESS if success. +** Otherwise, BTM_REPEATED_ATTEMPTS is too many attempts. +** +** Returns None +** +*******************************************************************************/ +//extern +void BTM_SecurityGrant(BD_ADDR bd_addr, UINT8 res); + +/******************************************************************************* +** +** Function BTM_BlePasskeyReply +** +** Description This function is called after Security Manager submitted +** passkey request to the application. +** +** Parameters: bd_addr - Address of the device for which passkey was requested +** res - result of the operation SMP_SUCCESS if success +** passkey - numeric value in the range of +** BTM_MIN_PASSKEY_VAL(0) - BTM_MAX_PASSKEY_VAL(999999(0xF423F)). +** +*******************************************************************************/ +//extern +void BTM_BlePasskeyReply (BD_ADDR bd_addr, UINT8 res, UINT32 passkey); + +/******************************************************************************* +** +** Function BTM_BleConfirmReply +** +** Description This function is called after Security Manager submitted +** numeric comparison request to the application. +** +** Parameters: bd_addr - Address of the device with which numeric +** comparison was requested +** res - comparison result BTM_SUCCESS if success +** +*******************************************************************************/ +//extern +void BTM_BleConfirmReply (BD_ADDR bd_addr, UINT8 res); + +/******************************************************************************* +** +** Function BTM_LeOobDataReply +** +** Description This function is called to provide the OOB data for +** SMP in response to BTM_LE_OOB_REQ_EVT +** +** Parameters: bd_addr - Address of the peer device +** res - result of the operation SMP_SUCCESS if success +** p_data - simple pairing Randomizer C. +** +*******************************************************************************/ +//extern +void BTM_BleOobDataReply(BD_ADDR bd_addr, UINT8 res, UINT8 len, UINT8 *p_data); + + +/******************************************************************************* +** +** Function BTM_BleDataSignature +** +** Description This function is called to sign the data using AES128 CMAC +** algorith. +** +** Parameter bd_addr: target device the data to be signed for. +** p_text: singing data +** len: length of the signing data +** signature: output parameter where data signature is going to +** be stored. +** +** Returns TRUE if signing sucessul, otherwise FALSE. +** +*******************************************************************************/ +//extern +BOOLEAN BTM_BleDataSignature (BD_ADDR bd_addr, UINT8 *p_text, UINT16 len, + BLE_SIGNATURE signature); + +/******************************************************************************* +** +** Function BTM_BleVerifySignature +** +** Description This function is called to verify the data signature +** +** Parameter bd_addr: target device the data to be signed for. +** p_orig: original data before signature. +** len: length of the signing data +** counter: counter used when doing data signing +** p_comp: signature to be compared against. + +** Returns TRUE if signature verified correctly; otherwise FALSE. +** +*******************************************************************************/ +//extern +BOOLEAN BTM_BleVerifySignature (BD_ADDR bd_addr, UINT8 *p_orig, + UINT16 len, UINT32 counter, + UINT8 *p_comp); + +/******************************************************************************* +** +** Function BTM_ReadConnectionAddr +** +** Description This function is called to set the local device random address +** . +** +** Returns void +** +*******************************************************************************/ +//extern +void BTM_ReadConnectionAddr (BD_ADDR remote_bda, BD_ADDR local_conn_addr, + tBLE_ADDR_TYPE *p_addr_type); + + + +/******************************************************************************* +** +** Function BTM_ReadRemoteConnectionAddr +** +** Description This function is read the remote device address currently used +** . +** +** Returns void +** +*******************************************************************************/ +//extern +BOOLEAN BTM_ReadRemoteConnectionAddr(BD_ADDR pseudo_addr, + BD_ADDR conn_addr, + tBLE_ADDR_TYPE *p_addr_type); + +/******************************************************************************* +** +** Function BTM_BleLoadLocalKeys +** +** Description Local local identity key, encryption root or sign counter. +** +** Parameters: key_type: type of key, can be BTM_BLE_KEY_TYPE_ID, BTM_BLE_KEY_TYPE_ER +** or BTM_BLE_KEY_TYPE_COUNTER. +** p_key: pointer to the key. +* +** Returns non2. +** +*******************************************************************************/ +//extern +void BTM_BleLoadLocalKeys(UINT8 key_type, tBTM_BLE_LOCAL_KEYS *p_key); + + +/******************************************************************************* +** +** Function BTM_BleSetBgConnType +** +** Description This function is called to set BLE background connection +** procedure type. It can be auto connection, or selective connection. +** +** Parameters conn_type: it can be auto connection, or selective connection. +** p_select_cback: callback function when selective connection procedure +** is being used. +** +** Returns void +** +*******************************************************************************/ +//extern +BOOLEAN BTM_BleSetBgConnType(tBTM_BLE_CONN_TYPE conn_type, + tBTM_BLE_SEL_CBACK *p_select_cback); + +/******************************************************************************* +** +** Function BTM_BleUpdateBgConnDev +** +** Description This function is called to add or remove a device into/from +** background connection procedure. The background connection +* procedure is decided by the background connection type, it can be +* auto connection, or selective connection. +** +** Parameters add_remove: TRUE to add; FALSE to remove. +** remote_bda: device address to add/remove. +** +** Returns void +** +*******************************************************************************/ +//extern +BOOLEAN BTM_BleUpdateBgConnDev(BOOLEAN add_remove, BD_ADDR remote_bda); + +/******************************************************************************* +** +** Function BTM_BleClearBgConnDev +** +** Description This function is called to clear the whitelist, +** end any pending whitelist connections, +* and reset the local bg device list. +** +** Parameters void +** +** Returns void +** +*******************************************************************************/ +//extern +void BTM_BleClearBgConnDev(void); + +/******************************************************** +** +** Function BTM_BleSetPrefConnParams +** +** Description Set a peripheral's preferred connection parameters. When +** any of the value does not want to be updated while others +** do, use BTM_BLE_CONN_PARAM_UNDEF for the ones want to +** leave untouched. +** +** Parameters: bd_addr - BD address of the peripheral +** min_conn_int - minimum preferred connection interval +** max_conn_int - maximum preferred connection interval +** slave_latency - preferred slave latency +** supervision_tout - preferred supervision timeout +** +** Returns void +** +*******************************************************************************/ +//extern +void BTM_BleSetPrefConnParams (BD_ADDR bd_addr, + UINT16 min_conn_int, UINT16 max_conn_int, + UINT16 slave_latency, UINT16 supervision_tout); + +/****************************************************************************** +** +** Function BTM_BleSetConnScanParams +** +** Description Set scan parameters used in BLE connection request +** +** Parameters: scan_interval - scan interval +** scan_window - scan window +** +** Returns void +** +*******************************************************************************/ +//extern +void BTM_BleSetConnScanParams (UINT32 scan_interval, UINT32 scan_window); + +/****************************************************************************** +** +** Function BTM_BleReadControllerFeatures +** +** Description Reads BLE specific controller features +** +** Parameters: tBTM_BLE_CTRL_FEATURES_CBACK : Callback to notify when features are read +** +** Returns void +** +*******************************************************************************/ +//extern +void BTM_BleReadControllerFeatures(tBTM_BLE_CTRL_FEATURES_CBACK *p_vsc_cback); + +/******************************************************************************* +** +** Function BTM_CheckAdvData +** +** Description This function is called to get ADV data for a specific type. +** +** Parameters p_adv - pointer of ADV data +** type - finding ADV data type +** p_length - return the length of ADV data not including type +** +** Returns pointer of ADV data +** +*******************************************************************************/ +//extern +UINT8 *BTM_CheckAdvData( UINT8 *p_adv, UINT8 type, UINT8 *p_length); + +/******************************************************************************* +** +** Function BTM__BLEReadDiscoverability +** +** Description This function is called to read the current LE discoverability +** mode of the device. +** +** Returns BTM_BLE_NON_DISCOVERABLE ,BTM_BLE_LIMITED_DISCOVERABLE or +** BTM_BLE_GENRAL_DISCOVERABLE +** +*******************************************************************************/ +UINT16 BTM_BleReadDiscoverability(); + +/******************************************************************************* +** +** Function BTM__BLEReadConnectability +** +** Description This function is called to read the current LE connectibility +** mode of the device. +** +** Returns BTM_BLE_NON_CONNECTABLE or BTM_BLE_CONNECTABLE +** +*******************************************************************************/ +//extern +UINT16 BTM_BleReadConnectability (); + +/******************************************************************************* +** +** Function BTM_ReadDevInfo +** +** Description This function is called to read the device/address type +** of BD address. +** +** Parameter remote_bda: remote device address +** p_dev_type: output parameter to read the device type. +** p_addr_type: output parameter to read the address type. +** +*******************************************************************************/ +//extern +void BTM_ReadDevInfo (BD_ADDR remote_bda, tBT_DEVICE_TYPE *p_dev_type, + tBLE_ADDR_TYPE *p_addr_type); + + +/******************************************************************************* +** +** Function BTM_ReadConnectedTransportAddress +** +** Description This function is called to read the paired device/address type of other device paired +** corresponding to the BD_address +** +** Parameter remote_bda: remote device address, carry out the transport address +** transport: active transport +** +** Return TRUE if an active link is identified; FALSE otherwise +** +*******************************************************************************/ +//extern +BOOLEAN BTM_ReadConnectedTransportAddress(BD_ADDR remote_bda, + tBT_TRANSPORT transport); + +/******************************************************************************* +** +** Function BTM_BleBroadcast +** +** Description This function is to start or stop broadcasting. +** +** Parameters start: start or stop broadcasting. +** +** Returns status. +** +*******************************************************************************/ +//extern +tBTM_STATUS BTM_BleBroadcast(BOOLEAN start); + +/******************************************************************************* +** +** Function BTM_BleConfigPrivacy +** +** Description This function is called to enable or disable the privacy in +** the local device. +** +** Parameters enable: TRUE to enable it; FALSE to disable it. +** +** Returns BOOLEAN privacy mode set success; otherwise failed. +** +*******************************************************************************/ +//extern +BOOLEAN BTM_BleConfigPrivacy(BOOLEAN enable); + +/******************************************************************************* +** +** Function BTM_BleLocalPrivacyEnabled +** +** Description Checks if local device supports private address +** +** Returns Return TRUE if local privacy is enabled else FALSE +** +*******************************************************************************/ +//extern +BOOLEAN BTM_BleLocalPrivacyEnabled(void); + +/******************************************************************************* +** +** Function BTM_BleEnableMixedPrivacyMode +** +** Description This function is called to enabled Mixed mode if privacy 1.2 +** is applicable in controller. +** +** Parameters mixed_on: mixed mode to be used or not. +** +** Returns void +** +*******************************************************************************/ +//extern +void BTM_BleEnableMixedPrivacyMode(BOOLEAN mixed_on); + +/******************************************************************************* +** +** Function BTM_BleMaxMultiAdvInstanceCount +** +** Description Returns max number of multi adv instances supported by controller +** +** Returns Max multi adv instance count +** +*******************************************************************************/ +//extern +UINT8 BTM_BleMaxMultiAdvInstanceCount(); + +/******************************************************************************* +** +** Function BTM_BleSetConnectableMode +** +** Description This function is called to set BLE connectable mode for a +** peripheral device. +** +** Parameters connectable_mode: directed connectable mode, or non-directed.It can +** be BTM_BLE_CONNECT_EVT, BTM_BLE_CONNECT_DIR_EVT or +** BTM_BLE_CONNECT_LO_DUTY_DIR_EVT +** +** Returns BTM_ILLEGAL_VALUE if controller does not support BLE. +** BTM_SUCCESS is status set successfully; otherwise failure. +** +*******************************************************************************/ +//extern +tBTM_STATUS BTM_BleSetConnectableMode(tBTM_BLE_CONN_MODE connectable_mode); + +/******************************************************************************* +** +** Function BTM_BleTurnOnPrivacyOnRemote +** +** Description This function is called to enable or disable the privacy on the +** remote device. +** +** Parameters bd_addr: remote device address. +** privacy_on: TRUE to enable it; FALSE to disable it. +** +** Returns void +** +*******************************************************************************/ +//extern +void BTM_BleTurnOnPrivacyOnRemote(BD_ADDR bd_addr, + BOOLEAN privacy_on); + +/******************************************************************************* +** +** Function BTM_BleUpdateAdvWhitelist +** +** Description Add or remove device from advertising white list +** +** Returns void +** +*******************************************************************************/ +//extern +BOOLEAN BTM_BleUpdateAdvWhitelist(BOOLEAN add_remove, BD_ADDR emote_bda); + +/******************************************************************************* +** +** Function BTM_BleUpdateAdvFilterPolicy +** +** Description This function update the filter policy of advertiser. +** +** Parameter adv_policy: advertising filter policy +** +** Return void +*******************************************************************************/ +//extern +void BTM_BleUpdateAdvFilterPolicy(tBTM_BLE_AFP adv_policy); + +/******************************************************************************* +** +** Function BTM_BleReceiverTest +** +** Description This function is called to start the LE Receiver test +** +** Parameter rx_freq - Frequency Range +** p_cmd_cmpl_cback - Command Complete callback +** +*******************************************************************************/ +void BTM_BleReceiverTest(UINT8 rx_freq, tBTM_CMPL_CB *p_cmd_cmpl_cback); + + +/******************************************************************************* +** +** Function BTM_BleTransmitterTest +** +** Description This function is called to start the LE Transmitter test +** +** Parameter tx_freq - Frequency Range +** test_data_len - Length in bytes of payload data in each packet +** packet_payload - Pattern to use in the payload +** p_cmd_cmpl_cback - Command Complete callback +** +*******************************************************************************/ +void BTM_BleTransmitterTest(UINT8 tx_freq, UINT8 test_data_len, + UINT8 packet_payload, tBTM_CMPL_CB *p_cmd_cmpl_cback); + +/******************************************************************************* +** +** Function BTM_BleTestEnd +** +** Description This function is called to stop the in-progress TX or RX test +** +** Parameter p_cmd_cmpl_cback - Command complete callback +** +*******************************************************************************/ +void BTM_BleTestEnd(tBTM_CMPL_CB *p_cmd_cmpl_cback); + +/******************************************************************************* +** +** Function BTM_UseLeLink +** +** Description This function is to select the underneath physical link to use. +** +** Returns TRUE to use LE, FALSE use BR/EDR. +** +*******************************************************************************/ +//extern +BOOLEAN BTM_UseLeLink (BD_ADDR bd_addr); + +/******************************************************************************* +** +** Function BTM_BleStackEnable +** +** Description Enable/Disable BLE functionality on stack regarless controller +** capability. +** +** Parameters: enable: TRUE to enable, FALSE to disable. +** +** Returns TRUE if added OK, else FALSE +** +*******************************************************************************/ +//extern +tBTM_STATUS BTM_BleStackEnable (BOOLEAN enable); + +/******************************************************************************* +** +** Function BTM_GetLeSecurityState +** +** Description This function is called to get security mode 1 flags and +** encryption key size for LE peer. +** +** Returns BOOLEAN TRUE if LE device is found, FALSE otherwise. +** +*******************************************************************************/ +//extern +BOOLEAN BTM_GetLeSecurityState (BD_ADDR bd_addr, + UINT8 *p_le_dev_sec_flags, + UINT8 *p_le_key_size); + +/******************************************************************************* +** +** Function BTM_BleSecurityProcedureIsRunning +** +** Description This function indicates if LE security procedure is +** currently running with the peer. +** +** Returns BOOLEAN TRUE if security procedure is running, FALSE otherwise. +** +*******************************************************************************/ +//extern +BOOLEAN BTM_BleSecurityProcedureIsRunning (BD_ADDR bd_addr); + +/******************************************************************************* +** +** Function BTM_BleGetSupportedKeySize +** +** Description This function gets the maximum encryption key size in bytes +** the local device can suport. +** record. +** +** Returns the key size or 0 if the size can't be retrieved. +** +*******************************************************************************/ +//extern +UINT8 BTM_BleGetSupportedKeySize (BD_ADDR bd_addr); + +/*******************************************************************************/ +/* Multi ADV API */ +/******************************************************************************* +** +** Function BTM_BleEnableAdvInstance +** +** Description This function enable a Multi-ADV instance with the specified +** adv parameters +** +** Parameters p_params: pointer to the adv parameter structure, set as default +** adv parameter when the instance is enabled. +** p_cback: callback function for the adv instance. +** p_ref: reference data attach to the adv instance to be enabled. +** +** Returns status +** +*******************************************************************************/ +//extern +tBTM_STATUS BTM_BleEnableAdvInstance (tBTM_BLE_ADV_PARAMS *p_params, + tBTM_BLE_MULTI_ADV_CBACK *p_cback, + void *p_ref); + +/******************************************************************************* +** +** Function BTM_BleUpdateAdvInstParam +** +** Description This function update a Multi-ADV instance with the specififed +** adv parameters. +** +** Parameters inst_id: adv instance ID +** p_params: pointer to the adv parameter structure. +** +** Returns status +** +*******************************************************************************/ +//extern +tBTM_STATUS BTM_BleUpdateAdvInstParam (UINT8 inst_id, tBTM_BLE_ADV_PARAMS *p_params); + +/******************************************************************************* +** +** Function BTM_BleCfgAdvInstData +** +** Description This function configure a Multi-ADV instance with the specified +** adv data or scan response data. +** +** Parameters inst_id: adv instance ID +** is_scan_rsp: is this scacn response, if no set as adv data. +** data_mask: adv data mask. +** p_data: pointer to the adv data structure. +** +** Returns status +** +*******************************************************************************/ +//extern +tBTM_STATUS BTM_BleCfgAdvInstData (UINT8 inst_id, BOOLEAN is_scan_rsp, + tBTM_BLE_AD_MASK data_mask, + tBTM_BLE_ADV_DATA *p_data); + +/******************************************************************************* +** +** Function BTM_BleDisableAdvInstance +** +** Description This function disable a Multi-ADV instance. +** +** Parameters inst_id: adv instance ID +** +** Returns status +** +*******************************************************************************/ +//extern +tBTM_STATUS BTM_BleDisableAdvInstance (UINT8 inst_id); + +/******************************************************************************* +** +** Function BTM_BleAdvFilterParamSetup +** +** Description This function is called to setup the adv data payload filter +** condition. +** +** Parameters p_target: enabble the filter condition on a target device; if NULL +** enable the generic scan condition. +** enable: enable or disable the filter condition +** +** Returns void +** +*******************************************************************************/ +//extern +tBTM_STATUS BTM_BleAdvFilterParamSetup(int action, + tBTM_BLE_PF_FILT_INDEX filt_index, + tBTM_BLE_PF_FILT_PARAMS *p_filt_params, + tBLE_BD_ADDR *p_target, tBTM_BLE_PF_PARAM_CBACK *p_cmpl_cback, + tBTM_BLE_REF_VALUE ref_value); + +/******************************************************************************* +** +** Function BTM_BleCfgFilterCondition +** +** Description This function is called to configure the adv data payload filter +** condition. +** +** Parameters action: to read/write/clear +** cond_type: filter condition type. +** p_cond: filter condition paramter +** +** Returns tBTM_STATUS +** +*******************************************************************************/ +//extern +tBTM_STATUS BTM_BleCfgFilterCondition(tBTM_BLE_SCAN_COND_OP action, + tBTM_BLE_PF_COND_TYPE cond_type, + tBTM_BLE_PF_FILT_INDEX filt_index, + tBTM_BLE_PF_COND_PARAM *p_cond, + tBTM_BLE_PF_CFG_CBACK *p_cmpl_cback, + tBTM_BLE_REF_VALUE ref_value); + +/******************************************************************************* +** +** Function BTM_BleEnableDisableFilterFeature +** +** Description This function is called to enable or disable the APCF feature +** +** Parameters enable - TRUE - enables the APCF, FALSE - disables the APCF +** ref_value - Ref value +** +** Returns tBTM_STATUS +** +*******************************************************************************/ +//extern +tBTM_STATUS BTM_BleEnableDisableFilterFeature(UINT8 enable, + tBTM_BLE_PF_STATUS_CBACK *p_stat_cback, + tBTM_BLE_REF_VALUE ref_value); + +/******************************************************************************* +** +** Function BTM_BleGetEnergyInfo +** +** Description This function obtains the energy info +** +** Parameters p_ener_cback - Callback pointer +** +** Returns status +** +*******************************************************************************/ +//extern +tBTM_STATUS BTM_BleGetEnergyInfo(tBTM_BLE_ENERGY_INFO_CBACK *p_ener_cback); + +/******************************************************************************* +** +** Function BTM_SetBleDataLength +** +** Description This function is called to set maximum BLE transmission packet size +** +** Returns BTM_SUCCESS if success; otherwise failed. +** +*******************************************************************************/ +//extern +tBTM_STATUS BTM_SetBleDataLength(BD_ADDR bd_addr, UINT16 tx_pdu_length); + +/* +#ifdef __cplusplus +} +#endif +*/ + +#endif diff --git a/components/bt/bluedroid/stack/include/btm_ble_int.h b/components/bt/bluedroid/stack/include/btm_ble_int.h new file mode 100755 index 0000000000..d44737fd77 --- /dev/null +++ b/components/bt/bluedroid/stack/include/btm_ble_int.h @@ -0,0 +1,486 @@ +/****************************************************************************** + * + * Copyright (C) 1999-2012 Broadcom Corporation + * + * 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 main Bluetooth Manager (BTM) internal + * definitions. + * + ******************************************************************************/ + +#ifndef BTM_BLE_INT_H +#define BTM_BLE_INT_H + +#include "bt_target.h" +#include "gki.h" +#include "hcidefs.h" +#include "btm_ble_api.h" +#include "btm_int.h" + +#if BLE_INCLUDED == TRUE && SMP_INCLUDED == TRUE +#include "smp_api.h" +#endif + + +/* scanning enable status */ +#define BTM_BLE_SCAN_ENABLE 0x01 +#define BTM_BLE_SCAN_DISABLE 0x00 + +/* advertising enable status */ +#define BTM_BLE_ADV_ENABLE 0x01 +#define BTM_BLE_ADV_DISABLE 0x00 + +/* use the high 4 bits unused by inquiry mode */ +#define BTM_BLE_SELECT_SCAN 0x20 +#define BTM_BLE_NAME_REQUEST 0x40 +#define BTM_BLE_OBSERVE 0x80 + +#define BTM_BLE_MAX_WL_ENTRY 1 +#define BTM_BLE_AD_DATA_LEN 31 + +#define BTM_BLE_ENC_MASK 0x03 + +#define BTM_BLE_DUPLICATE_ENABLE 1 +#define BTM_BLE_DUPLICATE_DISABLE 0 + +#define BTM_BLE_GAP_DISC_SCAN_INT 18 /* Interval(scan_int) = 11.25 ms= 0x0010 * 0.625 ms */ +#define BTM_BLE_GAP_DISC_SCAN_WIN 18 /* scan_window = 11.25 ms= 0x0010 * 0.625 ms */ +#define BTM_BLE_GAP_ADV_INT 512 /* Tgap(gen_disc) = 1.28 s= 512 * 0.625 ms */ +#define BTM_BLE_GAP_LIM_TOUT 180 /* Tgap(lim_timeout) = 180s max */ +#define BTM_BLE_LOW_LATENCY_SCAN_INT 8000 /* Interval(scan_int) = 5s= 8000 * 0.625 ms */ +#define BTM_BLE_LOW_LATENCY_SCAN_WIN 8000 /* scan_window = 5s= 8000 * 0.625 ms */ + + +#define BTM_BLE_GAP_ADV_FAST_INT_1 48 /* TGAP(adv_fast_interval1) = 30(used) ~ 60 ms = 48 *0.625 */ +#define BTM_BLE_GAP_ADV_FAST_INT_2 160 /* TGAP(adv_fast_interval2) = 100(used) ~ 150 ms = 160 * 0.625 ms */ +#define BTM_BLE_GAP_ADV_SLOW_INT 2048 /* Tgap(adv_slow_interval) = 1.28 s= 512 * 0.625 ms */ +#define BTM_BLE_GAP_ADV_DIR_MAX_INT 800 /* Tgap(dir_conn_adv_int_max) = 500 ms = 800 * 0.625 ms */ +#define BTM_BLE_GAP_ADV_DIR_MIN_INT 400 /* Tgap(dir_conn_adv_int_min) = 250 ms = 400 * 0.625 ms */ + +#define BTM_BLE_GAP_FAST_ADV_TOUT 30 + +#define BTM_BLE_SEC_REQ_ACT_NONE 0 +#define BTM_BLE_SEC_REQ_ACT_ENCRYPT 1 /* encrypt the link using current key or key refresh */ +#define BTM_BLE_SEC_REQ_ACT_PAIR 2 +#define BTM_BLE_SEC_REQ_ACT_DISCARD 3 /* discard the sec request while encryption is started but not completed */ +typedef UINT8 tBTM_BLE_SEC_REQ_ACT; + +#define BLE_STATIC_PRIVATE_MSB_MASK 0x3f +#define BLE_RESOLVE_ADDR_MSB 0x40 /* most significant bit, bit7, bit6 is 01 to be resolvable random */ +#define BLE_RESOLVE_ADDR_MASK 0xc0 /* bit 6, and bit7 */ +#define BTM_BLE_IS_RESOLVE_BDA(x) ((x[0] & BLE_RESOLVE_ADDR_MASK) == BLE_RESOLVE_ADDR_MSB) + +/* LE scan activity bit mask, continue with LE inquiry bits */ +#define BTM_LE_SELECT_CONN_ACTIVE 0x40 /* selection connection is in progress */ +#define BTM_LE_OBSERVE_ACTIVE 0x80 /* observe is in progress */ + +/* BLE scan activity mask checking */ +#define BTM_BLE_IS_SCAN_ACTIVE(x) ((x) & BTM_BLE_SCAN_ACTIVE_MASK) +#define BTM_BLE_IS_INQ_ACTIVE(x) ((x) & BTM_BLE_INQUIRY_MASK) +#define BTM_BLE_IS_OBS_ACTIVE(x) ((x) & BTM_LE_OBSERVE_ACTIVE) +#define BTM_BLE_IS_SEL_CONN_ACTIVE(x) ((x) & BTM_LE_SELECT_CONN_ACTIVE) + +/* BLE ADDR type ID bit */ +#define BLE_ADDR_TYPE_ID_BIT 0x02 + +#define BTM_VSC_CHIP_CAPABILITY_L_VERSION 55 +#define BTM_VSC_CHIP_CAPABILITY_M_VERSION 95 + +typedef struct +{ + UINT16 data_mask; + UINT8 *p_flags; + UINT8 ad_data[BTM_BLE_AD_DATA_LEN]; + UINT8 *p_pad; +}tBTM_BLE_LOCAL_ADV_DATA; + +typedef struct +{ + UINT32 inq_count; /* Used for determining if a response has already been */ + /* received for the current inquiry operation. (We do not */ + /* want to flood the caller with multiple responses from */ + /* the same device. */ + BOOLEAN scan_rsp; + tBLE_BD_ADDR le_bda; +} tINQ_LE_BDADDR; + +#define BTM_BLE_ADV_DATA_LEN_MAX 31 +#define BTM_BLE_CACHE_ADV_DATA_MAX 62 + +#define BTM_BLE_ISVALID_PARAM(x, min, max) (((x) >= (min) && (x) <= (max)) || ((x) == BTM_BLE_CONN_PARAM_UNDEF)) + +#define BTM_BLE_PRIVATE_ADDR_INT 900 /* 15 minutes minimum for random address refreshing */ + +typedef struct +{ + UINT16 discoverable_mode; + UINT16 connectable_mode; + UINT32 scan_window; + UINT32 scan_interval; + UINT8 scan_type; /* current scan type: active or passive */ + UINT8 scan_duplicate_filter; /* duplicate filter enabled for scan */ + UINT16 adv_interval_min; + UINT16 adv_interval_max; + tBTM_BLE_AFP afp; /* advertising filter policy */ + tBTM_BLE_SFP sfp; /* scanning filter policy */ + + tBLE_ADDR_TYPE adv_addr_type; + UINT8 evt_type; + UINT8 adv_mode; + tBLE_BD_ADDR direct_bda; + tBTM_BLE_EVT directed_conn; + BOOLEAN fast_adv_on; + TIMER_LIST_ENT fast_adv_timer; + + UINT8 adv_len; + UINT8 adv_data_cache[BTM_BLE_CACHE_ADV_DATA_MAX]; + + /* inquiry BD addr database */ + UINT8 num_bd_entries; + UINT8 max_bd_entries; + tBTM_BLE_LOCAL_ADV_DATA adv_data; + tBTM_BLE_ADV_CHNL_MAP adv_chnl_map; + + TIMER_LIST_ENT inq_timer_ent; + BOOLEAN scan_rsp; + UINT8 state; /* Current state that the inquiry process is in */ + INT8 tx_power; +} tBTM_BLE_INQ_CB; + + +/* random address resolving complete callback */ +typedef void (tBTM_BLE_RESOLVE_CBACK) (void * match_rec, void *p); + +typedef void (tBTM_BLE_ADDR_CBACK) (BD_ADDR_PTR static_random, void *p); + +/* random address management control block */ +typedef struct +{ + tBLE_ADDR_TYPE own_addr_type; /* local device LE address type */ + BD_ADDR private_addr; + BD_ADDR random_bda; + BOOLEAN busy; + UINT16 index; + tBTM_BLE_RESOLVE_CBACK *p_resolve_cback; + tBTM_BLE_ADDR_CBACK *p_generate_cback; + void *p; + TIMER_LIST_ENT raddr_timer_ent; +} tBTM_LE_RANDOM_CB; + +#define BTM_BLE_MAX_BG_CONN_DEV_NUM 10 + +typedef struct +{ + UINT16 min_conn_int; + UINT16 max_conn_int; + UINT16 slave_latency; + UINT16 supervision_tout; + +}tBTM_LE_CONN_PRAMS; + + +typedef struct +{ + BD_ADDR bd_addr; + UINT8 attr; + BOOLEAN is_connected; + BOOLEAN in_use; +}tBTM_LE_BG_CONN_DEV; + + /* white list using state as a bit mask */ +#define BTM_BLE_WL_IDLE 0 +#define BTM_BLE_WL_INIT 1 +#define BTM_BLE_WL_SCAN 2 +#define BTM_BLE_WL_ADV 4 +typedef UINT8 tBTM_BLE_WL_STATE; + +/* resolving list using state as a bit mask */ +#define BTM_BLE_RL_IDLE 0 +#define BTM_BLE_RL_INIT 1 +#define BTM_BLE_RL_SCAN 2 +#define BTM_BLE_RL_ADV 4 +typedef UINT8 tBTM_BLE_RL_STATE; + +/* BLE connection state */ +#define BLE_CONN_IDLE 0 +#define BLE_DIR_CONN 1 +#define BLE_BG_CONN 2 +#define BLE_CONN_CANCEL 3 +typedef UINT8 tBTM_BLE_CONN_ST; + +typedef struct +{ + void *p_param; +}tBTM_BLE_CONN_REQ; + +/* LE state request */ +#define BTM_BLE_STATE_INVALID 0 +#define BTM_BLE_STATE_CONN_ADV 1 +#define BTM_BLE_STATE_INIT 2 +#define BTM_BLE_STATE_MASTER 3 +#define BTM_BLE_STATE_SLAVE 4 +#define BTM_BLE_STATE_LO_DUTY_DIR_ADV 5 +#define BTM_BLE_STATE_HI_DUTY_DIR_ADV 6 +#define BTM_BLE_STATE_NON_CONN_ADV 7 +#define BTM_BLE_STATE_PASSIVE_SCAN 8 +#define BTM_BLE_STATE_ACTIVE_SCAN 9 +#define BTM_BLE_STATE_SCAN_ADV 10 +#define BTM_BLE_STATE_MAX 11 +typedef UINT8 tBTM_BLE_STATE; + +#define BTM_BLE_STATE_CONN_ADV_BIT 0x0001 +#define BTM_BLE_STATE_INIT_BIT 0x0002 +#define BTM_BLE_STATE_MASTER_BIT 0x0004 +#define BTM_BLE_STATE_SLAVE_BIT 0x0008 +#define BTM_BLE_STATE_LO_DUTY_DIR_ADV_BIT 0x0010 +#define BTM_BLE_STATE_HI_DUTY_DIR_ADV_BIT 0x0020 +#define BTM_BLE_STATE_NON_CONN_ADV_BIT 0x0040 +#define BTM_BLE_STATE_PASSIVE_SCAN_BIT 0x0080 +#define BTM_BLE_STATE_ACTIVE_SCAN_BIT 0x0100 +#define BTM_BLE_STATE_SCAN_ADV_BIT 0x0200 +typedef UINT16 tBTM_BLE_STATE_MASK; + +#define BTM_BLE_STATE_ALL_MASK 0x03ff +#define BTM_BLE_STATE_ALL_ADV_MASK (BTM_BLE_STATE_CONN_ADV_BIT|BTM_BLE_STATE_LO_DUTY_DIR_ADV_BIT|BTM_BLE_STATE_HI_DUTY_DIR_ADV_BIT|BTM_BLE_STATE_SCAN_ADV_BIT) +#define BTM_BLE_STATE_ALL_SCAN_MASK (BTM_BLE_STATE_PASSIVE_SCAN_BIT|BTM_BLE_STATE_ACTIVE_SCAN_BIT) +#define BTM_BLE_STATE_ALL_CONN_MASK (BTM_BLE_STATE_MASTER_BIT|BTM_BLE_STATE_SLAVE_BIT) + +#ifndef BTM_LE_RESOLVING_LIST_MAX +#define BTM_LE_RESOLVING_LIST_MAX 0x20 +#endif + +typedef struct +{ + BD_ADDR *resolve_q_random_pseudo; + UINT8 *resolve_q_action; + UINT8 q_next; + UINT8 q_pending; +} tBTM_BLE_RESOLVE_Q; + +typedef struct +{ + BOOLEAN in_use; + BOOLEAN to_add; + BD_ADDR bd_addr; + UINT8 attr; +}tBTM_BLE_WL_OP; + +/* BLE privacy mode */ +#define BTM_PRIVACY_NONE 0 /* BLE no privacy */ +#define BTM_PRIVACY_1_1 1 /* BLE privacy 1.1, do not support privacy 1.0 */ +#define BTM_PRIVACY_1_2 2 /* BLE privacy 1.2 */ +#define BTM_PRIVACY_MIXED 3 /* BLE privacy mixed mode, broadcom propietary mode */ +typedef UINT8 tBTM_PRIVACY_MODE; + +/* data length change event callback */ +typedef void (tBTM_DATA_LENGTH_CHANGE_CBACK) (UINT16 max_tx_length, UINT16 max_rx_length); + +/* Define BLE Device Management control structure +*/ +typedef struct +{ + UINT8 scan_activity; /* LE scan activity mask */ + + /***************************************************** + ** BLE Inquiry + *****************************************************/ + tBTM_BLE_INQ_CB inq_var; + + /* observer callback and timer */ + tBTM_INQ_RESULTS_CB *p_obs_results_cb; + tBTM_CMPL_CB *p_obs_cmpl_cb; + TIMER_LIST_ENT obs_timer_ent; + + /* background connection procedure cb value */ + tBTM_BLE_CONN_TYPE bg_conn_type; + UINT32 scan_int; + UINT32 scan_win; + tBTM_BLE_SEL_CBACK *p_select_cback; + + /* white list information */ + UINT8 white_list_avail_size; + tBTM_BLE_WL_STATE wl_state; + + BUFFER_Q conn_pending_q; + tBTM_BLE_CONN_ST conn_state; + + /* random address management control block */ + tBTM_LE_RANDOM_CB addr_mgnt_cb; + + BOOLEAN enabled; + +#if BLE_PRIVACY_SPT == TRUE + BOOLEAN mixed_mode; /* privacy 1.2 mixed mode is on or not */ + tBTM_PRIVACY_MODE privacy_mode; /* privacy mode */ + UINT8 resolving_list_avail_size; /* resolving list available size */ + tBTM_BLE_RESOLVE_Q resolving_list_pend_q; /* Resolving list queue */ + tBTM_BLE_RL_STATE suspended_rl_state; /* Suspended resolving list state */ + UINT8 *irk_list_mask; /* IRK list availability mask, up to max entry bits */ + tBTM_BLE_RL_STATE rl_state; /* Resolving list state */ +#endif + + tBTM_BLE_WL_OP wl_op_q[BTM_BLE_MAX_BG_CONN_DEV_NUM]; + + /* current BLE link state */ + tBTM_BLE_STATE_MASK cur_states; /* bit mask of tBTM_BLE_STATE */ + UINT8 link_count[2]; /* total link count master and slave*/ +} tBTM_BLE_CB; + +#ifdef __cplusplus +extern "C" { +#endif + +void btm_ble_timeout(TIMER_LIST_ENT *p_tle); +void btm_ble_process_adv_pkt (UINT8 *p); +void btm_ble_proc_scan_rsp_rpt (UINT8 *p); +tBTM_STATUS btm_ble_read_remote_name(BD_ADDR remote_bda, tBTM_INQ_INFO *p_cur, tBTM_CMPL_CB *p_cb); +BOOLEAN btm_ble_cancel_remote_name(BD_ADDR remote_bda); + +tBTM_STATUS btm_ble_set_discoverability(UINT16 combined_mode); +tBTM_STATUS btm_ble_set_connectability(UINT16 combined_mode); +tBTM_STATUS btm_ble_start_inquiry (UINT8 mode, UINT8 duration); +void btm_ble_stop_scan(void); +void btm_clear_all_pending_le_entry(void); + +void btm_ble_stop_scan(); +BOOLEAN btm_ble_send_extended_scan_params(UINT8 scan_type, UINT32 scan_int, + UINT32 scan_win, UINT8 addr_type_own, + UINT8 scan_filter_policy); +void btm_ble_stop_inquiry(void); +void btm_ble_init (void); +void btm_ble_connected (UINT8 *bda, UINT16 handle, UINT8 enc_mode, UINT8 role, tBLE_ADDR_TYPE addr_type, BOOLEAN addr_matched); +void btm_ble_read_remote_features_complete(UINT8 *p); +void btm_ble_write_adv_enable_complete(UINT8 * p); +void btm_ble_conn_complete(UINT8 *p, UINT16 evt_len, BOOLEAN enhanced); +void btm_read_ble_local_supported_states_complete(UINT8 *p, UINT16 evt_len); +tBTM_BLE_CONN_ST btm_ble_get_conn_st(void); +void btm_ble_set_conn_st(tBTM_BLE_CONN_ST new_st); +UINT8 *btm_ble_build_adv_data(tBTM_BLE_AD_MASK *p_data_mask, UINT8 **p_dst, + tBTM_BLE_ADV_DATA *p_data); +tBTM_STATUS btm_ble_start_adv(void); +tBTM_STATUS btm_ble_stop_adv(void); +tBTM_STATUS btm_ble_start_scan(void); +void btm_ble_create_ll_conn_complete (UINT8 status); + +/* LE security function from btm_sec.c */ +#if SMP_INCLUDED == TRUE +void btm_ble_link_sec_check(BD_ADDR bd_addr, tBTM_LE_AUTH_REQ auth_req, tBTM_BLE_SEC_REQ_ACT *p_sec_req_act); +void btm_ble_ltk_request_reply(BD_ADDR bda, BOOLEAN use_stk, BT_OCTET16 stk); +UINT8 btm_proc_smp_cback(tSMP_EVT event, BD_ADDR bd_addr, tSMP_EVT_DATA *p_data); +tBTM_STATUS btm_ble_set_encryption (BD_ADDR bd_addr, void *p_ref_data, UINT8 link_role); +void btm_ble_ltk_request(UINT16 handle, UINT8 rand[8], UINT16 ediv); +tBTM_STATUS btm_ble_start_encrypt(BD_ADDR bda, BOOLEAN use_stk, BT_OCTET16 stk); +void btm_ble_link_encrypted(BD_ADDR bd_addr, UINT8 encr_enable); +#endif + +/* LE device management functions */ +void btm_ble_reset_id( void ); + +/* security related functions */ +void btm_ble_increment_sign_ctr(BD_ADDR bd_addr, BOOLEAN is_local ); +BOOLEAN btm_get_local_div (BD_ADDR bd_addr, UINT16 *p_div); +BOOLEAN btm_ble_get_enc_key_type(BD_ADDR bd_addr, UINT8 *p_key_types); + +void btm_ble_test_command_complete(UINT8 *p); +void btm_ble_rand_enc_complete (UINT8 *p, UINT16 op_code, tBTM_RAND_ENC_CB *p_enc_cplt_cback); + +void btm_sec_save_le_key(BD_ADDR bd_addr, tBTM_LE_KEY_TYPE key_type, tBTM_LE_KEY_VALUE *p_keys, BOOLEAN pass_to_application); +void btm_ble_update_sec_key_size(BD_ADDR bd_addr, UINT8 enc_key_size); +UINT8 btm_ble_read_sec_key_size(BD_ADDR bd_addr); + +/* white list function */ +BOOLEAN btm_update_dev_to_white_list(BOOLEAN to_add, BD_ADDR bd_addr); +void btm_update_scanner_filter_policy(tBTM_BLE_SFP scan_policy); +void btm_update_adv_filter_policy(tBTM_BLE_AFP adv_policy); +void btm_ble_clear_white_list (void); +void btm_read_white_list_size_complete(UINT8 *p, UINT16 evt_len); +void btm_ble_add_2_white_list_complete(UINT8 status); +void btm_ble_remove_from_white_list_complete(UINT8 *p, UINT16 evt_len); +void btm_ble_clear_white_list_complete(UINT8 *p, UINT16 evt_len); +void btm_ble_white_list_init(UINT8 white_list_size); + +/* background connection function */ +BOOLEAN btm_ble_suspend_bg_conn(void); +BOOLEAN btm_ble_resume_bg_conn(void); +void btm_ble_initiate_select_conn(BD_ADDR bda); +BOOLEAN btm_ble_start_auto_conn(BOOLEAN start); +BOOLEAN btm_ble_start_select_conn(BOOLEAN start,tBTM_BLE_SEL_CBACK *p_select_cback); +BOOLEAN btm_ble_renew_bg_conn_params(BOOLEAN add, BD_ADDR bd_addr); +void btm_write_dir_conn_wl(BD_ADDR target_addr); +void btm_ble_update_mode_operation(UINT8 link_role, BD_ADDR bda, UINT8 status); +BOOLEAN btm_execute_wl_dev_operation(void); +void btm_ble_update_link_topology_mask(UINT8 role, BOOLEAN increase); + +/* direct connection utility */ +BOOLEAN btm_send_pending_direct_conn(void); +void btm_ble_enqueue_direct_conn_req(void *p_param); + +/* BLE address management */ +void btm_gen_resolvable_private_addr (void *p_cmd_cplt_cback); +void btm_gen_non_resolvable_private_addr (tBTM_BLE_ADDR_CBACK *p_cback, void *p); +void btm_ble_resolve_random_addr(BD_ADDR random_bda, tBTM_BLE_RESOLVE_CBACK * p_cback, void *p); +void btm_gen_resolve_paddr_low(tBTM_RAND_ENC *p); + +/* privacy function */ +#if (defined BLE_PRIVACY_SPT && BLE_PRIVACY_SPT == TRUE) +/* BLE address mapping with CS feature */ +BOOLEAN btm_identity_addr_to_random_pseudo(BD_ADDR bd_addr, UINT8 *p_addr_type, BOOLEAN refresh); +BOOLEAN btm_random_pseudo_to_identity_addr(BD_ADDR random_pseudo, UINT8 *p_static_addr_type); +void btm_ble_refresh_peer_resolvable_private_addr(BD_ADDR pseudo_bda, BD_ADDR rra, UINT8 rra_type); +void btm_ble_refresh_local_resolvable_private_addr(BD_ADDR pseudo_addr, BD_ADDR local_rpa); +void btm_ble_read_resolving_list_entry_complete(UINT8 *p, UINT16 evt_len) ; +void btm_ble_remove_resolving_list_entry_complete(UINT8 *p, UINT16 evt_len); +void btm_ble_add_resolving_list_entry_complete(UINT8 *p, UINT16 evt_len); +void btm_ble_clear_resolving_list_complete(UINT8 *p, UINT16 evt_len); +void btm_read_ble_resolving_list_size_complete (UINT8 *p, UINT16 evt_len); +void btm_ble_enable_resolving_list(UINT8); +BOOLEAN btm_ble_disable_resolving_list(UINT8 rl_mask, BOOLEAN to_resume); +void btm_ble_enable_resolving_list_for_platform (UINT8 rl_mask); +void btm_ble_resolving_list_init(UINT8 max_irk_list_sz); +void btm_ble_resolving_list_cleanup(void); +#endif + +void btm_ble_multi_adv_configure_rpa (tBTM_BLE_MULTI_ADV_INST *p_inst); +void btm_ble_multi_adv_init(void); +void* btm_ble_multi_adv_get_ref(UINT8 inst_id); +void btm_ble_multi_adv_cleanup(void); +void btm_ble_multi_adv_reenable(UINT8 inst_id); +void btm_ble_multi_adv_enb_privacy(BOOLEAN enable); +char btm_ble_map_adv_tx_power(int tx_power_index); +void btm_ble_batchscan_init(void); +void btm_ble_batchscan_cleanup(void); +void btm_ble_adv_filter_init(void); +void btm_ble_adv_filter_cleanup(void); +BOOLEAN btm_ble_topology_check(tBTM_BLE_STATE_MASK request); +BOOLEAN btm_ble_clear_topology_mask(tBTM_BLE_STATE_MASK request_state); +BOOLEAN btm_ble_set_topology_mask(tBTM_BLE_STATE_MASK request_state); + +#if BTM_BLE_CONFORMANCE_TESTING == TRUE +void btm_ble_set_no_disc_if_pair_fail (BOOLEAN disble_disc); +void btm_ble_set_test_mac_value (BOOLEAN enable, UINT8 *p_test_mac_val); +void btm_ble_set_test_local_sign_cntr_value(BOOLEAN enable, UINT32 test_local_sign_cntr); +void btm_set_random_address(BD_ADDR random_bda); +void btm_ble_set_keep_rfu_in_auth_req(BOOLEAN keep_rfu); +#endif + +/* +#ifdef __cplusplus +} +#endif +*/ +#endif diff --git a/components/bt/bluedroid/stack/include/btm_int.h b/components/bt/bluedroid/stack/include/btm_int.h new file mode 100755 index 0000000000..acc0e05a03 --- /dev/null +++ b/components/bt/bluedroid/stack/include/btm_int.h @@ -0,0 +1,1121 @@ +/****************************************************************************** + * + * Copyright (C) 1999-2012 Broadcom Corporation + * + * 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 main Bluetooth Manager (BTM) internal + * definitions. + * + ******************************************************************************/ +#ifndef BTM_INT_H +#define BTM_INT_H + +#include "bt_defs.h" +#include "bt_target.h" +#include "gki.h" +#include "hcidefs.h" + +#include "rfcdefs.h" + +#include "btm_api.h" + +#if (BLE_INCLUDED == TRUE) +#include "btm_ble_int.h" +#if (SMP_INCLUDED == TRUE) +#include "smp_api.h" +#endif +#endif + +#if BTM_MAX_LOC_BD_NAME_LEN > 0 +typedef char tBTM_LOC_BD_NAME[BTM_MAX_LOC_BD_NAME_LEN + 1]; +#endif + +#define BTM_ACL_IS_CONNECTED(bda) (btm_bda_to_acl (bda, BT_TRANSPORT_BR_EDR) != NULL) + +/* Definitions for Server Channel Number (SCN) management +*/ +#define BTM_MAX_SCN PORT_MAX_RFC_PORTS + +/* Define masks for supported and exception 2.0 ACL packet types +*/ +#define BTM_ACL_SUPPORTED_PKTS_MASK (HCI_PKT_TYPES_MASK_DM1 | \ + HCI_PKT_TYPES_MASK_DH1 | \ + HCI_PKT_TYPES_MASK_DM3 | \ + HCI_PKT_TYPES_MASK_DH3 | \ + HCI_PKT_TYPES_MASK_DM5 | \ + HCI_PKT_TYPES_MASK_DH5) + +#define BTM_ACL_EXCEPTION_PKTS_MASK (HCI_PKT_TYPES_MASK_NO_2_DH1 | \ + HCI_PKT_TYPES_MASK_NO_3_DH1 | \ + HCI_PKT_TYPES_MASK_NO_2_DH3 | \ + HCI_PKT_TYPES_MASK_NO_3_DH3 | \ + HCI_PKT_TYPES_MASK_NO_2_DH5 | \ + HCI_PKT_TYPES_MASK_NO_3_DH5) + +#define BTM_EPR_AVAILABLE(p) ((HCI_ATOMIC_ENCRYPT_SUPPORTED((p)->peer_lmp_features[HCI_EXT_FEATURES_PAGE_0]) && \ + HCI_ATOMIC_ENCRYPT_SUPPORTED(controller_get_interface()->get_features_classic(0)->as_array)) \ + ? TRUE : FALSE) + +#define BTM_IS_BRCM_CONTROLLER() (controller_get_interface()->get_bt_version()->manufacturer == LMP_COMPID_BROADCOM) + +/* Define the ACL Management control structure +*/ +typedef struct +{ + UINT16 hci_handle; + UINT16 pkt_types_mask; + UINT16 clock_offset; + BD_ADDR remote_addr; + DEV_CLASS remote_dc; + BD_NAME remote_name; + + UINT16 manufacturer; + UINT16 lmp_subversion; + UINT16 link_super_tout; + BD_FEATURES peer_lmp_features[HCI_EXT_FEATURES_PAGE_MAX + 1]; /* Peer LMP Extended features mask table for the device */ + UINT8 num_read_pages; + UINT8 lmp_version; + + BOOLEAN in_use; + UINT8 link_role; + BOOLEAN link_up_issued; /* True if busy_level link up has been issued */ + +#define BTM_ACL_SWKEY_STATE_IDLE 0 +#define BTM_ACL_SWKEY_STATE_MODE_CHANGE 1 +#define BTM_ACL_SWKEY_STATE_ENCRYPTION_OFF 2 +#define BTM_ACL_SWKEY_STATE_SWITCHING 3 +#define BTM_ACL_SWKEY_STATE_ENCRYPTION_ON 4 +#define BTM_ACL_SWKEY_STATE_IN_PROGRESS 5 + UINT8 switch_role_state; + +#define BTM_ACL_ENCRYPT_STATE_IDLE 0 +#define BTM_ACL_ENCRYPT_STATE_ENCRYPT_OFF 1 /* encryption turning off */ +#define BTM_ACL_ENCRYPT_STATE_TEMP_FUNC 2 /* temporarily off for change link key or role switch */ +#define BTM_ACL_ENCRYPT_STATE_ENCRYPT_ON 3 /* encryption turning on */ + UINT8 encrypt_state; /* overall BTM encryption state */ + +#if BLE_INCLUDED == TRUE + tBT_TRANSPORT transport; + BD_ADDR conn_addr; /* local device address used for this connection */ + UINT8 conn_addr_type; /* local device address type for this connection */ + BD_ADDR active_remote_addr; /* remote address used on this connection */ + UINT8 active_remote_addr_type; /* local device address type for this connection */ + BD_FEATURES peer_le_features; /* Peer LE Used features mask for the device */ + +#endif + +} tACL_CONN; + +/***************************************************** +** TIMER Definitions +******************************************************/ +#define TT_DEV_RESET 1 +#define TT_DEV_RLN 2 +#define TT_DEV_RLNKP 4 /* Read Link Policy Settings */ + +/* Define the Device Management control structure +*/ +typedef struct +{ + tBTM_DEV_STATUS_CB *p_dev_status_cb; /* Device status change callback */ + tBTM_VS_EVT_CB *p_vend_spec_cb[BTM_MAX_VSE_CALLBACKS]; /* Register for vendor specific events */ + + tBTM_CMPL_CB *p_stored_link_key_cmpl_cb; /* Read/Write/Delete stored link key */ + + TIMER_LIST_ENT reset_timer; + tBTM_CMPL_CB *p_reset_cmpl_cb; + + TIMER_LIST_ENT rln_timer; + tBTM_CMPL_CB *p_rln_cmpl_cb; /* Callback function to be called when */ + /* read local name function complete */ + TIMER_LIST_ENT rssi_timer; + tBTM_CMPL_CB *p_rssi_cmpl_cb; /* Callback function to be called when */ + /* read rssi function completes */ + TIMER_LIST_ENT lnk_quality_timer; + tBTM_CMPL_CB *p_lnk_qual_cmpl_cb;/* Callback function to be called when */ + /* read link quality function completes */ + TIMER_LIST_ENT txpwer_timer; + tBTM_CMPL_CB *p_txpwer_cmpl_cb; /* Callback function to be called when */ + /* read inq tx power function completes */ + + TIMER_LIST_ENT qossu_timer; + tBTM_CMPL_CB *p_qossu_cmpl_cb; /* Callback function to be called when */ + /* qos setup function completes */ + + tBTM_ROLE_SWITCH_CMPL switch_role_ref_data; + tBTM_CMPL_CB *p_switch_role_cb; /* Callback function to be called when */ + /* requested switch role is completed */ + + TIMER_LIST_ENT tx_power_timer; + tBTM_CMPL_CB *p_tx_power_cmpl_cb;/* Callback function to be called */ + + DEV_CLASS dev_class; /* Local device class */ + +#if BLE_INCLUDED == TRUE + + tBTM_CMPL_CB *p_le_test_cmd_cmpl_cb; /* Callback function to be called when + LE test mode command has been sent successfully */ + + BD_ADDR read_tx_pwr_addr; /* read TX power target address */ + +#define BTM_LE_SUPPORT_STATE_SIZE 8 +UINT8 le_supported_states[BTM_LE_SUPPORT_STATE_SIZE]; + +tBTM_BLE_LOCAL_ID_KEYS id_keys; /* local BLE ID keys */ +BT_OCTET16 ble_encryption_key_value; /* BLE encryption key */ + +#if BTM_BLE_CONFORMANCE_TESTING == TRUE + BOOLEAN no_disc_if_pair_fail; + BOOLEAN enable_test_mac_val; + BT_OCTET8 test_mac; + BOOLEAN enable_test_local_sign_cntr; + UINT32 test_local_sign_cntr; +#endif + +#endif /* BLE_INCLUDED */ + + tBTM_IO_CAP loc_io_caps; /* IO capability of the local device */ + tBTM_AUTH_REQ loc_auth_req; /* the auth_req flag */ + BOOLEAN secure_connections_only; /* Rejects service level 0 connections if */ + /* itself or peer device doesn't support */ + /* secure connections */ +} tBTM_DEVCB; + + +/* Define the structures and constants used for inquiry +*/ + +/* Definitions of limits for inquiries */ +#define BTM_PER_INQ_MIN_MAX_PERIOD HCI_PER_INQ_MIN_MAX_PERIOD +#define BTM_PER_INQ_MAX_MAX_PERIOD HCI_PER_INQ_MAX_MAX_PERIOD +#define BTM_PER_INQ_MIN_MIN_PERIOD HCI_PER_INQ_MIN_MIN_PERIOD +#define BTM_PER_INQ_MAX_MIN_PERIOD HCI_PER_INQ_MAX_MIN_PERIOD +#define BTM_MAX_INQUIRY_LENGTH HCI_MAX_INQUIRY_LENGTH +#define BTM_MIN_INQUIRY_LEN 0x01 + +#define BTM_MIN_INQ_TX_POWER -70 +#define BTM_MAX_INQ_TX_POWER 20 + +typedef struct +{ + UINT32 inq_count; /* Used for determining if a response has already been */ + /* received for the current inquiry operation. (We do not */ + /* want to flood the caller with multiple responses from */ + /* the same device. */ + BD_ADDR bd_addr; +} tINQ_BDADDR; + +typedef struct +{ + UINT32 time_of_resp; + UINT32 inq_count; /* "timestamps" the entry with a particular inquiry count */ + /* Used for determining if a response has already been */ + /* received for the current inquiry operation. (We do not */ + /* want to flood the caller with multiple responses from */ + /* the same device. */ + tBTM_INQ_INFO inq_info; + BOOLEAN in_use; + +#if (BLE_INCLUDED == TRUE) + BOOLEAN scan_rsp; +#endif +} tINQ_DB_ENT; + + +enum +{ + INQ_NONE, + INQ_LE_OBSERVE, + INQ_GENERAL +}; +typedef UINT8 tBTM_INQ_TYPE; + +typedef struct +{ + tBTM_CMPL_CB *p_remname_cmpl_cb; + +#define BTM_EXT_RMT_NAME_TIMEOUT 40 + + + TIMER_LIST_ENT rmt_name_timer_ent; + + UINT16 discoverable_mode; + UINT16 connectable_mode; + UINT16 page_scan_window; + UINT16 page_scan_period; + UINT16 inq_scan_window; + UINT16 inq_scan_period; + UINT16 inq_scan_type; + UINT16 page_scan_type; /* current page scan type */ + tBTM_INQ_TYPE scan_type; + + BD_ADDR remname_bda; /* Name of bd addr for active remote name request */ +#define BTM_RMT_NAME_INACTIVE 0 +#define BTM_RMT_NAME_EXT 0x1 /* Initiated through API */ +#define BTM_RMT_NAME_SEC 0x2 /* Initiated internally by security manager */ +#define BTM_RMT_NAME_INQ 0x4 /* Remote name initiated internally by inquiry */ + BOOLEAN remname_active; /* State of a remote name request by external API */ + + tBTM_CMPL_CB *p_inq_cmpl_cb; + tBTM_INQ_RESULTS_CB *p_inq_results_cb; + tBTM_CMPL_CB *p_inq_ble_cmpl_cb; /*completion callback exclusively for LE Observe*/ + tBTM_INQ_RESULTS_CB *p_inq_ble_results_cb;/*results callback exclusively for LE observe*/ + tBTM_CMPL_CB *p_inqfilter_cmpl_cb; /* Called (if not NULL) after inquiry filter completed */ + UINT32 inq_counter; /* Counter incremented each time an inquiry completes */ + /* Used for determining whether or not duplicate devices */ + /* have responded to the same inquiry */ + TIMER_LIST_ENT inq_timer_ent; + tINQ_BDADDR *p_bd_db; /* Pointer to memory that holds bdaddrs */ + UINT16 num_bd_entries; /* Number of entries in database */ + UINT16 max_bd_entries; /* Maximum number of entries that can be stored */ + tINQ_DB_ENT inq_db[BTM_INQ_DB_SIZE]; + tBTM_INQ_PARMS inqparms; /* Contains the parameters for the current inquiry */ + tBTM_INQUIRY_CMPL inq_cmpl_info; /* Status and number of responses from the last inquiry */ + + UINT16 per_min_delay; /* Current periodic minimum delay */ + UINT16 per_max_delay; /* Current periodic maximum delay */ + BOOLEAN inqfilt_active; + UINT8 pending_filt_complete_event; /* to take care of btm_event_filter_complete corresponding to */ + /* inquiry that has been cancelled*/ + UINT8 inqfilt_type; /* Contains the inquiry filter type (BD ADDR, COD, or Clear) */ + +#define BTM_INQ_INACTIVE_STATE 0 +#define BTM_INQ_CLR_FILT_STATE 1 /* Currently clearing the inquiry filter preceeding the inquiry request */ + /* (bypassed if filtering is not used) */ +#define BTM_INQ_SET_FILT_STATE 2 /* Sets the new filter (or turns off filtering) in this state */ +#define BTM_INQ_ACTIVE_STATE 3 /* Actual inquiry or periodic inquiry is in progress */ +#define BTM_INQ_REMNAME_STATE 4 /* Remote name requests are active */ + + UINT8 state; /* Current state that the inquiry process is in */ + UINT8 inq_active; /* Bit Mask indicating type of inquiry is active */ + BOOLEAN no_inc_ssp; /* TRUE, to stop inquiry on incoming SSP */ +#if (defined(BTA_HOST_INTERLEAVE_SEARCH) && BTA_HOST_INTERLEAVE_SEARCH == TRUE) + btm_inq_state next_state; /*interleaving state to determine next mode to be inquired*/ +#endif +} tBTM_INQUIRY_VAR_ST; + +/* The MSB of the clock offset field indicates that the offset is valid if TRUE */ +#define BTM_CLOCK_OFFSET_VALID 0x8000 + +/* Define the structures needed by security management +*/ + +#define BTM_SEC_INVALID_HANDLE 0xFFFF + +typedef UINT8 *BTM_BD_NAME_PTR; /* Pointer to Device name */ + +/* Security callback is called by this unit when security +** procedures are completed. Parameters are +** BD Address of remote +** Result of the operation +*/ +typedef tBTM_SEC_CBACK tBTM_SEC_CALLBACK; + +typedef void (tBTM_SCO_IND_CBACK) (UINT16 sco_inx) ; + +/* MACROs to convert from SCO packet types mask to ESCO and back */ +#define BTM_SCO_PKT_TYPE_MASK ( HCI_PKT_TYPES_MASK_HV1 \ + | HCI_PKT_TYPES_MASK_HV2 \ + | HCI_PKT_TYPES_MASK_HV3) + +/* Mask defining only the SCO types of an esco packet type */ +#define BTM_ESCO_PKT_TYPE_MASK ( HCI_ESCO_PKT_TYPES_MASK_HV1 \ + | HCI_ESCO_PKT_TYPES_MASK_HV2 \ + | HCI_ESCO_PKT_TYPES_MASK_HV3) + +#define BTM_SCO_2_ESCO(scotype) ((UINT16)(((scotype) & BTM_SCO_PKT_TYPE_MASK) >> 5)) +#define BTM_ESCO_2_SCO(escotype) ((UINT16)(((escotype) & BTM_ESCO_PKT_TYPE_MASK) << 5)) + +/* Define masks for supported and exception 2.0 SCO packet types +*/ +#define BTM_SCO_SUPPORTED_PKTS_MASK (HCI_ESCO_PKT_TYPES_MASK_HV1 | \ + HCI_ESCO_PKT_TYPES_MASK_HV2 | \ + HCI_ESCO_PKT_TYPES_MASK_HV3 | \ + HCI_ESCO_PKT_TYPES_MASK_EV3 | \ + HCI_ESCO_PKT_TYPES_MASK_EV4 | \ + HCI_ESCO_PKT_TYPES_MASK_EV5) + +#define BTM_SCO_EXCEPTION_PKTS_MASK (HCI_ESCO_PKT_TYPES_MASK_NO_2_EV3 | \ + HCI_ESCO_PKT_TYPES_MASK_NO_3_EV3 | \ + HCI_ESCO_PKT_TYPES_MASK_NO_2_EV5 | \ + HCI_ESCO_PKT_TYPES_MASK_NO_3_EV5) + + +#define BTM_SCO_ROUTE_UNKNOWN 0xff + +/* Define the structure that contains (e)SCO data */ +typedef struct +{ + tBTM_ESCO_CBACK *p_esco_cback; /* Callback for eSCO events */ + tBTM_ESCO_PARAMS setup; + tBTM_ESCO_DATA data; /* Connection complete information */ + UINT8 hci_status; +} tBTM_ESCO_INFO; + +/* Define the structure used for SCO Management +*/ +typedef struct +{ + tBTM_ESCO_INFO esco; /* Current settings */ +#if BTM_SCO_HCI_INCLUDED == TRUE + BUFFER_Q xmit_data_q; /* SCO data transmitting queue */ +#endif + tBTM_SCO_CB *p_conn_cb; /* Callback for when connected */ + tBTM_SCO_CB *p_disc_cb; /* Callback for when disconnect */ + UINT16 state; /* The state of the SCO link */ + UINT16 hci_handle; /* HCI Handle */ + BOOLEAN is_orig; /* TRUE if the originator */ + BOOLEAN rem_bd_known; /* TRUE if remote BD addr known */ + +} tSCO_CONN; + +/* SCO Management control block */ +typedef struct +{ + tBTM_SCO_IND_CBACK *app_sco_ind_cb; +#if BTM_SCO_HCI_INCLUDED == TRUE + tBTM_SCO_DATA_CB *p_data_cb; /* Callback for SCO data over HCI */ + UINT32 xmit_window_size; /* Total SCO window in bytes */ +#endif + tSCO_CONN sco_db[BTM_MAX_SCO_LINKS]; + tBTM_ESCO_PARAMS def_esco_parms; + BD_ADDR xfer_addr; + UINT16 sco_disc_reason; + BOOLEAN esco_supported; /* TRUE if 1.2 cntlr AND supports eSCO links */ + tBTM_SCO_TYPE desired_sco_mode; + tBTM_SCO_TYPE xfer_sco_type; + tBTM_SCO_PCM_PARAM sco_pcm_param; + tBTM_SCO_CODEC_TYPE codec_in_use; /* None, CVSD, MSBC, etc. */ +#if BTM_SCO_HCI_INCLUDED == TRUE + tBTM_SCO_ROUTE_TYPE sco_path; +#endif + +} tSCO_CB; + + +#if BTM_SCO_INCLUDED == TRUE +void btm_set_sco_ind_cback( tBTM_SCO_IND_CBACK *sco_ind_cb ); +void btm_accept_sco_link(UINT16 sco_inx, tBTM_ESCO_PARAMS *p_setup, + tBTM_SCO_CB *p_conn_cb, tBTM_SCO_CB *p_disc_cb); +void btm_reject_sco_link(UINT16 sco_inx ); +void btm_sco_chk_pend_rolechange (UINT16 hci_handle); +#else +#define btm_accept_sco_link(sco_inx, p_setup, p_conn_cb, p_disc_cb) +#define btm_reject_sco_link(sco_inx) +#define btm_set_sco_ind_cback(sco_ind_cb) +#define btm_sco_chk_pend_rolechange(hci_handle) +#endif /* BTM_SCO_INCLUDED */ + +/* +** Define structure for Security Service Record. +** A record exists for each service registered with the Security Manager +*/ +typedef struct +{ + UINT32 mx_proto_id; /* Service runs over this multiplexer protocol */ + UINT32 orig_mx_chan_id; /* Channel on the multiplexer protocol */ + UINT32 term_mx_chan_id; /* Channel on the multiplexer protocol */ + UINT16 psm; /* L2CAP PSM value */ + UINT16 security_flags; /* Bitmap of required security features */ + UINT8 service_id; /* Passed in authorization callback */ +#if (L2CAP_UCD_INCLUDED == TRUE) + UINT16 ucd_security_flags; /* Bitmap of required security features for UCD */ +#endif +#if BTM_SEC_SERVICE_NAME_LEN > 0 + UINT8 orig_service_name[BTM_SEC_SERVICE_NAME_LEN + 1]; + UINT8 term_service_name[BTM_SEC_SERVICE_NAME_LEN + 1]; +#endif +} tBTM_SEC_SERV_REC; + +#if BLE_INCLUDED == TRUE +/* LE Security information of device in Slave Role */ +typedef struct +{ + BT_OCTET16 irk; /* peer diverified identity root */ + BT_OCTET16 pltk; /* peer long term key */ + BT_OCTET16 pcsrk; /* peer SRK peer device used to secured sign local data */ + + BT_OCTET16 lltk; /* local long term key */ + BT_OCTET16 lcsrk; /* local SRK peer device used to secured sign local data */ + + BT_OCTET8 rand; /* random vector for LTK generation */ + UINT16 ediv; /* LTK diversifier of this slave device */ + UINT16 div; /* local DIV to generate local LTK=d1(ER,DIV,0) and CSRK=d1(ER,DIV,1) */ + UINT8 sec_level; /* local pairing security level */ + UINT8 key_size; /* key size of the LTK delivered to peer device */ + UINT8 srk_sec_level; /* security property of peer SRK for this device */ + UINT8 local_csrk_sec_level; /* security property of local CSRK for this device */ + + UINT32 counter; /* peer sign counter for verifying rcv signed cmd */ + UINT32 local_counter; /* local sign counter for sending signed write cmd*/ +}tBTM_SEC_BLE_KEYS; + +typedef struct +{ + BD_ADDR pseudo_addr; /* LE pseudo address of the device if different from device address */ + tBLE_ADDR_TYPE ble_addr_type; /* LE device type: public or random address */ + tBLE_ADDR_TYPE static_addr_type; /* static address type */ + BD_ADDR static_addr; /* static address */ + +#define BTM_WHITE_LIST_BIT 0x01 +#define BTM_RESOLVING_LIST_BIT 0x02 + UINT8 in_controller_list; /* in controller resolving list or not */ + UINT8 resolving_list_index; +#if BLE_PRIVACY_SPT == TRUE + BD_ADDR cur_rand_addr; /* current random address */ + +#define BTM_BLE_ADDR_PSEUDO 0 /* address index device record */ +#define BTM_BLE_ADDR_RRA 1 /* cur_rand_addr */ +#define BTM_BLE_ADDR_STATIC 2 /* static_addr */ + UINT8 active_addr_type; +#endif + +#if SMP_INCLUDED == TRUE + tBTM_LE_KEY_TYPE key_type; /* bit mask of valid key types in record */ + tBTM_SEC_BLE_KEYS keys; /* LE device security info in slave rode */ +#endif +} tBTM_SEC_BLE; + + +#endif /* BLE_INCLUDED */ + +/* Peering bond type */ +enum +{ + BOND_TYPE_UNKNOWN, + BOND_TYPE_PERSISTENT, + BOND_TYPE_TEMPORARY +}; +typedef UINT8 tBTM_BOND_TYPE; + +/* +** Define structure for Security Device Record. +** A record exists for each device authenticated with this device +*/ +typedef struct +{ + tBTM_SEC_SERV_REC *p_cur_service; + tBTM_SEC_CALLBACK *p_callback; + void *p_ref_data; + UINT32 timestamp; /* Timestamp of the last connection */ + UINT32 trusted_mask[BTM_SEC_SERVICE_ARRAY_SIZE]; /* Bitwise OR of trusted services */ + UINT16 hci_handle; /* Handle to connection when exists */ + UINT16 clock_offset; /* Latest known clock offset */ + BD_ADDR bd_addr; /* BD_ADDR of the device */ + DEV_CLASS dev_class; /* DEV_CLASS of the device */ + LINK_KEY link_key; /* Device link key */ + UINT8 pin_code_length; /* Length of the pin_code used for paring */ + +#define BTM_SEC_AUTHORIZED BTM_SEC_FLAG_AUTHORIZED /* 0x01 */ +#define BTM_SEC_AUTHENTICATED BTM_SEC_FLAG_AUTHENTICATED /* 0x02 */ +#define BTM_SEC_ENCRYPTED BTM_SEC_FLAG_ENCRYPTED /* 0x04 */ +#define BTM_SEC_NAME_KNOWN 0x08 +#define BTM_SEC_LINK_KEY_KNOWN BTM_SEC_FLAG_LKEY_KNOWN /* 0x10 */ +#define BTM_SEC_LINK_KEY_AUTHED BTM_SEC_FLAG_LKEY_AUTHED /* 0x20 */ +#define BTM_SEC_ROLE_SWITCHED 0x40 +#define BTM_SEC_IN_USE 0x80 + /* LE link security flag */ +#define BTM_SEC_LE_AUTHENTICATED 0x0200 /* LE link is encrypted after pairing with MITM */ +#define BTM_SEC_LE_ENCRYPTED 0x0400 /* LE link is encrypted */ +#define BTM_SEC_LE_NAME_KNOWN 0x0800 /* not used */ +#define BTM_SEC_LE_LINK_KEY_KNOWN 0x1000 /* bonded with peer (peer LTK and/or SRK is saved) */ +#define BTM_SEC_LE_LINK_KEY_AUTHED 0x2000 /* pairing is done with MITM */ +#define BTM_SEC_16_DIGIT_PIN_AUTHED 0x4000 /* pairing is done with 16 digit pin */ + + UINT16 sec_flags; /* Current device security state */ + + tBTM_BD_NAME sec_bd_name; /* User friendly name of the device. (may be truncated to save space in dev_rec table) */ + BD_FEATURES features[HCI_EXT_FEATURES_PAGE_MAX + 1]; /* Features supported by the device */ + UINT8 num_read_pages; + +#define BTM_SEC_STATE_IDLE 0 +#define BTM_SEC_STATE_AUTHENTICATING 1 +#define BTM_SEC_STATE_ENCRYPTING 2 +#define BTM_SEC_STATE_GETTING_NAME 3 +#define BTM_SEC_STATE_AUTHORIZING 4 +#define BTM_SEC_STATE_SWITCHING_ROLE 5 +#define BTM_SEC_STATE_DISCONNECTING 6 /* disconnecting BR/EDR */ +#define BTM_SEC_STATE_DELAY_FOR_ENC 7 /* delay to check for encryption to work around */ + /* controller problems */ +#define BTM_SEC_STATE_DISCONNECTING_BLE 8 /* disconnecting BLE */ +#define BTM_SEC_STATE_DISCONNECTING_BOTH 9 /* disconnecting BR/EDR and BLE */ + + UINT8 sec_state; /* Operating state */ + BOOLEAN is_originator; /* TRUE if device is originating connection */ +#if (L2CAP_UCD_INCLUDED == TRUE) + BOOLEAN is_ucd; /* TRUE if device is sending or receiving UCD */ + /* if incoming security failed, received UCD will be discarded */ +#endif + BOOLEAN role_master; /* TRUE if current mode is master */ + UINT16 security_required; /* Security required for connection */ + BOOLEAN link_key_not_sent; /* link key notification has not been sent waiting for name */ + UINT8 link_key_type; /* Type of key used in pairing */ + BOOLEAN link_key_changed; /* Changed link key during current connection */ + +#define BTM_MAX_PRE_SM4_LKEY_TYPE BTM_LKEY_TYPE_REMOTE_UNIT /* the link key type used by legacy pairing */ + +#define BTM_SM4_UNKNOWN 0x00 +#define BTM_SM4_KNOWN 0x10 +#define BTM_SM4_TRUE 0x11 +#define BTM_SM4_REQ_PEND 0x08 /* set this bit when getting remote features */ +#define BTM_SM4_UPGRADE 0x04 /* set this bit when upgrading link key */ +#define BTM_SM4_RETRY 0x02 /* set this bit to retry on HCI_ERR_KEY_MISSING or HCI_ERR_LMP_ERR_TRANS_COLLISION */ +#define BTM_SM4_DD_ACP 0x20 /* set this bit to indicate peer initiated dedicated bonding */ +#define BTM_SM4_CONN_PEND 0x40 /* set this bit to indicate accepting acl conn; to be cleared on btm_acl_created */ + UINT8 sm4; /* BTM_SM4_TRUE, if the peer supports SM4 */ + tBTM_IO_CAP rmt_io_caps; /* IO capability of the peer device */ + tBTM_AUTH_REQ rmt_auth_req; /* the auth_req flag as in the IO caps rsp evt */ + BOOLEAN remote_supports_secure_connections; + BOOLEAN remote_features_needed; /* set to true if the local device is in */ + /* "Secure Connections Only" mode and it receives */ + /* HCI_IO_CAPABILITY_REQUEST_EVT from the peer before */ + /* it knows peer's support for Secure Connections */ + + UINT16 ble_hci_handle; /* use in DUMO connection */ + UINT8 enc_key_size; /* current link encryption key size */ + tBT_DEVICE_TYPE device_type; + BOOLEAN new_encryption_key_is_p256; /* Set to TRUE when the newly generated LK + ** is generated from P-256. + ** Link encrypted with such LK can be used + ** for SM over BR/EDR. + */ + BOOLEAN no_smp_on_br; /* if set to TRUE then SMP on BR/EDR doesn't */ + /* work, i.e. link keys crosspairing */ + /* SC BR/EDR->SC LE doesn't happen */ + tBTM_BOND_TYPE bond_type; /* peering bond type */ + +#if BLE_INCLUDED == TRUE + tBTM_SEC_BLE ble; + tBTM_LE_CONN_PRAMS conn_params; +#endif + +// btla-specific ++ +#if BTM_DISC_DURING_RS == TRUE +#define BTM_SEC_RS_NOT_PENDING 0 /* Role Switch not in progress */ +#define BTM_SEC_RS_PENDING 1 /* Role Switch in progress */ +#define BTM_SEC_DISC_PENDING 2 /* Disconnect is pending */ + UINT8 rs_disc_pending; +#endif +// btla-specific -- +#define BTM_SEC_NO_LAST_SERVICE_ID 0 + UINT8 last_author_service_id; /* ID of last serviced authorized: Reset after each l2cap connection */ + +} tBTM_SEC_DEV_REC; + +#define BTM_SEC_IS_SM4(sm) ((BOOLEAN)(BTM_SM4_TRUE == ((sm)&BTM_SM4_TRUE))) +#define BTM_SEC_IS_SM4_LEGACY(sm) ((BOOLEAN)(BTM_SM4_KNOWN == ((sm)&BTM_SM4_TRUE))) +#define BTM_SEC_IS_SM4_UNKNOWN(sm) ((BOOLEAN)(BTM_SM4_UNKNOWN == ((sm)&BTM_SM4_TRUE))) + +#define BTM_SEC_LE_MASK (BTM_SEC_LE_AUTHENTICATED|BTM_SEC_LE_ENCRYPTED|BTM_SEC_LE_LINK_KEY_KNOWN|BTM_SEC_LE_LINK_KEY_AUTHED) + +/* +** Define device configuration structure +*/ +typedef struct +{ +#if BTM_MAX_LOC_BD_NAME_LEN > 0 + tBTM_LOC_BD_NAME bd_name; /* local Bluetooth device name */ +#endif + BOOLEAN pin_type; /* TRUE if PIN type is fixed */ + UINT8 pin_code_len; /* Bonding information */ + PIN_CODE pin_code; /* PIN CODE if pin type is fixed */ + BOOLEAN connectable; /* If TRUE page scan should be enabled */ + UINT8 def_inq_scan_mode; /* ??? limited/general/none */ +} tBTM_CFG; + +enum +{ + BTM_PM_ST_ACTIVE = BTM_PM_STS_ACTIVE, + BTM_PM_ST_HOLD = BTM_PM_STS_HOLD, + BTM_PM_ST_SNIFF = BTM_PM_STS_SNIFF, + BTM_PM_ST_PARK = BTM_PM_STS_PARK, + BTM_PM_ST_PENDING = BTM_PM_STS_PENDING +}; +typedef UINT8 tBTM_PM_STATE; + +enum +{ + BTM_PM_SET_MODE_EVT, /* Set power mode API is called. */ + BTM_PM_UPDATE_EVT, + BTM_PM_RD_MODE_EVT /* Read power mode API is called. */ +}; +typedef UINT8 tBTM_PM_EVENT; + +typedef struct +{ + UINT16 event; + UINT16 len; + UINT8 link_ind; +} tBTM_PM_MSG_DATA; + +typedef struct +{ + UINT8 hci_status; + UINT8 mode; + UINT16 interval; +} tBTM_PM_MD_CHG_DATA; + +typedef struct +{ + UINT8 pm_id; /* the entity that calls SetPowerMode API */ + tBTM_PM_PWR_MD *p_pmd; +} tBTM_PM_SET_MD_DATA; + +typedef struct +{ + void *p_data; + UINT8 link_ind; +} tBTM_PM_SM_DATA; + +typedef struct +{ + tBTM_PM_PWR_MD req_mode[BTM_MAX_PM_RECORDS+1]; /* the desired mode and parameters of the connection*/ + tBTM_PM_PWR_MD set_mode; /* the mode and parameters sent down to the host controller. */ + UINT16 interval; /* the interval from last mode change event. */ +#if (BTM_SSR_INCLUDED == TRUE) + UINT16 max_lat; /* stored SSR maximum latency */ + UINT16 min_rmt_to;/* stored SSR minimum remote timeout */ + UINT16 min_loc_to;/* stored SSR minimum local timeout */ +#endif + tBTM_PM_STATE state; /* contains the current mode of the connection */ + BOOLEAN chg_ind; /* a request change indication */ +} tBTM_PM_MCB; + +#define BTM_PM_REC_NOT_USED 0 +typedef struct +{ + tBTM_PM_STATUS_CBACK *cback;/* to notify the registered party of mode change event */ + UINT8 mask; /* registered request mask. 0, if this entry is not used */ +} tBTM_PM_RCB; + +enum +{ + BTM_BLI_ACL_UP_EVT, + BTM_BLI_ACL_DOWN_EVT, + BTM_BLI_PAGE_EVT, + BTM_BLI_PAGE_DONE_EVT, + BTM_BLI_INQ_EVT, + BTM_BLI_INQ_CANCEL_EVT, + BTM_BLI_INQ_DONE_EVT +}; +typedef UINT8 tBTM_BLI_EVENT; + +/* Pairing State */ +enum +{ + BTM_PAIR_STATE_IDLE, /* Idle */ + BTM_PAIR_STATE_GET_REM_NAME, /* Getting the remote name (to check for SM4) */ + BTM_PAIR_STATE_WAIT_PIN_REQ, /* Started authentication, waiting for PIN req (PIN is pre-fetched) */ + BTM_PAIR_STATE_WAIT_LOCAL_PIN, /* Waiting for local PIN code */ + BTM_PAIR_STATE_WAIT_NUMERIC_CONFIRM, /* Waiting user 'yes' to numeric confirmation */ + BTM_PAIR_STATE_KEY_ENTRY, /* Key entry state (we are a keyboard) */ + BTM_PAIR_STATE_WAIT_LOCAL_OOB_RSP, /* Waiting for local response to peer OOB data */ + BTM_PAIR_STATE_WAIT_LOCAL_IOCAPS, /* Waiting for local IO capabilities and OOB data */ + BTM_PAIR_STATE_INCOMING_SSP, /* Incoming SSP (got peer IO caps when idle) */ + BTM_PAIR_STATE_WAIT_AUTH_COMPLETE, /* All done, waiting authentication cpmplete */ + BTM_PAIR_STATE_WAIT_DISCONNECT /* Waiting to disconnect the ACL */ +}; +typedef UINT8 tBTM_PAIRING_STATE; + +#define BTM_PAIR_FLAGS_WE_STARTED_DD 0x01 /* We want to do dedicated bonding */ +#define BTM_PAIR_FLAGS_PEER_STARTED_DD 0x02 /* Peer initiated dedicated bonding */ +#define BTM_PAIR_FLAGS_DISC_WHEN_DONE 0x04 /* Disconnect when done */ +#define BTM_PAIR_FLAGS_PIN_REQD 0x08 /* set this bit when pin_callback is called */ +#define BTM_PAIR_FLAGS_PRE_FETCH_PIN 0x10 /* set this bit when pre-fetch pin */ +#define BTM_PAIR_FLAGS_REJECTED_CONNECT 0x20 /* set this bit when rejected incoming connection */ +#define BTM_PAIR_FLAGS_WE_CANCEL_DD 0x40 /* set this bit when cancelling a bonding procedure */ +#define BTM_PAIR_FLAGS_LE_ACTIVE 0x80 /* use this bit when SMP pairing is active */ + + +typedef struct +{ + BOOLEAN is_mux; + BD_ADDR bd_addr; + UINT16 psm; + BOOLEAN is_orig; + tBTM_SEC_CALLBACK *p_callback; + void *p_ref_data; + UINT32 mx_proto_id; + UINT32 mx_chan_id; + tBT_TRANSPORT transport; +} tBTM_SEC_QUEUE_ENTRY; + +#if (L2CAP_UCD_INCLUDED == TRUE) + +#define CONN_ORIENT_TERM 0x00 /* incoming connection oriented */ +#define CONN_ORIENT_ORIG 0x01 /* outgoing connection oriented */ +#define CONNLESS_TERM 0x02 /* incoming connectionless */ +#define CONNLESS_ORIG 0x03 /* outgoing connectionless */ +#define CONNECTION_TYPE_ORIG_MASK 0x01 /* mask for direction */ +#define CONNECTION_TYPE_CONNLESS_MASK 0x02 /* mask for connectionless or not */ +typedef UINT8 CONNECTION_TYPE; + +#else + +#define CONN_ORIENT_TERM FALSE +#define CONN_ORIENT_ORIG TRUE +typedef BOOLEAN CONNECTION_TYPE; + +#endif /* (L2CAP_UCD_INCLUDED == TRUE) */ + +/* Define a structure to hold all the BTM data +*/ + +#define BTM_STATE_BUFFER_SIZE 5 /* size of state buffer */ + +typedef struct +{ + tBTM_CFG cfg; /* Device configuration */ + + /**************************************************** + ** ACL Management + ****************************************************/ + tACL_CONN acl_db[MAX_L2CAP_LINKS]; + UINT8 btm_scn[BTM_MAX_SCN]; /* current SCNs: TRUE if SCN is in use */ + UINT16 btm_def_link_policy; + UINT16 btm_def_link_super_tout; + + tBTM_BL_EVENT_MASK bl_evt_mask; + tBTM_BL_CHANGE_CB *p_bl_changed_cb; /* Callback for when Busy Level changed */ + + /**************************************************** + ** Power Management + ****************************************************/ + tBTM_PM_MCB pm_mode_db[MAX_L2CAP_LINKS]; /* per ACL link */ + tBTM_PM_RCB pm_reg_db[BTM_MAX_PM_RECORDS+1]; /* per application/module */ + UINT8 pm_pend_link; /* the index of acl_db, which has a pending PM cmd */ + UINT8 pm_pend_id; /* the id pf the module, which has a pending PM cmd */ + + /***************************************************** + ** Device control + *****************************************************/ + tBTM_DEVCB devcb; + + /***************************************************** + ** BLE Device controllers + *****************************************************/ +#if (BLE_INCLUDED == TRUE) + tBTM_BLE_CB ble_ctr_cb; + + UINT16 enc_handle; + BT_OCTET8 enc_rand; /* received rand value from LTK request*/ + UINT16 ediv; /* received ediv value from LTK request */ + UINT8 key_size; + tBTM_BLE_VSC_CB cmn_ble_vsc_cb; +#endif + + /* Packet types supported by the local device */ + UINT16 btm_acl_pkt_types_supported; + UINT16 btm_sco_pkt_types_supported; + + + /***************************************************** + ** Inquiry + *****************************************************/ + tBTM_INQUIRY_VAR_ST btm_inq_vars; + + /***************************************************** + ** SCO Management + *****************************************************/ +#if BTM_SCO_INCLUDED == TRUE + tSCO_CB sco_cb; +#endif + + /***************************************************** + ** Security Management + *****************************************************/ + tBTM_APPL_INFO api; + +#define BTM_SEC_MAX_RMT_NAME_CALLBACKS 2 + tBTM_RMT_NAME_CALLBACK *p_rmt_name_callback[BTM_SEC_MAX_RMT_NAME_CALLBACKS]; + + tBTM_SEC_DEV_REC *p_collided_dev_rec; + TIMER_LIST_ENT sec_collision_tle; + UINT32 collision_start_time; + UINT32 max_collision_delay; + UINT32 dev_rec_count; /* Counter used for device record timestamp */ + UINT8 security_mode; + BOOLEAN pairing_disabled; + BOOLEAN connect_only_paired; + BOOLEAN security_mode_changed; /* mode changed during bonding */ + BOOLEAN pin_type_changed; /* pin type changed during bonding */ + BOOLEAN sec_req_pending; /* TRUE if a request is pending */ +// btla-specific ++ +#ifdef PORCHE_PAIRING_CONFLICT + UINT8 pin_code_len_saved; /* for legacy devices */ +#endif +// btla-specific -- + + UINT8 pin_code_len; /* for legacy devices */ + PIN_CODE pin_code; /* for legacy devices */ + tBTM_PAIRING_STATE pairing_state; /* The current pairing state */ + UINT8 pairing_flags; /* The current pairing flags */ + BD_ADDR pairing_bda; /* The device currently pairing */ + TIMER_LIST_ENT pairing_tle; /* Timer for pairing process */ + UINT16 disc_handle; /* for legacy devices */ + UINT8 disc_reason; /* for legacy devices */ + tBTM_SEC_SERV_REC sec_serv_rec[BTM_SEC_MAX_SERVICE_RECORDS]; + tBTM_SEC_DEV_REC sec_dev_rec[BTM_SEC_MAX_DEVICE_RECORDS]; + tBTM_SEC_SERV_REC *p_out_serv; + tBTM_MKEY_CALLBACK *mkey_cback; + + BD_ADDR connecting_bda; + DEV_CLASS connecting_dc; + + UINT8 acl_disc_reason; + UINT8 trace_level; + UINT8 busy_level; /* the current busy level */ + BOOLEAN is_paging; /* TRUE, if paging is in progess */ + BOOLEAN is_inquiry; /* TRUE, if inquiry is in progess */ + BUFFER_Q page_queue; + BOOLEAN paging; + BOOLEAN discing; + BUFFER_Q sec_pending_q; /* pending sequrity requests in tBTM_SEC_QUEUE_ENTRY format */ + +#if (!defined(BT_TRACE_VERBOSE) || (BT_TRACE_VERBOSE == FALSE)) + char state_temp_buffer[BTM_STATE_BUFFER_SIZE]; +#endif +} tBTM_CB; + +/* +#ifdef __cplusplus +extern "C" +{ +#endif +*/ + +#if BTM_DYNAMIC_MEMORY == FALSE +extern tBTM_CB btm_cb; +#else +extern tBTM_CB *btm_cb_ptr; +#define btm_cb (*btm_cb_ptr) +#endif + +/* Internal functions provided by btm_main.c +******************************************** +*/ +void btm_init (void); + +/* Internal functions provided by btm_inq.c +******************************************* +*/ +tBTM_STATUS btm_initiate_rem_name (BD_ADDR remote_bda, + tBTM_INQ_INFO *p_cur, + UINT8 origin, UINT32 timeout, + tBTM_CMPL_CB *p_cb); + +void btm_process_remote_name (BD_ADDR bda, BD_NAME name, UINT16 evt_len, + UINT8 hci_status); +void btm_inq_rmt_name_failed(void); + +/* Inquiry related functions */ +void btm_clr_inq_db (BD_ADDR p_bda); +void btm_inq_db_init (void); +void btm_process_inq_results (UINT8 *p, UINT8 inq_res_mode); +void btm_process_inq_complete (UINT8 status, UINT8 mode); +void btm_process_cancel_complete(UINT8 status, UINT8 mode); +void btm_event_filter_complete (UINT8 *p); +void btm_inq_stop_on_ssp(void); +void btm_inq_clear_ssp(void); +tINQ_DB_ENT *btm_inq_db_find (BD_ADDR p_bda); +BOOLEAN btm_inq_find_bdaddr (BD_ADDR p_bda); + +BOOLEAN btm_lookup_eir(BD_ADDR_PTR p_rem_addr); + +/* Internal functions provided by btm_acl.c +******************************************** +*/ +void btm_acl_init (void); +void btm_acl_created (BD_ADDR bda, DEV_CLASS dc, BD_NAME bdn, + UINT16 hci_handle, UINT8 link_role, tBT_TRANSPORT transport); +void btm_acl_removed (BD_ADDR bda, tBT_TRANSPORT transport); +void btm_acl_device_down (void); +void btm_acl_update_busy_level (tBTM_BLI_EVENT event); + +void btm_cont_rswitch (tACL_CONN *p, + tBTM_SEC_DEV_REC *p_dev_rec, + UINT8 hci_status); + +UINT8 btm_handle_to_acl_index (UINT16 hci_handle); +void btm_read_link_policy_complete (UINT8 *p); +void btm_read_rssi_complete (UINT8 *p); +void btm_read_tx_power_complete (UINT8 *p, BOOLEAN is_ble); +void btm_read_link_quality_complete (UINT8 *p); +tBTM_STATUS btm_set_packet_types (tACL_CONN *p, UINT16 pkt_types); +void btm_process_clk_off_comp_evt (UINT16 hci_handle, UINT16 clock_offset); +void btm_acl_role_changed (UINT8 hci_status, BD_ADDR bd_addr, UINT8 new_role); +void btm_acl_encrypt_change (UINT16 handle, UINT8 status, UINT8 encr_enable); +UINT16 btm_get_acl_disc_reason_code (void); +tBTM_STATUS btm_remove_acl (BD_ADDR bd_addr, tBT_TRANSPORT transport); +void btm_read_remote_features_complete (UINT8 *p); +void btm_read_remote_ext_features_complete (UINT8 *p); +void btm_read_remote_ext_features_failed (UINT8 status, UINT16 handle); +void btm_read_remote_version_complete (UINT8 *p); +void btm_establish_continue (tACL_CONN *p_acl_cb); + +// btla-specific ++ +void btm_acl_chk_peer_pkt_type_support (tACL_CONN *p, UINT16 *p_pkt_type); +// btla-specific -- +/* Read maximum data packet that can be sent over current connection */ +UINT16 btm_get_max_packet_size (BD_ADDR addr); +tACL_CONN *btm_bda_to_acl (BD_ADDR bda, tBT_TRANSPORT transport); +BOOLEAN btm_acl_notif_conn_collision (BD_ADDR bda); + +void btm_pm_reset(void); +void btm_pm_sm_alloc(UINT8 ind); +void btm_pm_proc_cmd_status(UINT8 status); +void btm_pm_proc_mode_change (UINT8 hci_status, UINT16 hci_handle, UINT8 mode, + UINT16 interval); +void btm_pm_proc_ssr_evt (UINT8 *p, UINT16 evt_len); +#if BTM_SCO_INCLUDED == TRUE +void btm_sco_chk_pend_unpark (UINT8 hci_status, UINT16 hci_handle); +#else +#define btm_sco_chk_pend_unpark(hci_status, hci_handle) +#endif /* BTM_SCO_INCLUDED */ +void btm_qos_setup_complete (UINT8 status, UINT16 handle, FLOW_SPEC *p_flow); + + +/* Internal functions provided by btm_sco.c +******************************************** +*/ +void btm_sco_init (void); +void btm_sco_connected (UINT8 hci_status, BD_ADDR bda, UINT16 hci_handle, + tBTM_ESCO_DATA *p_esco_data); +void btm_esco_proc_conn_chg (UINT8 status, UINT16 handle, UINT8 tx_interval, + UINT8 retrans_window, UINT16 rx_pkt_len, + UINT16 tx_pkt_len); +void btm_sco_conn_req (BD_ADDR bda, DEV_CLASS dev_class, UINT8 link_type); +void btm_sco_removed (UINT16 hci_handle, UINT8 reason); +void btm_sco_acl_removed (BD_ADDR bda); +void btm_route_sco_data (BT_HDR *p_msg); +BOOLEAN btm_is_sco_active (UINT16 handle); +void btm_remove_sco_links (BD_ADDR bda); +BOOLEAN btm_is_sco_active_by_bdaddr (BD_ADDR remote_bda); + +tBTM_SCO_TYPE btm_read_def_esco_mode (tBTM_ESCO_PARAMS *p_parms); +UINT16 btm_find_scb_by_handle (UINT16 handle); +void btm_sco_flush_sco_data(UINT16 sco_inx); + +/* Internal functions provided by btm_devctl.c +********************************************** +*/ +void btm_dev_init (void); +void btm_dev_timeout (TIMER_LIST_ENT *p_tle); +void btm_read_local_name_complete (UINT8 *p, UINT16 evt_len); + +#if (BLE_INCLUDED == TRUE) +void btm_ble_add_2_white_list_complete(UINT8 status); +void btm_ble_remove_from_white_list_complete(UINT8 *p, UINT16 evt_len); +void btm_ble_clear_white_list_complete(UINT8 *p, UINT16 evt_len); +BOOLEAN btm_ble_addr_resolvable(BD_ADDR rpa, tBTM_SEC_DEV_REC *p_dev_rec); +tBTM_STATUS btm_ble_read_resolving_list_entry(tBTM_SEC_DEV_REC *p_dev_rec); +BOOLEAN btm_ble_resolving_list_load_dev(tBTM_SEC_DEV_REC *p_dev_rec); +void btm_ble_resolving_list_remove_dev(tBTM_SEC_DEV_REC *p_dev_rec); +#endif /* BLE_INCLUDED */ + +/* Vendor Specific Command complete evt handler */ +void btm_vsc_complete (UINT8 *p, UINT16 cc_opcode, UINT16 evt_len, + tBTM_CMPL_CB *p_vsc_cplt_cback); +void btm_inq_db_reset (void); +void btm_vendor_specific_evt (UINT8 *p, UINT8 evt_len); +void btm_delete_stored_link_key_complete (UINT8 *p); +void btm_report_device_status (tBTM_DEV_STATUS status); + + +/* Internal functions provided by btm_dev.c +********************************************** +*/ +BOOLEAN btm_dev_support_switch (BD_ADDR bd_addr); + +tBTM_SEC_DEV_REC *btm_sec_alloc_dev (BD_ADDR bd_addr); +void btm_sec_free_dev (tBTM_SEC_DEV_REC *p_dev_rec); +tBTM_SEC_DEV_REC *btm_find_dev (BD_ADDR bd_addr); +tBTM_SEC_DEV_REC *btm_find_or_alloc_dev (BD_ADDR bd_addr); +tBTM_SEC_DEV_REC *btm_find_dev_by_handle (UINT16 handle); +tBTM_BOND_TYPE btm_get_bond_type_dev(BD_ADDR bd_addr); +BOOLEAN btm_set_bond_type_dev(BD_ADDR bd_addr, + tBTM_BOND_TYPE bond_type); + +/* Internal functions provided by btm_sec.c +********************************************** +*/ +BOOLEAN btm_dev_support_switch (BD_ADDR bd_addr); +tBTM_STATUS btm_sec_l2cap_access_req (BD_ADDR bd_addr, UINT16 psm, + UINT16 handle, CONNECTION_TYPE conn_type, + tBTM_SEC_CALLBACK *p_callback, void *p_ref_data); +tBTM_STATUS btm_sec_mx_access_request (BD_ADDR bd_addr, UINT16 psm, BOOLEAN is_originator, + UINT32 mx_proto_id, UINT32 mx_chan_id, + tBTM_SEC_CALLBACK *p_callback, void *p_ref_data); +void btm_sec_conn_req (UINT8 *bda, UINT8 *dc); +void btm_create_conn_cancel_complete (UINT8 *p); +void btm_read_linq_tx_power_complete (UINT8 *p); + +void btm_sec_init (UINT8 sec_mode); +void btm_sec_dev_reset (void); +void btm_sec_abort_access_req (BD_ADDR bd_addr); +void btm_sec_auth_complete (UINT16 handle, UINT8 status); +void btm_sec_encrypt_change (UINT16 handle, UINT8 status, UINT8 encr_enable); +void btm_sec_connected (UINT8 *bda, UINT16 handle, UINT8 status, UINT8 enc_mode); +tBTM_STATUS btm_sec_disconnect (UINT16 handle, UINT8 reason); +void btm_sec_disconnected (UINT16 handle, UINT8 reason); +void btm_sec_rmt_name_request_complete (UINT8 *bd_addr, UINT8 *bd_name, UINT8 status); +void btm_sec_rmt_host_support_feat_evt (UINT8 *p); +void btm_io_capabilities_req (UINT8 *p); +void btm_io_capabilities_rsp (UINT8 *p); +void btm_proc_sp_req_evt (tBTM_SP_EVT event, UINT8 *p); +void btm_keypress_notif_evt (UINT8 *p); +void btm_simple_pair_complete (UINT8 *p); +void btm_sec_link_key_notification (UINT8 *p_bda, UINT8 *p_link_key, UINT8 key_type); +void btm_sec_link_key_request (UINT8 *p_bda); +void btm_sec_pin_code_request (UINT8 *p_bda); +void btm_sec_update_clock_offset (UINT16 handle, UINT16 clock_offset); +void btm_sec_dev_rec_cback_event (tBTM_SEC_DEV_REC *p_dev_rec, UINT8 res, BOOLEAN is_le_trasnport); +void btm_sec_set_peer_sec_caps (tACL_CONN *p_acl_cb, tBTM_SEC_DEV_REC *p_dev_rec); + +#if BLE_INCLUDED == TRUE +void btm_sec_clear_ble_keys (tBTM_SEC_DEV_REC *p_dev_rec); +BOOLEAN btm_sec_find_bonded_dev (UINT8 start_idx, UINT8 *p_found_idx, tBTM_SEC_DEV_REC **p_rec); +BOOLEAN btm_sec_is_a_bonded_dev (BD_ADDR bda); +void btm_consolidate_dev(tBTM_SEC_DEV_REC *p_target_rec); +BOOLEAN btm_sec_is_le_capable_dev (BD_ADDR bda); +BOOLEAN btm_ble_init_pseudo_addr (tBTM_SEC_DEV_REC *p_dev_rec, BD_ADDR new_pseudo_addr); +#endif /* BLE_INCLUDED */ + +tINQ_DB_ENT *btm_inq_db_new (BD_ADDR p_bda); + +#if BTM_OOB_INCLUDED == TRUE +void btm_rem_oob_req (UINT8 *p); +void btm_read_local_oob_complete (UINT8 *p); +#else +#define btm_rem_oob_req(p) +#define btm_read_local_oob_complete(p) +#endif + +void btm_acl_resubmit_page (void); +void btm_acl_reset_paging (void); +void btm_acl_paging (BT_HDR *p, BD_ADDR dest); +UINT8 btm_sec_clr_service_by_psm (UINT16 psm); +void btm_sec_clr_temp_auth_service (BD_ADDR bda); + +/* +#ifdef __cplusplus +} +#endif +*/ + +#endif diff --git a/components/bt/bluedroid/stack/include/btu.h b/components/bt/bluedroid/stack/include/btu.h new file mode 100755 index 0000000000..176c121207 --- /dev/null +++ b/components/bt/bluedroid/stack/include/btu.h @@ -0,0 +1,284 @@ +/****************************************************************************** + * + * Copyright (C) 1999-2012 Broadcom Corporation + * + * 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 main Bluetooth Upper Layer definitions. The Broadcom + * implementations of L2CAP RFCOMM, SDP and the BTIf run as one GKI task. The + * btu_task switches between them. + * + ******************************************************************************/ + +#ifndef BTU_H +#define BTU_H + +#include "bt_target.h" +#include "gki.h" + +// HACK(zachoverflow): temporary dark magic +#define BTU_POST_TO_TASK_NO_GOOD_HORRIBLE_HACK 0x1700 // didn't look used in bt_types...here goes nothing +typedef struct { + void (*callback)(BT_HDR *); +} post_to_task_hack_t; + +typedef struct { + void (*callback)(BT_HDR *); + BT_HDR *response; + void *context; +} command_complete_hack_t; + +typedef struct { + void (*callback)(BT_HDR *); + uint8_t status; + BT_HDR *command; + void *context; +} command_status_hack_t; + +/* callbacks +*/ +typedef void (*tBTU_TIMER_CALLBACK)(TIMER_LIST_ENT *p_tle); +typedef void (*tBTU_EVENT_CALLBACK)(BT_HDR *p_hdr); + + +/* Define the timer types maintained by BTU +*/ +#define BTU_TTYPE_BTM_DEV_CTL 1 +#define BTU_TTYPE_L2CAP_LINK 2 +#define BTU_TTYPE_L2CAP_CHNL 3 +#define BTU_TTYPE_L2CAP_HOLD 4 +#define BTU_TTYPE_SDP 5 +#define BTU_TTYPE_BTM_SCO 6 +#define BTU_TTYPE_BTM_ACL 9 +#define BTU_TTYPE_BTM_RMT_NAME 10 +#define BTU_TTYPE_RFCOMM_MFC 11 +#define BTU_TTYPE_RFCOMM_PORT 12 +#define BTU_TTYPE_TCS_L2CAP 13 +#define BTU_TTYPE_TCS_CALL 14 +#define BTU_TTYPE_TCS_WUG 15 +#define BTU_TTYPE_AUTO_SYNC 16 +#define BTU_TTYPE_CTP_RECON 17 +#define BTU_TTYPE_CTP_T100 18 +#define BTU_TTYPE_CTP_GUARD 19 +#define BTU_TTYPE_CTP_DETACH 20 + +#define BTU_TTYPE_SPP_CONN_RETRY 21 +#define BTU_TTYPE_USER_FUNC 22 + +#define BTU_TTYPE_FTP_DISC 25 +#define BTU_TTYPE_OPP_DISC 26 + +#define BTU_TTYPE_CTP_TL_DISCVY 28 +#define BTU_TTYPE_IPFRAG_TIMER 29 +#define BTU_TTYPE_HSP2_AT_CMD_TO 30 +#define BTU_TTYPE_HSP2_REPEAT_RING 31 + +#define BTU_TTYPE_CTP_GW_INIT 32 +#define BTU_TTYPE_CTP_GW_CONN 33 +#define BTU_TTYPE_CTP_GW_IDLE 35 + +#define BTU_TTYPE_ICP_L2CAP 36 +#define BTU_TTYPE_ICP_T100 37 + +#define BTU_TTYPE_HSP2_WAIT_OK 38 + +/* HCRP Timers */ +#define BTU_TTYPE_HCRP_NOTIF_REG 39 +#define BTU_TTYPE_HCRP_PROTO_RSP 40 +#define BTU_TTYPE_HCRP_CR_GRANT 41 +#define BTU_TTYPE_HCRP_CR_CHECK 42 +#define BTU_TTYPE_HCRP_W4_CLOSE 43 + +/* HCRPM Timers */ +#define BTU_TTYPE_HCRPM_NOTIF_REG 44 +#define BTU_TTYPE_HCRPM_NOTIF_KEEP 45 +#define BTU_TTYPE_HCRPM_API_RSP 46 +#define BTU_TTYPE_HCRPM_W4_OPEN 47 +#define BTU_TTYPE_HCRPM_W4_CLOSE 48 + +/* BNEP Timers */ +#define BTU_TTYPE_BNEP 50 + +#define BTU_TTYPE_HSP2_SDP_FAIL_TO 55 +#define BTU_TTYPE_HSP2_SDP_RTRY_TO 56 + +/* BTU internal */ +/* unused 60 */ + +#define BTU_TTYPE_AVDT_CCB_RET 61 +#define BTU_TTYPE_AVDT_CCB_RSP 62 +#define BTU_TTYPE_AVDT_CCB_IDLE 63 +#define BTU_TTYPE_AVDT_SCB_TC 64 + +#define BTU_TTYPE_HID_DEV_REPAGE_TO 65 +#define BTU_TTYPE_HID_HOST_REPAGE_TO 66 + +#define BTU_TTYPE_HSP2_DELAY_CKPD_RCV 67 + +#define BTU_TTYPE_SAP_TO 68 + +/* BPP Timer */ +#define BTU_TTYPE_BPP_REF_CHNL 72 + +/* LP HC idle Timer */ +#define BTU_TTYPE_LP_HC_IDLE_TO 74 + +/* Patch RAM Timer */ +#define BTU_TTYPE_PATCHRAM_TO 75 + +/* eL2CAP Info Request and other proto cmds timer */ +#define BTU_TTYPE_L2CAP_FCR_ACK 78 +#define BTU_TTYPE_L2CAP_INFO 79 + +#define BTU_TTYPE_MCA_CCB_RSP 98 + +/* BTU internal timer for BLE activity */ +#define BTU_TTYPE_BLE_INQUIRY 99 +#define BTU_TTYPE_BLE_GAP_LIM_DISC 100 +#define BTU_TTYPE_ATT_WAIT_FOR_RSP 101 +#define BTU_TTYPE_SMP_PAIRING_CMD 102 +#define BTU_TTYPE_BLE_RANDOM_ADDR 103 +#define BTU_TTYPE_ATT_WAIT_FOR_APP_RSP 104 +#define BTU_TTYPE_ATT_WAIT_FOR_IND_ACK 105 + +#define BTU_TTYPE_BLE_GAP_FAST_ADV 106 +#define BTU_TTYPE_BLE_OBSERVE 107 + + +#define BTU_TTYPE_UCD_TO 108 + +/* This is the inquiry response information held by BTU, and available +** to applications. +*/ +typedef struct +{ + BD_ADDR remote_bd_addr; + UINT8 page_scan_rep_mode; + UINT8 page_scan_per_mode; + UINT8 page_scan_mode; + DEV_CLASS dev_class; + UINT16 clock_offset; +} tBTU_INQ_INFO; + + + +#define BTU_MAX_REG_TIMER (2) /* max # timer callbacks which may register */ +#define BTU_MAX_REG_EVENT (6) /* max # event callbacks which may register */ +#define BTU_DEFAULT_DATA_SIZE (0x2a0) + +#if (BLE_INCLUDED == TRUE) +#define BTU_DEFAULT_BLE_DATA_SIZE (27) +#endif + +/* structure to hold registered timers */ +typedef struct +{ + TIMER_LIST_ENT *p_tle; /* timer entry */ + tBTU_TIMER_CALLBACK timer_cb; /* callback triggered when timer expires */ +} tBTU_TIMER_REG; + +/* structure to hold registered event callbacks */ +typedef struct +{ + UINT16 event_range; /* start of event range */ + tBTU_EVENT_CALLBACK event_cb; /* callback triggered when event is in range */ +} tBTU_EVENT_REG; + +#define NFC_MAX_LOCAL_CTRLS 0 + +/* the index to BTU command queue array */ +#define NFC_CONTROLLER_ID (1) +#define BTU_MAX_LOCAL_CTRLS (1 + NFC_MAX_LOCAL_CTRLS) /* only BR/EDR */ + +/* Define structure holding BTU variables +*/ +typedef struct +{ + tBTU_TIMER_REG timer_reg[BTU_MAX_REG_TIMER]; + tBTU_EVENT_REG event_reg[BTU_MAX_REG_EVENT]; + + BOOLEAN reset_complete; /* TRUE after first ack from device received */ + UINT8 trace_level; /* Trace level for HCI layer */ +} tBTU_CB; + +/* +#ifdef __cplusplus +extern "C" { +#endif +*/ +/* Global BTU data */ +#if BTU_DYNAMIC_MEMORY == FALSE +extern tBTU_CB btu_cb; +#else +extern tBTU_CB *btu_cb_ptr; +#define btu_cb (*btu_cb_ptr) +#endif + +extern const BD_ADDR BT_BD_ANY; + +/* Functions provided by btu_task.c +************************************ +*/ +void btu_start_timer (TIMER_LIST_ENT *p_tle, UINT16 type, UINT32 timeout); +void btu_stop_timer (TIMER_LIST_ENT *p_tle); +void btu_start_timer_oneshot(TIMER_LIST_ENT *p_tle, UINT16 type, UINT32 timeout); +void btu_stop_timer_oneshot(TIMER_LIST_ENT *p_tle); + +void btu_uipc_rx_cback(BT_HDR *p_msg); + +/* +** Quick Timer +*/ +#if defined(QUICK_TIMER_TICKS_PER_SEC) && (QUICK_TIMER_TICKS_PER_SEC > 0) +void btu_start_quick_timer (TIMER_LIST_ENT *p_tle, UINT16 type, UINT32 timeout); +void btu_stop_quick_timer (TIMER_LIST_ENT *p_tle); +void btu_process_quick_timer_evt (void); +#endif + +#if (defined(HCILP_INCLUDED) && HCILP_INCLUDED == TRUE) +void btu_check_bt_sleep (void); +#endif + +/* Functions provided by btu_hcif.c +************************************ +*/ +void btu_hcif_process_event (UINT8 controller_id, BT_HDR *p_buf); +void btu_hcif_send_cmd (UINT8 controller_id, BT_HDR *p_msg); +void btu_hcif_send_host_rdy_for_data(void); +void btu_hcif_cmd_timeout (UINT8 controller_id); + +/* Functions provided by btu_core.c +************************************ +*/ +void btu_init_core(void); +void btu_free_core(void); + +void BTU_StartUp(void); +void BTU_ShutDown(void); + +void btu_task_start_up(void); +void btu_task_shut_down(void); + +UINT16 BTU_BleAclPktSize(void); + +/* +#ifdef __cplusplus +} +#endif +*/ + +#endif diff --git a/components/bt/bluedroid/stack/include/dyn_mem.h b/components/bt/bluedroid/stack/include/dyn_mem.h new file mode 100755 index 0000000000..2693ae6362 --- /dev/null +++ b/components/bt/bluedroid/stack/include/dyn_mem.h @@ -0,0 +1,154 @@ +/****************************************************************************** + * + * Copyright (C) 2002-2012 Broadcom Corporation + * + * 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. + * + ******************************************************************************/ +#ifndef DYN_MEM_H +#define DYN_MEM_H + +/**************************************************************************** +** Define memory usage for each CORE component (if not defined in bdroid_buildcfg.h) +** The default for each component is to use static memory allocations. +*/ +#ifndef BTU_DYNAMIC_MEMORY +#define BTU_DYNAMIC_MEMORY FALSE +#endif + +#ifndef BTM_DYNAMIC_MEMORY +#define BTM_DYNAMIC_MEMORY FALSE +#endif + +#ifndef SDP_DYNAMIC_MEMORY +#define SDP_DYNAMIC_MEMORY FALSE +#endif + +#ifndef L2C_DYNAMIC_MEMORY +#define L2C_DYNAMIC_MEMORY FALSE +#endif + +#ifndef RFC_DYNAMIC_MEMORY +#define RFC_DYNAMIC_MEMORY FALSE +#endif + +#ifndef TCS_DYNAMIC_MEMORY +#define TCS_DYNAMIC_MEMORY FALSE +#endif + +#ifndef BNEP_DYNAMIC_MEMORY +#define BNEP_DYNAMIC_MEMORY FALSE +#endif + +#ifndef AVDT_DYNAMIC_MEMORY +#define AVDT_DYNAMIC_MEMORY FALSE +#endif + +#ifndef AVCT_DYNAMIC_MEMORY +#define AVCT_DYNAMIC_MEMORY FALSE +#endif + +#ifndef MCA_DYNAMIC_MEMORY +#define MCA_DYNAMIC_MEMORY FALSE +#endif + +#ifndef GATT_DYNAMIC_MEMORY +#define GATT_DYNAMIC_MEMORY FALSE +#endif + +#ifndef SMP_DYNAMIC_MEMORY +#define SMP_DYNAMIC_MEMORY FALSE +#endif + +/**************************************************************************** +** Define memory usage for each PROFILE component (if not defined in bdroid_buildcfg.h) +** The default for each component is to use static memory allocations. +*/ +#ifndef A2D_DYNAMIC_MEMORY +#define A2D_DYNAMIC_MEMORY FALSE +#endif + +#ifndef VDP_DYNAMIC_MEMORY +#define VDP_DYNAMIC_MEMORY FALSE +#endif + +#ifndef AVRC_DYNAMIC_MEMORY +#define AVRC_DYNAMIC_MEMORY FALSE +#endif + +#ifndef BIP_DYNAMIC_MEMORY +#define BIP_DYNAMIC_MEMORY FALSE +#endif + +#ifndef BPP_DYNAMIC_MEMORY +#define BPP_DYNAMIC_MEMORY FALSE +#endif + +#ifndef CTP_DYNAMIC_MEMORY +#define CTP_DYNAMIC_MEMORY FALSE +#endif + +#ifndef FTP_DYNAMIC_MEMORY +#define FTP_DYNAMIC_MEMORY FALSE +#endif + +#ifndef HCRP_DYNAMIC_MEMORY +#define HCRP_DYNAMIC_MEMORY FALSE +#endif + +#ifndef HFP_DYNAMIC_MEMORY +#define HFP_DYNAMIC_MEMORY FALSE +#endif + +#ifndef HID_DYNAMIC_MEMORY +#define HID_DYNAMIC_MEMORY FALSE +#endif + +#ifndef HSP2_DYNAMIC_MEMORY +#define HSP2_DYNAMIC_MEMORY FALSE +#endif + +#ifndef ICP_DYNAMIC_MEMORY +#define ICP_DYNAMIC_MEMORY FALSE +#endif + +#ifndef OPP_DYNAMIC_MEMORY +#define OPP_DYNAMIC_MEMORY FALSE +#endif + +#ifndef PAN_DYNAMIC_MEMORY +#define PAN_DYNAMIC_MEMORY FALSE +#endif + +#ifndef SPP_DYNAMIC_MEMORY +#define SPP_DYNAMIC_MEMORY FALSE +#endif + +#ifndef SLIP_DYNAMIC_MEMORY +#define SLIP_DYNAMIC_MEMORY FALSE +#endif + +#ifndef LLCP_DYNAMIC_MEMORY +#define LLCP_DYNAMIC_MEMORY FALSE +#endif + +/**************************************************************************** +** Define memory usage for BTA (if not defined in bdroid_buildcfg.h) +** The default for each component is to use static memory allocations. +*/ +#ifndef BTA_DYNAMIC_MEMORY +#define BTA_DYNAMIC_MEMORY FALSE +#endif + +#endif /* #ifdef DYN_MEM_H */ + diff --git a/components/bt/bluedroid/stack/include/gap_api.h b/components/bt/bluedroid/stack/include/gap_api.h new file mode 100755 index 0000000000..755c49c0b8 --- /dev/null +++ b/components/bt/bluedroid/stack/include/gap_api.h @@ -0,0 +1,393 @@ +/****************************************************************************** + * + * Copyright (C) 2009-2013 Broadcom Corporation + * + * 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. + * + ******************************************************************************/ + +#ifndef GAP_API_H +#define GAP_API_H + +#include "profiles_api.h" +#include "btm_api.h" +#include "l2c_api.h" + +/***************************************************************************** +** Constants +*****************************************************************************/ +/*** GAP Error and Status Codes ***/ +#define GAP_UNSUPPORTED (GAP_ERR_GRP + 0x01) /* Unsupported call */ +#define GAP_EOINQDB (GAP_ERR_GRP + 0x02) /* End of inquiry database marker */ +#define GAP_ERR_BUSY (GAP_ERR_GRP + 0x03) /* The requested function was busy */ +#define GAP_ERR_NO_CTRL_BLK (GAP_ERR_GRP + 0x04) /* No control blocks available */ +#define GAP_ERR_STARTING_CMD (GAP_ERR_GRP + 0x05) /* Error occurred while initiating the command */ +#define GAP_NO_BDADDR_REC (GAP_ERR_GRP + 0x06) /* No Inquiry DB record for BD_ADDR */ +#define GAP_ERR_ILL_MODE (GAP_ERR_GRP + 0x07) /* An illegal mode parameter was detected */ +#define GAP_ERR_ILL_INQ_TIME (GAP_ERR_GRP + 0x08) /* An illegal time parameter was detected */ +#define GAP_ERR_ILL_PARM (GAP_ERR_GRP + 0x09) /* An illegal parameter was detected */ +#define GAP_ERR_REM_NAME (GAP_ERR_GRP + 0x0a) /* Error starting the remote device name request */ +#define GAP_CMD_INITIATED (GAP_ERR_GRP + 0x0b) /* The GAP command was started (result pending) */ +#define GAP_DEVICE_NOT_UP (GAP_ERR_GRP + 0x0c) /* The device was not up; the request was not executed */ +#define GAP_BAD_BD_ADDR (GAP_ERR_GRP + 0x0d) /* The bd addr passed in was not found or invalid */ + +#define GAP_ERR_BAD_HANDLE (GAP_ERR_GRP + 0x0e) /* Bad GAP handle */ +#define GAP_ERR_BUF_OFFSET (GAP_ERR_GRP + 0x0f) /* Buffer offset invalid */ +#define GAP_ERR_BAD_STATE (GAP_ERR_GRP + 0x10) /* Connection is in invalid state */ +#define GAP_NO_DATA_AVAIL (GAP_ERR_GRP + 0x11) /* No data available */ +#define GAP_ERR_CONGESTED (GAP_ERR_GRP + 0x12) /* BT stack is congested */ +#define GAP_ERR_SECURITY (GAP_ERR_GRP + 0x13) /* Security failed */ + +#define GAP_ERR_PROCESSING (GAP_ERR_GRP + 0x14) /* General error processing BTM request */ +#define GAP_ERR_TIMEOUT (GAP_ERR_GRP + 0x15) /* Timeout occurred while processing cmd */ +#define GAP_EVT_CONN_OPENED 0x0100 +#define GAP_EVT_CONN_CLOSED 0x0101 +#define GAP_EVT_CONN_DATA_AVAIL 0x0102 +#define GAP_EVT_CONN_CONGESTED 0x0103 +#define GAP_EVT_CONN_UNCONGESTED 0x0104 +/* Values for 'chan_mode_mask' field */ +/* GAP_ConnOpen() - optional channels to negotiate */ +#define GAP_FCR_CHAN_OPT_BASIC L2CAP_FCR_CHAN_OPT_BASIC +#define GAP_FCR_CHAN_OPT_ERTM L2CAP_FCR_CHAN_OPT_ERTM +#define GAP_FCR_CHAN_OPT_STREAM L2CAP_FCR_CHAN_OPT_STREAM +/*** used in connection variables and functions ***/ +#define GAP_INVALID_HANDLE 0xFFFF + +/* This is used to change the criteria for AMP */ +#define GAP_PROTOCOL_ID (UUID_PROTOCOL_UDP) + + +#ifndef GAP_PREFER_CONN_INT_MAX +#define GAP_PREFER_CONN_INT_MAX BTM_BLE_CONN_INT_MIN +#endif + +#ifndef GAP_PREFER_CONN_INT_MIN +#define GAP_PREFER_CONN_INT_MIN BTM_BLE_CONN_INT_MIN +#endif + +#ifndef GAP_PREFER_CONN_LATENCY +#define GAP_PREFER_CONN_LATENCY 0 +#endif + +#ifndef GAP_PREFER_CONN_SP_TOUT +#define GAP_PREFER_CONN_SP_TOUT 2000 +#endif + +/***************************************************************************** +** Type Definitions +*****************************************************************************/ +/* +** Callback function for connection services +*/ +typedef void (tGAP_CONN_CALLBACK) (UINT16 gap_handle, UINT16 event); + +/* +** Define the callback function prototypes. Parameters are specific +** to each event and are described below +*/ +typedef void (tGAP_CALLBACK) (UINT16 event, void *p_data); + + +/* Definition of the GAP_FindAddrByName results structure */ +typedef struct +{ + UINT16 status; + BD_ADDR bd_addr; + tBTM_BD_NAME devname; +} tGAP_FINDADDR_RESULTS; + +typedef struct +{ + UINT16 int_min; + UINT16 int_max; + UINT16 latency; + UINT16 sp_tout; +}tGAP_BLE_PREF_PARAM; + +typedef union +{ + tGAP_BLE_PREF_PARAM conn_param; + BD_ADDR reconn_bda; + UINT16 icon; + UINT8 *p_dev_name; + UINT8 addr_resolution; + +}tGAP_BLE_ATTR_VALUE; + +typedef void (tGAP_BLE_CMPL_CBACK)(BOOLEAN status, BD_ADDR addr, UINT16 length, char *p_name); + + +/***************************************************************************** +** External Function Declarations +*****************************************************************************/ + +/*** Functions for L2CAP connection interface ***/ + +/******************************************************************************* +** +** Function GAP_ConnOpen +** +** Description This function is called to open a generic L2CAP connection. +** +** Returns handle of the connection if successful, else GAP_INVALID_HANDLE +** +*******************************************************************************/ +extern UINT16 GAP_ConnOpen (char *p_serv_name, UINT8 service_id, BOOLEAN is_server, + BD_ADDR p_rem_bda, UINT16 psm, tL2CAP_CFG_INFO *p_cfg, + tL2CAP_ERTM_INFO *ertm_info, + UINT16 security, UINT8 chan_mode_mask, tGAP_CONN_CALLBACK *p_cb); + +/******************************************************************************* +** +** Function GAP_ConnClose +** +** Description This function is called to close a connection. +** +** Returns BT_PASS - closed OK +** GAP_ERR_BAD_HANDLE - invalid handle +** +*******************************************************************************/ +extern UINT16 GAP_ConnClose (UINT16 gap_handle); + +/******************************************************************************* +** +** Function GAP_ConnReadData +** +** Description GKI buffer unaware application will call this function +** after receiving GAP_EVT_RXDATA event. A data copy is made +** into the receive buffer parameter. +** +** Returns BT_PASS - data read +** GAP_ERR_BAD_HANDLE - invalid handle +** GAP_NO_DATA_AVAIL - no data available +** +*******************************************************************************/ +extern UINT16 GAP_ConnReadData (UINT16 gap_handle, UINT8 *p_data, + UINT16 max_len, UINT16 *p_len); + +/******************************************************************************* +** +** Function GAP_GetRxQueueCnt +** +** Description This function return number of bytes on the rx queue. +** +** Parameters: handle - Handle returned in the GAP_ConnOpen +** p_rx_queue_count - Pointer to return queue count in. +** +** +*******************************************************************************/ +extern int GAP_GetRxQueueCnt (UINT16 handle, UINT32 *p_rx_queue_count); + +/******************************************************************************* +** +** Function GAP_ConnBTRead +** +** Description GKI buffer aware applications will call this function after +** receiving an GAP_EVT_RXDATA event to process the incoming +** data buffer. +** +** Returns BT_PASS - data read +** GAP_ERR_BAD_HANDLE - invalid handle +** GAP_NO_DATA_AVAIL - no data available +** +*******************************************************************************/ +extern UINT16 GAP_ConnBTRead (UINT16 gap_handle, BT_HDR **pp_buf); + +/******************************************************************************* +** +** Function GAP_ConnBTWrite +** +** Description GKI buffer aware applications can call this function to write data +** by passing a pointer to the GKI buffer of data. +** +** Returns BT_PASS - data read +** GAP_ERR_BAD_HANDLE - invalid handle +** GAP_ERR_BAD_STATE - connection not established +** GAP_INVALID_BUF_OFFSET - buffer offset is invalid +*******************************************************************************/ +extern UINT16 GAP_ConnBTWrite (UINT16 gap_handle, BT_HDR *p_buf); + +/******************************************************************************* +** +** Function GAP_ConnWriteData +** +** Description GKI buffer unaware application will call this function +** to send data to the connection. A data copy is made into a GKI +** buffer. +** +** Returns BT_PASS - data read +** GAP_ERR_BAD_HANDLE - invalid handle +** GAP_ERR_BAD_STATE - connection not established +** GAP_CONGESTION - system is congested +** +*******************************************************************************/ +extern UINT16 GAP_ConnWriteData (UINT16 gap_handle, UINT8 *p_data, + UINT16 max_len, UINT16 *p_len); + +/******************************************************************************* +** +** Function GAP_ConnReconfig +** +** Description Applications can call this function to reconfigure the connection. +** +** Returns BT_PASS - config process started +** GAP_ERR_BAD_HANDLE - invalid handle +** +*******************************************************************************/ +extern UINT16 GAP_ConnReconfig (UINT16 gap_handle, tL2CAP_CFG_INFO *p_cfg); + +/******************************************************************************* +** +** Function GAP_ConnSetIdleTimeout +** +** Description Higher layers call this function to set the idle timeout for +** a connection, or for all future connections. The "idle timeout" +** is the amount of time that a connection can remain up with +** no L2CAP channels on it. A timeout of zero means that the +** connection will be torn down immediately when the last channel +** is removed. A timeout of 0xFFFF means no timeout. Values are +** in seconds. +** +** Returns BT_PASS - config process started +** GAP_ERR_BAD_HANDLE - invalid handle +** +*******************************************************************************/ +extern UINT16 GAP_ConnSetIdleTimeout (UINT16 gap_handle, UINT16 timeout); + +/******************************************************************************* +** +** Function GAP_ConnGetRemoteAddr +** +** Description This function is called to get the remote BD address +** of a connection. +** +** Returns BT_PASS - closed OK +** GAP_ERR_BAD_HANDLE - invalid handle +** +*******************************************************************************/ +extern UINT8 *GAP_ConnGetRemoteAddr (UINT16 gap_handle); + +/******************************************************************************* +** +** Function GAP_ConnGetRemMtuSize +** +** Description Returns the remote device's MTU size. +** +** Returns UINT16 - maximum size buffer that can be transmitted to the peer +** +*******************************************************************************/ +extern UINT16 GAP_ConnGetRemMtuSize (UINT16 gap_handle); + +/******************************************************************************* +** +** Function GAP_ConnGetL2CAPCid +** +** Description Returns the L2CAP channel id +** +** Parameters: handle - Handle of the connection +** +** Returns UINT16 - The L2CAP channel id +** 0, if error +** +*******************************************************************************/ +extern UINT16 GAP_ConnGetL2CAPCid (UINT16 gap_handle); + +/******************************************************************************* +** +** Function GAP_SetTraceLevel +** +** Description This function sets the trace level for GAP. If called with +** a value of 0xFF, it simply returns the current trace level. +** +** Returns The new or current trace level +** +*******************************************************************************/ +extern UINT8 GAP_SetTraceLevel (UINT8 new_level); + +/******************************************************************************* +** +** Function GAP_Init +** +** Description Initializes the control blocks used by GAP. +** This routine should not be called except once per +** stack invocation. +** +** Returns Nothing +** +*******************************************************************************/ +extern void GAP_Init(void); + +#if (BLE_INCLUDED == TRUE) +/******************************************************************************* +** +** Function GAP_BleAttrDBUpdate +** +** Description update GAP local BLE attribute database. +** +** Returns Nothing +** +*******************************************************************************/ +extern void GAP_BleAttrDBUpdate(UINT16 attr_uuid, tGAP_BLE_ATTR_VALUE *p_value); + + +/******************************************************************************* +** +** Function GAP_BleReadPeerPrefConnParams +** +** Description Start a process to read a connected peripheral's preferred +** connection parameters +** +** Returns TRUE if read started, else FALSE if GAP is busy +** +*******************************************************************************/ +extern BOOLEAN GAP_BleReadPeerPrefConnParams (BD_ADDR peer_bda); + +/******************************************************************************* +** +** Function GAP_BleReadPeerDevName +** +** Description Start a process to read a connected peripheral's device name. +** +** Returns TRUE if request accepted +** +*******************************************************************************/ +extern BOOLEAN GAP_BleReadPeerDevName (BD_ADDR peer_bda, tGAP_BLE_CMPL_CBACK *p_cback); + + +/******************************************************************************* +** +** Function GAP_BleReadPeerAddressResolutionCap +** +** Description Start a process to read peer address resolution capability +** +** Returns TRUE if request accepted +** +*******************************************************************************/ +extern BOOLEAN GAP_BleReadPeerAddressResolutionCap (BD_ADDR peer_bda, + tGAP_BLE_CMPL_CBACK *p_cback); + +/******************************************************************************* +** +** Function GAP_BleCancelReadPeerDevName +** +** Description Cancel reading a peripheral's device name. +** +** Returns TRUE if request accepted +** +*******************************************************************************/ +extern BOOLEAN GAP_BleCancelReadPeerDevName (BD_ADDR peer_bda); + + +#endif + +#endif /* GAP_API_H */ diff --git a/components/bt/bluedroid/stack/include/gap_int.h b/components/bt/bluedroid/stack/include/gap_int.h new file mode 100755 index 0000000000..36064c657b --- /dev/null +++ b/components/bt/bluedroid/stack/include/gap_int.h @@ -0,0 +1,162 @@ +/****************************************************************************** + * + * Copyright (C) 2009-2013 Broadcom Corporation + * + * 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. + * + ******************************************************************************/ + + +#ifndef GAP_INT_H +#define GAP_INT_H + +#include "bt_target.h" +#include "gap_api.h" +#include "gki.h" +#include "gatt_api.h" +#define GAP_MAX_BLOCKS 2 /* Concurrent GAP commands pending at a time*/ +/* Define the Generic Access Profile control structure */ +typedef struct +{ + void *p_data; /* Pointer to any data returned in callback */ + tGAP_CALLBACK *gap_cback; /* Pointer to users callback function */ + tGAP_CALLBACK *gap_inq_rslt_cback; /* Used for inquiry results */ + UINT16 event; /* Passed back in the callback */ + UINT8 index; /* Index of this control block and callback */ + BOOLEAN in_use; /* True when structure is allocated */ +} tGAP_INFO; + +/* Define the control block for the FindAddrByName operation (Only 1 active at a time) */ +typedef struct +{ + tGAP_CALLBACK *p_cback; + tBTM_INQ_INFO *p_cur_inq; /* Pointer to the current inquiry database entry */ + tGAP_FINDADDR_RESULTS results; + BOOLEAN in_use; +} tGAP_FINDADDR_CB; + +/* Define the GAP Connection Control Block. +*/ +typedef struct +{ +#define GAP_CCB_STATE_IDLE 0 +#define GAP_CCB_STATE_LISTENING 1 +#define GAP_CCB_STATE_CONN_SETUP 2 +#define GAP_CCB_STATE_CFG_SETUP 3 +#define GAP_CCB_STATE_WAIT_SEC 4 +#define GAP_CCB_STATE_CONNECTED 5 + UINT8 con_state; + +#define GAP_CCB_FLAGS_IS_ORIG 0x01 +#define GAP_CCB_FLAGS_HIS_CFG_DONE 0x02 +#define GAP_CCB_FLAGS_MY_CFG_DONE 0x04 +#define GAP_CCB_FLAGS_SEC_DONE 0x08 +#define GAP_CCB_FLAGS_CONN_DONE 0x0E + UINT8 con_flags; + + UINT8 service_id; /* Used by BTM */ + UINT16 gap_handle; /* GAP handle */ + UINT16 connection_id; /* L2CAP CID */ + BOOLEAN rem_addr_specified; + UINT8 chan_mode_mask; /* Supported channel modes (FCR) */ + BD_ADDR rem_dev_address; + UINT16 psm; + UINT16 rem_mtu_size; + + BOOLEAN is_congested; + BUFFER_Q tx_queue; /* Queue of buffers waiting to be sent */ + BUFFER_Q rx_queue; /* Queue of buffers waiting to be read */ + + UINT32 rx_queue_size; /* Total data count in rx_queue */ + + tGAP_CONN_CALLBACK *p_callback; /* Users callback function */ + + tL2CAP_CFG_INFO cfg; /* Configuration */ + tL2CAP_ERTM_INFO ertm_info; /* Pools and modes for ertm */ +} tGAP_CCB; + +typedef struct +{ +#if ((defined AMP_INCLUDED) && (AMP_INCLUDED == TRUE)) + tAMP_APPL_INFO reg_info; +#else + tL2CAP_APPL_INFO reg_info; /* L2CAP Registration info */ +#endif + tGAP_CCB ccb_pool[GAP_MAX_CONNECTIONS]; +} tGAP_CONN; + + +#if BLE_INCLUDED == TRUE +#define GAP_MAX_CHAR_NUM 4 + +typedef struct +{ + UINT16 handle; + UINT16 uuid; + tGAP_BLE_ATTR_VALUE attr_value; +}tGAP_ATTR; +#endif +/********************************************************************** +** M A I N C O N T R O L B L O C K +***********************************************************************/ + +#define GAP_MAX_CL GATT_CL_MAX_LCB + +typedef struct +{ + UINT16 uuid; + tGAP_BLE_CMPL_CBACK *p_cback; +} tGAP_BLE_REQ; + +typedef struct +{ + BD_ADDR bda; + tGAP_BLE_CMPL_CBACK *p_cback; + UINT16 conn_id; + UINT16 cl_op_uuid; + BOOLEAN in_use; + BOOLEAN connected; + BUFFER_Q pending_req_q; + +}tGAP_CLCB; + +typedef struct +{ + tGAP_INFO blk[GAP_MAX_BLOCKS]; + tBTM_CMPL_CB *btm_cback[GAP_MAX_BLOCKS]; + UINT8 trace_level; + tGAP_FINDADDR_CB findaddr_cb; /* Contains the control block for finding a device addr */ + tBTM_INQ_INFO *cur_inqptr; + +#if GAP_CONN_INCLUDED == TRUE + tGAP_CONN conn; +#endif + + /* LE GAP attribute database */ +#if BLE_INCLUDED == TRUE + tGAP_ATTR gatt_attr[GAP_MAX_CHAR_NUM]; + tGAP_CLCB clcb[GAP_MAX_CL]; /* connection link*/ + tGATT_IF gatt_if; +#endif +} tGAP_CB; + + +extern tGAP_CB gap_cb; +#if (GAP_CONN_INCLUDED == TRUE) + extern void gap_conn_init(void); +#endif +#if (BLE_INCLUDED == TRUE) + extern void gap_attr_db_init(void); +#endif + +#endif diff --git a/components/bt/bluedroid/stack/include/gatt_api.h b/components/bt/bluedroid/stack/include/gatt_api.h new file mode 100755 index 0000000000..6ef768763b --- /dev/null +++ b/components/bt/bluedroid/stack/include/gatt_api.h @@ -0,0 +1,1189 @@ +/****************************************************************************** + * + * Copyright (C) 1999-2012 Broadcom Corporation + * + * 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. + * + ******************************************************************************/ +#ifndef GATT_API_H +#define GATT_API_H + +#include "bt_target.h" +#include "gattdefs.h" +#include "btm_ble_api.h" + +/***************************************************************************** +** Constants +*****************************************************************************/ +/* Success code and error codes */ +#define GATT_SUCCESS 0x00 +#define GATT_INVALID_HANDLE 0x01 +#define GATT_READ_NOT_PERMIT 0x02 +#define GATT_WRITE_NOT_PERMIT 0x03 +#define GATT_INVALID_PDU 0x04 +#define GATT_INSUF_AUTHENTICATION 0x05 +#define GATT_REQ_NOT_SUPPORTED 0x06 +#define GATT_INVALID_OFFSET 0x07 +#define GATT_INSUF_AUTHORIZATION 0x08 +#define GATT_PREPARE_Q_FULL 0x09 +#define GATT_NOT_FOUND 0x0a +#define GATT_NOT_LONG 0x0b +#define GATT_INSUF_KEY_SIZE 0x0c +#define GATT_INVALID_ATTR_LEN 0x0d +#define GATT_ERR_UNLIKELY 0x0e +#define GATT_INSUF_ENCRYPTION 0x0f +#define GATT_UNSUPPORT_GRP_TYPE 0x10 +#define GATT_INSUF_RESOURCE 0x11 + + +#define GATT_ILLEGAL_PARAMETER 0x87 +#define GATT_NO_RESOURCES 0x80 +#define GATT_INTERNAL_ERROR 0x81 +#define GATT_WRONG_STATE 0x82 +#define GATT_DB_FULL 0x83 +#define GATT_BUSY 0x84 +#define GATT_ERROR 0x85 +#define GATT_CMD_STARTED 0x86 +#define GATT_PENDING 0x88 +#define GATT_AUTH_FAIL 0x89 +#define GATT_MORE 0x8a +#define GATT_INVALID_CFG 0x8b +#define GATT_SERVICE_STARTED 0x8c +#define GATT_ENCRYPED_MITM GATT_SUCCESS +#define GATT_ENCRYPED_NO_MITM 0x8d +#define GATT_NOT_ENCRYPTED 0x8e +#define GATT_CONGESTED 0x8f + + /* 0xE0 ~ 0xFC reserved for future use */ +#define GATT_CCC_CFG_ERR 0xFD /* Client Characteristic Configuration Descriptor Improperly Configured */ +#define GATT_PRC_IN_PROGRESS 0xFE /* Procedure Already in progress */ +#define GATT_OUT_OF_RANGE 0xFF /* Attribute value out of range */ +typedef UINT8 tGATT_STATUS; + + +#define GATT_RSP_ERROR 0x01 +#define GATT_REQ_MTU 0x02 +#define GATT_RSP_MTU 0x03 +#define GATT_REQ_FIND_INFO 0x04 +#define GATT_RSP_FIND_INFO 0x05 +#define GATT_REQ_FIND_TYPE_VALUE 0x06 +#define GATT_RSP_FIND_TYPE_VALUE 0x07 +#define GATT_REQ_READ_BY_TYPE 0x08 +#define GATT_RSP_READ_BY_TYPE 0x09 +#define GATT_REQ_READ 0x0A +#define GATT_RSP_READ 0x0B +#define GATT_REQ_READ_BLOB 0x0C +#define GATT_RSP_READ_BLOB 0x0D +#define GATT_REQ_READ_MULTI 0x0E +#define GATT_RSP_READ_MULTI 0x0F +#define GATT_REQ_READ_BY_GRP_TYPE 0x10 +#define GATT_RSP_READ_BY_GRP_TYPE 0x11 +#define GATT_REQ_WRITE 0x12 /* 0001-0010 (write)*/ +#define GATT_RSP_WRITE 0x13 +#define GATT_CMD_WRITE 0x52 /* changed in V4.0 01001-0010(write cmd)*/ +#define GATT_REQ_PREPARE_WRITE 0x16 +#define GATT_RSP_PREPARE_WRITE 0x17 +#define GATT_REQ_EXEC_WRITE 0x18 +#define GATT_RSP_EXEC_WRITE 0x19 +#define GATT_HANDLE_VALUE_NOTIF 0x1B +#define GATT_HANDLE_VALUE_IND 0x1D +#define GATT_HANDLE_VALUE_CONF 0x1E +#define GATT_SIGN_CMD_WRITE 0xD2 /* changed in V4.0 1101-0010 (signed write) see write cmd above*/ +#define GATT_OP_CODE_MAX GATT_HANDLE_VALUE_CONF + 1 /* 0x1E = 30 + 1 = 31*/ + + +#define GATT_HANDLE_IS_VALID(x) ((x) != 0) + +#define GATT_CONN_UNKNOWN 0 +#define GATT_CONN_L2C_FAILURE 1 /* general L2cap failure */ +#define GATT_CONN_TIMEOUT HCI_ERR_CONNECTION_TOUT /* 0x08 connection timeout */ +#define GATT_CONN_TERMINATE_PEER_USER HCI_ERR_PEER_USER /* 0x13 connection terminate by peer user */ +#define GATT_CONN_TERMINATE_LOCAL_HOST HCI_ERR_CONN_CAUSE_LOCAL_HOST /* 0x16 connectionterminated by local host */ +#define GATT_CONN_FAIL_ESTABLISH HCI_ERR_CONN_FAILED_ESTABLISHMENT/* 0x03E connection fail to establish */ +#define GATT_CONN_LMP_TIMEOUT HCI_ERR_LMP_RESPONSE_TIMEOUT /* 0x22 connection fail for LMP response tout */ +#define GATT_CONN_CANCEL L2CAP_CONN_CANCEL /* 0x0100 L2CAP connection cancelled */ +typedef UINT16 tGATT_DISCONN_REASON; + +/* MAX GATT MTU size +*/ +#ifndef GATT_MAX_MTU_SIZE + #define GATT_MAX_MTU_SIZE 517 +#endif + +/* max legth of an attribute value +*/ +#ifndef GATT_MAX_ATTR_LEN + #define GATT_MAX_ATTR_LEN 600 +#endif + +/* default GATT MTU size over LE link +*/ +#define GATT_DEF_BLE_MTU_SIZE 23 + +/* invalid connection ID +*/ +#define GATT_INVALID_CONN_ID 0xFFFF + +#ifndef GATT_CL_MAX_LCB + #define GATT_CL_MAX_LCB 12 // 22 +#endif + +#ifndef GATT_MAX_SCCB + #define GATT_MAX_SCCB 10 +#endif + + +/* GATT notification caching timer, default to be three seconds +*/ +#ifndef GATTC_NOTIF_TIMEOUT + #define GATTC_NOTIF_TIMEOUT 3 +#endif + +/***************************************************************************** +** GATT Structure Definition +*****************************************************************************/ + +/* Attribute permissions +*/ +#define GATT_PERM_READ (1 << 0) /* bit 0 */ +#define GATT_PERM_READ_ENCRYPTED (1 << 1) /* bit 1 */ +#define GATT_PERM_READ_ENC_MITM (1 << 2) /* bit 2 */ +#define GATT_PERM_WRITE (1 << 4) /* bit 4 */ +#define GATT_PERM_WRITE_ENCRYPTED (1 << 5) /* bit 5 */ +#define GATT_PERM_WRITE_ENC_MITM (1 << 6) /* bit 6 */ +#define GATT_PERM_WRITE_SIGNED (1 << 7) /* bit 7 */ +#define GATT_PERM_WRITE_SIGNED_MITM (1 << 8) /* bit 8 */ +typedef UINT16 tGATT_PERM; + +#define GATT_ENCRYPT_KEY_SIZE_MASK (0xF000) /* the MS nibble of tGATT_PERM; key size 7=0; size 16=9 */ + +#define GATT_READ_ALLOWED (GATT_PERM_READ | GATT_PERM_READ_ENCRYPTED | GATT_PERM_READ_ENC_MITM) +#define GATT_READ_AUTH_REQUIRED (GATT_PERM_READ_ENCRYPTED) +#define GATT_READ_MITM_REQUIRED (GATT_PERM_READ_ENC_MITM) +#define GATT_READ_ENCRYPTED_REQUIRED (GATT_PERM_READ_ENCRYPTED | GATT_PERM_READ_ENC_MITM) + + +#define GATT_WRITE_ALLOWED (GATT_PERM_WRITE | GATT_PERM_WRITE_ENCRYPTED | GATT_PERM_WRITE_ENC_MITM | \ + GATT_PERM_WRITE_SIGNED | GATT_PERM_WRITE_SIGNED_MITM) + +#define GATT_WRITE_AUTH_REQUIRED (GATT_PERM_WRITE_ENCRYPTED | GATT_PERM_WRITE_SIGNED) + +#define GATT_WRITE_MITM_REQUIRED (GATT_PERM_WRITE_ENC_MITM | GATT_PERM_WRITE_SIGNED_MITM) + +#define GATT_WRITE_ENCRYPTED_PERM (GATT_PERM_WRITE_ENCRYPTED | GATT_PERM_WRITE_ENC_MITM) + +#define GATT_WRITE_SIGNED_PERM (GATT_PERM_WRITE_SIGNED | GATT_PERM_WRITE_SIGNED_MITM) + + +/* Characteristic properties +*/ +#define GATT_CHAR_PROP_BIT_BROADCAST (1 << 0) +#define GATT_CHAR_PROP_BIT_READ (1 << 1) +#define GATT_CHAR_PROP_BIT_WRITE_NR (1 << 2) +#define GATT_CHAR_PROP_BIT_WRITE (1 << 3) +#define GATT_CHAR_PROP_BIT_NOTIFY (1 << 4) +#define GATT_CHAR_PROP_BIT_INDICATE (1 << 5) +#define GATT_CHAR_PROP_BIT_AUTH (1 << 6) +#define GATT_CHAR_PROP_BIT_EXT_PROP (1 << 7) +typedef UINT8 tGATT_CHAR_PROP; + + +/* Format of the value of a characteristic. enumeration type +*/ +enum +{ + GATT_FORMAT_RES, /* rfu */ + GATT_FORMAT_BOOL, /* 0x01 boolean */ + GATT_FORMAT_2BITS, /* 0x02 2 bit */ + GATT_FORMAT_NIBBLE, /* 0x03 nibble */ + GATT_FORMAT_UINT8, /* 0x04 uint8 */ + GATT_FORMAT_UINT12, /* 0x05 uint12 */ + GATT_FORMAT_UINT16, /* 0x06 uint16 */ + GATT_FORMAT_UINT24, /* 0x07 uint24 */ + GATT_FORMAT_UINT32, /* 0x08 uint32 */ + GATT_FORMAT_UINT48, /* 0x09 uint48 */ + GATT_FORMAT_UINT64, /* 0x0a uint64 */ + GATT_FORMAT_UINT128, /* 0x0B uint128 */ + GATT_FORMAT_SINT8, /* 0x0C signed 8 bit integer */ + GATT_FORMAT_SINT12, /* 0x0D signed 12 bit integer */ + GATT_FORMAT_SINT16, /* 0x0E signed 16 bit integer */ + GATT_FORMAT_SINT24, /* 0x0F signed 24 bit integer */ + GATT_FORMAT_SINT32, /* 0x10 signed 32 bit integer */ + GATT_FORMAT_SINT48, /* 0x11 signed 48 bit integer */ + GATT_FORMAT_SINT64, /* 0x12 signed 64 bit integer */ + GATT_FORMAT_SINT128, /* 0x13 signed 128 bit integer */ + GATT_FORMAT_FLOAT32, /* 0x14 float 32 */ + GATT_FORMAT_FLOAT64, /* 0x15 float 64*/ + GATT_FORMAT_SFLOAT, /* 0x16 IEEE-11073 16 bit SFLOAT */ + GATT_FORMAT_FLOAT, /* 0x17 IEEE-11073 32 bit SFLOAT */ + GATT_FORMAT_DUINT16, /* 0x18 IEEE-20601 format */ + GATT_FORMAT_UTF8S, /* 0x19 UTF-8 string */ + GATT_FORMAT_UTF16S, /* 0x1a UTF-16 string */ + GATT_FORMAT_STRUCT, /* 0x1b Opaque structure*/ + GATT_FORMAT_MAX /* 0x1c or above reserved */ +}; +typedef UINT8 tGATT_FORMAT; + +/* Characteristic Presentation Format Descriptor value +*/ +typedef struct +{ + UINT16 unit; /* as UUIUD defined by SIG */ + UINT16 descr; /* as UUID as defined by SIG */ + tGATT_FORMAT format; + INT8 exp; + UINT8 name_spc; /* The name space of the description */ +} tGATT_CHAR_PRES; + +/* Characteristic Report reference Descriptor format +*/ +typedef struct +{ + UINT8 rpt_id; /* report ID */ + UINT8 rpt_type; /* report type */ +} tGATT_CHAR_RPT_REF; + + +#define GATT_VALID_RANGE_MAX_SIZE 16 +typedef struct +{ + UINT8 format; + UINT16 len; + UINT8 lower_range[GATT_VALID_RANGE_MAX_SIZE]; /* in little endian format */ + UINT8 upper_range[GATT_VALID_RANGE_MAX_SIZE]; +} tGATT_VALID_RANGE; + +/* Characteristic Aggregate Format attribute value +*/ +#define GATT_AGGR_HANDLE_NUM_MAX 10 +typedef struct +{ + UINT8 num_handle; + UINT16 handle_list[GATT_AGGR_HANDLE_NUM_MAX]; +} tGATT_CHAR_AGGRE; + +/* Characteristic descriptor: Extended Properties value +*/ +#define GATT_CHAR_BIT_REL_WRITE 0x0001 /* permits reliable writes of the Characteristic Value */ +#define GATT_CHAR_BIT_WRITE_AUX 0x0002 /* permits writes to the characteristic descriptor */ + + +/* characteristic descriptor: client configuration value +*/ +#define GATT_CLT_CONFIG_NONE 0x0000 +#define GATT_CLT_CONFIG_NOTIFICATION 0x0001 +#define GATT_CLT_CONFIG_INDICATION 0x0002 +typedef UINT16 tGATT_CLT_CHAR_CONFIG; + + +/* characteristic descriptor: server configuration value +*/ +#define GATT_SVR_CONFIG_NONE 0x0000 +#define GATT_SVR_CONFIG_BROADCAST 0x0001 +typedef UINT16 tGATT_SVR_CHAR_CONFIG; + +/* Characteristic descriptor: Extended Properties value +*/ +#define GATT_CHAR_BIT_REL_WRITE 0x0001 /* permits reliable writes of the Characteristic Value */ +#define GATT_CHAR_BIT_WRITE_AUX 0x0002 /* permits writes to the characteristic descriptor */ + +/* authentication requirement +*/ +#define GATT_AUTH_REQ_NONE 0 +#define GATT_AUTH_REQ_NO_MITM 1 /* unauthenticated encryption */ +#define GATT_AUTH_REQ_MITM 2 /* authenticated encryption */ +#define GATT_AUTH_REQ_SIGNED_NO_MITM 3 +#define GATT_AUTH_REQ_SIGNED_MITM 4 +typedef UINT8 tGATT_AUTH_REQ; + +/* Attribute Value structure +*/ +typedef struct +{ + UINT16 conn_id; + UINT16 handle; /* attribute handle */ + UINT16 offset; /* attribute value offset, if no offfset is needed for the command, ignore it */ + UINT16 len; /* length of attribute value */ + tGATT_AUTH_REQ auth_req; /* authentication request */ + UINT8 value[GATT_MAX_ATTR_LEN]; /* the actual attribute value */ +} tGATT_VALUE; + +/* Union of the event data which is used in the server respond API to carry the server response information +*/ +typedef union +{ + /* data type member event */ + tGATT_VALUE attr_value; /* READ, HANDLE_VALUE_IND, PREPARE_WRITE */ + /* READ_BLOB, READ_BY_TYPE */ + UINT16 handle; /* WRITE, WRITE_BLOB */ + +} tGATTS_RSP; + +/* Transports for the primary service */ +#define GATT_TRANSPORT_LE BT_TRANSPORT_LE +#define GATT_TRANSPORT_BR_EDR BT_TRANSPORT_BR_EDR +#define GATT_TRANSPORT_LE_BR_EDR (BT_TRANSPORT_LE|BT_TRANSPORT_BR_EDR) +typedef UINT8 tGATT_TRANSPORT; + +#define GATT_PREP_WRITE_CANCEL 0x00 +#define GATT_PREP_WRITE_EXEC 0x01 +typedef UINT8 tGATT_EXEC_FLAG; + +/* read request always based on UUID */ +typedef struct +{ + UINT16 handle; + UINT16 offset; + BOOLEAN is_long; +} tGATT_READ_REQ; + +/* write request data */ +typedef struct +{ + UINT16 handle; /* attribute handle */ + UINT16 offset; /* attribute value offset, if no offfset is needed for the command, ignore it */ + UINT16 len; /* length of attribute value */ + UINT8 value[GATT_MAX_ATTR_LEN]; /* the actual attribute value */ + BOOLEAN need_rsp; /* need write response */ + BOOLEAN is_prep; /* is prepare write */ +} tGATT_WRITE_REQ; + +/* callback data for server access request from client */ +typedef union +{ + tGATT_READ_REQ read_req; /* read request, read by Type, read blob */ + + tGATT_WRITE_REQ write_req; /* write */ + /* prepare write */ + /* write blob */ + UINT16 handle; /* handle value confirmation */ + UINT16 mtu; /* MTU exchange request */ + tGATT_EXEC_FLAG exec_write; /* execute write */ +} tGATTS_DATA; + +typedef UINT8 tGATT_SERV_IF; /* GATT Service Interface */ + +enum +{ + GATTS_REQ_TYPE_READ = 1, /* Attribute read request */ + GATTS_REQ_TYPE_WRITE, /* Attribute write request */ + GATTS_REQ_TYPE_WRITE_EXEC, /* Execute write */ + GATTS_REQ_TYPE_MTU, /* MTU exchange information */ + GATTS_REQ_TYPE_CONF /* handle value confirmation */ +}; +typedef UINT8 tGATTS_REQ_TYPE; + + + +/* Client Used Data Structure +*/ +/* definition of different discovery types */ +enum +{ + GATT_DISC_SRVC_ALL = 1, /* discover all services */ + GATT_DISC_SRVC_BY_UUID, /* discover service of a special type */ + GATT_DISC_INC_SRVC, /* discover the included service within a service */ + GATT_DISC_CHAR, /* discover characteristics of a service with/without type requirement */ + GATT_DISC_CHAR_DSCPT, /* discover characteristic descriptors of a character */ + GATT_DISC_MAX /* maximnun discover type */ +}; +typedef UINT8 tGATT_DISC_TYPE; + +/* Discover parameters of different discovery types +*/ +typedef struct +{ + tBT_UUID service; + UINT16 s_handle; + UINT16 e_handle; +}tGATT_DISC_PARAM; + +/* GATT read type enumeration +*/ +enum +{ + GATT_READ_BY_TYPE = 1, + GATT_READ_BY_HANDLE, + GATT_READ_MULTIPLE, + GATT_READ_CHAR_VALUE, + GATT_READ_PARTIAL, + GATT_READ_MAX +}; +typedef UINT8 tGATT_READ_TYPE; + +/* Read By Type Request (GATT_READ_BY_TYPE) Data +*/ +typedef struct +{ + tGATT_AUTH_REQ auth_req; + UINT16 s_handle; + UINT16 e_handle; + tBT_UUID uuid; +} tGATT_READ_BY_TYPE; + +/* GATT_READ_MULTIPLE request data +*/ +#define GATT_MAX_READ_MULTI_HANDLES 10 /* Max attributes to read in one request */ +typedef struct +{ + tGATT_AUTH_REQ auth_req; + UINT16 num_handles; /* number of handles to read */ + UINT16 handles[GATT_MAX_READ_MULTI_HANDLES]; /* handles list to be read */ +} tGATT_READ_MULTI; + +/* Read By Handle Request (GATT_READ_BY_HANDLE) data */ +typedef struct +{ + tGATT_AUTH_REQ auth_req; + UINT16 handle; +} tGATT_READ_BY_HANDLE; + +/* READ_BT_HANDLE_Request data */ +typedef struct +{ + tGATT_AUTH_REQ auth_req; + UINT16 handle; + UINT16 offset; +} tGATT_READ_PARTIAL; + +/* Read Request Data +*/ +typedef union +{ + tGATT_READ_BY_TYPE service; + tGATT_READ_BY_TYPE char_type; /* characterisitc type */ + tGATT_READ_MULTI read_multiple; + tGATT_READ_BY_HANDLE by_handle; + tGATT_READ_PARTIAL partial; +} tGATT_READ_PARAM; + +/* GATT write type enumeration */ +enum +{ + GATT_WRITE_NO_RSP = 1, + GATT_WRITE , + GATT_WRITE_PREPARE +}; +typedef UINT8 tGATT_WRITE_TYPE; + +/* Client Operation Complete Callback Data +*/ +typedef union +{ + tGATT_VALUE att_value; + UINT16 mtu; + UINT16 handle; +} tGATT_CL_COMPLETE; + +/* GATT client operation type, used in client callback function +*/ +#define GATTC_OPTYPE_NONE 0 +#define GATTC_OPTYPE_DISCOVERY 1 +#define GATTC_OPTYPE_READ 2 +#define GATTC_OPTYPE_WRITE 3 +#define GATTC_OPTYPE_EXE_WRITE 4 +#define GATTC_OPTYPE_CONFIG 5 +#define GATTC_OPTYPE_NOTIFICATION 6 +#define GATTC_OPTYPE_INDICATION 7 +typedef UINT8 tGATTC_OPTYPE; + +/* characteristic declaration +*/ +typedef struct +{ + tGATT_CHAR_PROP char_prop; /* characterisitc properties */ + UINT16 val_handle; /* characteristic value attribute handle */ + tBT_UUID char_uuid; /* characteristic UUID type */ +} tGATT_CHAR_DCLR_VAL; + +/* primary service group data +*/ +typedef struct +{ + UINT16 e_handle; /* ending handle of the group */ + tBT_UUID service_type; /* group type */ +} tGATT_GROUP_VALUE; + + +/* included service attribute value +*/ +typedef struct +{ + tBT_UUID service_type; /* included service UUID */ + UINT16 s_handle; /* starting handle */ + UINT16 e_handle; /* ending handle */ +} tGATT_INCL_SRVC; + +typedef union +{ + tGATT_INCL_SRVC incl_service; /* include service value */ + tGATT_GROUP_VALUE group_value; /* Service UUID type. + This field is used with GATT_DISC_SRVC_ALL + or GATT_DISC_SRVC_BY_UUID + type of discovery result callback. */ + + UINT16 handle; /* When used with GATT_DISC_INC_SRVC type discovery result, + it is the included service starting handle.*/ + + tGATT_CHAR_DCLR_VAL dclr_value; /* Characteristic declaration value. + This field is used with GATT_DISC_CHAR type discovery.*/ +} tGATT_DISC_VALUE; + +/* discover result record +*/ +typedef struct +{ + tBT_UUID type; + UINT16 handle; + tGATT_DISC_VALUE value; +} tGATT_DISC_RES; + + +#define GATT_LINK_IDLE_TIMEOUT_WHEN_NO_APP 0 /* start a idle timer for this duration + when no application need to use the link */ + +#define GATT_LINK_NO_IDLE_TIMEOUT 0xFFFF + +#define GATT_INVALID_ACL_HANDLE 0xFFFF +/* discover result callback function */ +typedef void (tGATT_DISC_RES_CB) (UINT16 conn_id, tGATT_DISC_TYPE disc_type, + tGATT_DISC_RES *p_data); + +/* discover complete callback function */ +typedef void (tGATT_DISC_CMPL_CB) (UINT16 conn_id, tGATT_DISC_TYPE disc_type, tGATT_STATUS status); + +/* Define a callback function for when read/write/disc/config operation is completed. */ +typedef void (tGATT_CMPL_CBACK) (UINT16 conn_id, tGATTC_OPTYPE op, tGATT_STATUS status, + tGATT_CL_COMPLETE *p_data); + +/* Define a callback function when an initialized connection is established. */ +typedef void (tGATT_CONN_CBACK) (tGATT_IF gatt_if, BD_ADDR bda, UINT16 conn_id, BOOLEAN connected, + tGATT_DISCONN_REASON reason, tBT_TRANSPORT transport); + +/* attribute request callback for ATT server */ +typedef void (tGATT_REQ_CBACK )(UINT16 conn_id, UINT32 trans_id, tGATTS_REQ_TYPE type, + tGATTS_DATA *p_data); + +/* channel congestion/uncongestion callback */ +typedef void (tGATT_CONGESTION_CBACK )(UINT16 conn_id, BOOLEAN congested); + +/* Define a callback function when encryption is established. */ +typedef void (tGATT_ENC_CMPL_CB)(tGATT_IF gatt_if, BD_ADDR bda); + + +/* Define the structure that applications use to register with +** GATT. This structure includes callback functions. All functions +** MUST be provided. +*/ +typedef struct +{ + tGATT_CONN_CBACK *p_conn_cb; + tGATT_CMPL_CBACK *p_cmpl_cb; + tGATT_DISC_RES_CB *p_disc_res_cb; + tGATT_DISC_CMPL_CB *p_disc_cmpl_cb; + tGATT_REQ_CBACK *p_req_cb; + tGATT_ENC_CMPL_CB *p_enc_cmpl_cb; + tGATT_CONGESTION_CBACK *p_congestion_cb; +} tGATT_CBACK; + +/*********************** Start Handle Management Definitions ********************** +*/ + + +typedef struct +{ + tBT_UUID app_uuid128; + tBT_UUID svc_uuid; + UINT16 svc_inst; + UINT16 s_handle; + UINT16 e_handle; + BOOLEAN is_primary; /* primary service or secondary */ +} tGATTS_HNDL_RANGE; + + + +#define GATTS_SRV_CHG_CMD_ADD_CLIENT 1 +#define GATTS_SRV_CHG_CMD_UPDATE_CLIENT 2 +#define GATTS_SRV_CHG_CMD_REMOVE_CLIENT 3 +#define GATTS_SRV_CHG_CMD_READ_NUM_CLENTS 4 +#define GATTS_SRV_CHG_CMD_READ_CLENT 5 +typedef UINT8 tGATTS_SRV_CHG_CMD; + +typedef struct +{ + BD_ADDR bda; + BOOLEAN srv_changed; +} tGATTS_SRV_CHG; + + +typedef union +{ + tGATTS_SRV_CHG srv_chg; + UINT8 client_read_index; /* only used for sequential reading client srv chg info */ +} tGATTS_SRV_CHG_REQ; + +typedef union +{ + tGATTS_SRV_CHG srv_chg; + UINT8 num_clients; +} tGATTS_SRV_CHG_RSP; + + + +typedef struct +{ + tGATTS_HNDL_RANGE *p_new_srv_start; +} tGATTS_PENDING_NEW_SRV_START; + +/* Attibute server handle ranges NV storage callback functions +*/ +typedef void (tGATTS_NV_SAVE_CBACK)(BOOLEAN is_saved, tGATTS_HNDL_RANGE *p_hndl_range); +typedef BOOLEAN (tGATTS_NV_SRV_CHG_CBACK)(tGATTS_SRV_CHG_CMD cmd, tGATTS_SRV_CHG_REQ *p_req, + tGATTS_SRV_CHG_RSP *p_rsp); + +typedef struct +{ + tGATTS_NV_SAVE_CBACK *p_nv_save_callback; + tGATTS_NV_SRV_CHG_CBACK *p_srv_chg_callback; +} tGATT_APPL_INFO; + +/* +*********************** End Handle Management Definitions **********************/ + +/***************************************************************************** +** External Function Declarations +*****************************************************************************/ +#ifdef __cplusplus +extern "C" +{ +#endif + +/******************************************************************************* +** +** Function GATT_SetTraceLevel +** +** Description This function sets the trace level. If called with +** a value of 0xFF, it simply returns the current trace level. +** +** Returns The new or current trace level +** +*******************************************************************************/ +extern UINT8 GATT_SetTraceLevel (UINT8 new_level); + + +/*******************************************************************************/ +/* GATT Profile API Functions */ +/*******************************************************************************/ +/* GATT Profile Server Functions */ +/*******************************************************************************/ +/******************************************************************************* +** +** Function GATTS_AddHandleRange +** +** Description This function add the allocated handles range for the specifed +** application UUID, service UUID and service instance +** +** Parameter p_hndl_range: pointer to allocated handles information +** +** Returns TRUE if handle range is added sucessfully; otherwise FALSE. +** +*******************************************************************************/ + +extern BOOLEAN GATTS_AddHandleRange(tGATTS_HNDL_RANGE *p_hndl_range); + +/******************************************************************************* +** +** Function GATTS_NVRegister +** +** Description Application manager calls this function to register for +** NV save callback function. There can be one and only one +** NV save callback function. +** +** Parameter p_cb_info : callback informaiton +** +** Returns TRUE if registered OK, else FALSE +** +*******************************************************************************/ +extern BOOLEAN GATTS_NVRegister (tGATT_APPL_INFO *p_cb_info); + + +/******************************************************************************* +** +** Function GATTS_CreateService +** +** Description This function is called to reserve a block of handles for a service. +** +** *** It should be called only once per service instance *** +** +** Parameter gatt_if : application if +** p_svc_uuid : service UUID +** svc_inst : instance of the service inside the application +** num_handles : number of handles needed by the service. +** is_pri : is a primary service or not. +** +** Returns service handle if sucessful, otherwise 0. +** +*******************************************************************************/ +extern UINT16 GATTS_CreateService (tGATT_IF gatt_if, tBT_UUID *p_svc_uuid, + UINT16 svc_inst, UINT16 num_handles, BOOLEAN is_pri); + + +/******************************************************************************* +** +** Function GATTS_AddIncludeService +** +** Description This function is called to add an included service. +** +** Parameter service_handle : To which service this included service is added to. +** include_svc_handle : included service handle. +** +** Returns included service attribute handle. If 0, add included service +** fail. +** +*******************************************************************************/ +extern UINT16 GATTS_AddIncludeService (UINT16 service_handle, + UINT16 include_svc_handle); + + +/******************************************************************************* +** +** Function GATTS_AddCharacteristic +** +** Description This function is called to add a characteristic into a service. +** It will add a characteristic declaration and characteristic +** value declaration into the service database identified by the +** service handle. +** +** Parameter service_handle : To which service this included service is added to. +** char_uuid : Characteristic UUID. +** perm : Characteristic value declaration attribute permission. +** property : Characteristic Properties +** +** Returns Characteristic value declaration attribute handle. 0 if add +** characteristic failed. +** +*******************************************************************************/ +extern UINT16 GATTS_AddCharacteristic (UINT16 service_handle, tBT_UUID *char_uuid, + tGATT_PERM perm,tGATT_CHAR_PROP property); + +/******************************************************************************* +** +** Function GATTS_AddCharDescriptor +** +** Description This function is called to add a characteristic descriptor +** into a service database. Add descriptor should follow add char +** to which it belongs, and next add char should be done only +** after all add descriptors for the previous char. +** +** Parameter service_handle : To which service this characteristic descriptor +** is added to. +** perm : Characteristic value declaration attribute +** permission. +** p_descr_uuid : Characteristic descriptor UUID. +** +** Returns Characteristic descriptor attribute handle. 0 if add +** characteristic descriptor failed. +** +*******************************************************************************/ +extern UINT16 GATTS_AddCharDescriptor (UINT16 service_handle, tGATT_PERM perm, + tBT_UUID * p_descr_uuid); + +/******************************************************************************* +** +** Function GATTS_DeleteService +** +** Description This function is called to delete a service. +** +** Parameter gatt_if : application interface +** p_svc_uuid : service UUID +** svc_inst : instance of the service inside the application +** +** Returns TRUE if operation succeed, FALSE if handle block was not found. +** +*******************************************************************************/ +extern BOOLEAN GATTS_DeleteService (tGATT_IF gatt_if, tBT_UUID *p_svc_uuid, + UINT16 svc_inst); + +/******************************************************************************* +** +** Function GATTS_StartService +** +** Description This function is called to start a service with GATT +** +** Parameter gatt_if : service handle. +** p_cback : application service callback functions. +** sup_transport : supported transport(s) for this primary service +** +** return GATT_SUCCESS if sucessfully started; otherwise error code. +** +*******************************************************************************/ +extern tGATT_STATUS GATTS_StartService (tGATT_IF gatt_if, UINT16 service_handle, + tGATT_TRANSPORT sup_transport); + + +/******************************************************************************* +** +** Function GATTS_StopService +** +** Description This function is called to stop a service +** +** Parameter service_handle : this is the start handle of a service +** +** Returns None. +** +*******************************************************************************/ +extern void GATTS_StopService (UINT16 service_handle); + + +/******************************************************************************* +** +** Function GATTs_HandleValueIndication +** +** Description This function sends a handle value indication to a client. +** +** Parameter conn_id: connection identifier. +** attr_handle: Attribute handle of this handle value indication. +** val_len: Length of the indicated attribute value. +** p_val: Pointer to the indicated attribute value data. +** +** Returns GATT_SUCCESS if sucessfully sent or queued; otherwise error code. +** +*******************************************************************************/ +extern tGATT_STATUS GATTS_HandleValueIndication (UINT16 conn_id, + UINT16 attr_handle, + UINT16 val_len, UINT8 *p_val); + +/******************************************************************************* +** +** Function GATTS_HandleValueNotification +** +** Description This function sends a handle value notification to a client. +** +** Parameter conn_id: connection identifier. +** attr_handle: Attribute handle of this handle value indication. +** val_len: Length of the indicated attribute value. +** p_val: Pointer to the indicated attribute value data. +** +** Returns GATT_SUCCESS if sucessfully sent; otherwise error code. +** +*******************************************************************************/ +extern tGATT_STATUS GATTS_HandleValueNotification (UINT16 conn_id, UINT16 attr_handle, + UINT16 val_len, UINT8 *p_val); + + +/******************************************************************************* +** +** Function GATTS_SendRsp +** +** Description This function sends the server response to client. +** +** Parameter conn_id: connection identifier. +** trans_id: transaction id +** status: response status +** p_msg: pointer to message parameters structure. +** +** Returns GATT_SUCCESS if sucessfully sent; otherwise error code. +** +*******************************************************************************/ +extern tGATT_STATUS GATTS_SendRsp (UINT16 conn_id, UINT32 trans_id, + tGATT_STATUS status, tGATTS_RSP *p_msg); + + +/*******************************************************************************/ +/* GATT Profile Client Functions */ +/*******************************************************************************/ + +/******************************************************************************* +** +** Function GATTC_ConfigureMTU +** +** Description This function is called to configure the ATT MTU size for +** a connection on an LE transport. +** +** Parameters conn_id: connection identifier. +** mtu - attribute MTU size.. +** +** Returns GATT_SUCCESS if command started successfully. +** +*******************************************************************************/ +extern tGATT_STATUS GATTC_ConfigureMTU (UINT16 conn_id, UINT16 mtu); + +/******************************************************************************* +** +** Function GATTC_Discover +** +** Description This function is called to do a discovery procedure on ATT server. +** +** Parameters conn_id: connection identifier. +** disc_type:discovery type. +** p_param: parameters of discovery requirement. +** +** Returns GATT_SUCCESS if command received/sent successfully. +** +*******************************************************************************/ +extern tGATT_STATUS GATTC_Discover (UINT16 conn_id, + tGATT_DISC_TYPE disc_type, + tGATT_DISC_PARAM *p_param ); +/******************************************************************************* +** +** Function GATTC_Read +** +** Description This function is called to read the value of an attribute from +** the server. +** +** Parameters conn_id: connection identifier. +** type - attribute read type. +** p_read - read operation parameters. +** +** Returns GATT_SUCCESS if command started successfully. +** +*******************************************************************************/ +extern tGATT_STATUS GATTC_Read (UINT16 conn_id, tGATT_READ_TYPE type, + tGATT_READ_PARAM *p_read); + +/******************************************************************************* +** +** Function GATTC_Write +** +** Description This function is called to read the value of an attribute from +** the server. +** +** Parameters conn_id: connection identifier. +** type - attribute write type. +** p_write - write operation parameters. +** +** Returns GATT_SUCCESS if command started successfully. +** +*******************************************************************************/ +extern tGATT_STATUS GATTC_Write (UINT16 conn_id, tGATT_WRITE_TYPE type, + tGATT_VALUE *p_write); + + +/******************************************************************************* +** +** Function GATTC_ExecuteWrite +** +** Description This function is called to send an Execute write request to +** the server. +** +** Parameters conn_id: connection identifier. +** is_execute - to execute or cancel the prepare write requet(s) +** +** Returns GATT_SUCCESS if command started successfully. +** +*******************************************************************************/ +extern tGATT_STATUS GATTC_ExecuteWrite (UINT16 conn_id, BOOLEAN is_execute); + +/******************************************************************************* +** +** Function GATTC_SendHandleValueConfirm +** +** Description This function is called to send a handle value confirmation +** as response to a handle value notification from server. +** +** Parameters conn_id: connection identifier. +** handle: the handle of the attribute confirmation. +** +** Returns GATT_SUCCESS if command started successfully. +** +*******************************************************************************/ +extern tGATT_STATUS GATTC_SendHandleValueConfirm (UINT16 conn_id, UINT16 handle); + + +/******************************************************************************* +** +** Function GATT_SetIdleTimeout +** +** Description This function (common to both client and server) sets the idle +** timeout for a tansport connection +** +** Parameter bd_addr: target device bd address. +** idle_tout: timeout value in seconds. +** transport: trasnport option. +** +** Returns void +** +*******************************************************************************/ +extern void GATT_SetIdleTimeout (BD_ADDR bd_addr, UINT16 idle_tout, + tGATT_TRANSPORT transport); + + +/******************************************************************************* +** +** Function GATT_Register +** +** Description This function is called to register an application +** with GATT +** +** Parameter p_app_uuid128: Application UUID +** p_cb_info: callback functions. +** +** Returns 0 for error, otherwise the index of the client registered with GATT +** +*******************************************************************************/ +extern tGATT_IF GATT_Register (tBT_UUID *p_app_uuid128, tGATT_CBACK *p_cb_info); + +/******************************************************************************* +** +** Function GATT_Deregister +** +** Description This function deregistered the application from GATT. +** +** Parameters gatt_if: applicaiton interface. +** +** Returns None. +** +*******************************************************************************/ +extern void GATT_Deregister (tGATT_IF gatt_if); + +/******************************************************************************* +** +** Function GATT_StartIf +** +** Description This function is called after registration to start receiving +** callbacks for registered interface. Function may call back +** with connection status and queued notifications +** +** Parameter gatt_if: applicaiton interface. +** +** Returns None +** +*******************************************************************************/ +extern void GATT_StartIf (tGATT_IF gatt_if); + +/******************************************************************************* +** +** Function GATT_Connect +** +** Description This function initiate a connecttion to a remote device on GATT +** channel. +** +** Parameters gatt_if: applicaiton interface +** bd_addr: peer device address. +** is_direct: is a direct conenection or a background auto connection +** transport : Physical transport for GATT connection (BR/EDR or LE) +** +** Returns TRUE if connection started; FALSE if connection start failure. +** +*******************************************************************************/ +extern BOOLEAN GATT_Connect (tGATT_IF gatt_if, BD_ADDR bd_addr, + BOOLEAN is_direct, tBT_TRANSPORT transport); + + +/******************************************************************************* +** +** Function GATT_CancelConnect +** +** Description This function terminate the connection initaition to a remote +** device on GATT channel. +** +** Parameters gatt_if: client interface. If 0 used as unconditionally disconnect, +** typically used for direct connection cancellation. +** bd_addr: peer device address. +** is_direct: is a direct conenection or a background auto connection +** +** Returns TRUE if connection started; FALSE if connection start failure. +** +*******************************************************************************/ +extern BOOLEAN GATT_CancelConnect (tGATT_IF gatt_if, BD_ADDR bd_addr, + BOOLEAN is_direct); + +/******************************************************************************* +** +** Function GATT_Disconnect +** +** Description This function disconnect the GATT channel for this registered +** application. +** +** Parameters conn_id: connection identifier. +** +** Returns GATT_SUCCESS if disconnected. +** +*******************************************************************************/ +extern tGATT_STATUS GATT_Disconnect (UINT16 conn_id); + + + +/******************************************************************************* +** +** Function GATT_GetConnectionInfor +** +** Description This function use conn_id to find its associated BD address and applciation +** interface +** +** Parameters conn_id: connection id (input) +** p_gatt_if: applicaiton interface (output) +** bd_addr: peer device address. (output) +** transport : physical transport of the GATT connection (BR/EDR or LE) +** +** Returns TRUE the ligical link information is found for conn_id +** +*******************************************************************************/ +extern BOOLEAN GATT_GetConnectionInfor(UINT16 conn_id, tGATT_IF *p_gatt_if, + BD_ADDR bd_addr, tBT_TRANSPORT *p_transport); + + +/******************************************************************************* +** +** Function GATT_GetConnIdIfConnected +** +** Description This function find the conn_id if the logical link for BD address +** and applciation interface is connected +** +** Parameters gatt_if: applicaiton interface (input) +** bd_addr: peer device address. (input) +** p_conn_id: connection id (output) +** transport : physical transport of the GATT connection (BR/EDR or LE) +** +** Returns TRUE the ligical link is connected +** +*******************************************************************************/ +extern BOOLEAN GATT_GetConnIdIfConnected(tGATT_IF gatt_if, BD_ADDR bd_addr, + UINT16 *p_conn_id, tBT_TRANSPORT transport); + + +/******************************************************************************* +** +** Function GATT_Listen +** +** Description This function start or stop LE advertisement and listen for +** connection. +** +** Parameters gatt_if: applicaiton interface +** p_bd_addr: listen for specific address connection, or NULL for +** listen to all device connection. +** start: is a direct conenection or a background auto connection +** +** Returns TRUE if advertisement is started; FALSE if adv start failure. +** +*******************************************************************************/ +extern BOOLEAN GATT_Listen (tGATT_IF gatt_if, BOOLEAN start, BD_ADDR_PTR bd_addr); + +/******************************************************************************* +** +** Function GATT_ConfigServiceChangeCCC +** +** Description Configure service change indication on remote device +** +** Returns None. +** +*******************************************************************************/ +extern void GATT_ConfigServiceChangeCCC (BD_ADDR remote_bda, BOOLEAN enable, + tBT_TRANSPORT transport); + +#ifdef __cplusplus + +} +#endif + +#endif /* GATT_API_H */ diff --git a/components/bt/bluedroid/stack/include/gatt_int.h b/components/bt/bluedroid/stack/include/gatt_int.h new file mode 100755 index 0000000000..a1fbb9d022 --- /dev/null +++ b/components/bt/bluedroid/stack/include/gatt_int.h @@ -0,0 +1,710 @@ +/****************************************************************************** + * + * Copyright (C) 1999-2012 Broadcom Corporation + * + * 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. + * + ******************************************************************************/ + +#ifndef GATT_INT_H +#define GATT_INT_H + +#include "bt_target.h" + + +#include "bt_trace.h" +#include "gatt_api.h" +#include "btm_ble_api.h" +#include "btu.h" + +#include + + +#define GATT_CREATE_CONN_ID(tcb_idx, gatt_if) ((UINT16) ((((UINT8)(tcb_idx) ) << 8) | ((UINT8) (gatt_if)))) +#define GATT_GET_TCB_IDX(conn_id) ((UINT8) (((UINT16) (conn_id)) >> 8)) +#define GATT_GET_GATT_IF(conn_id) ((tGATT_IF)((UINT8) (conn_id))) + +#define GATT_GET_SR_REG_PTR(index) (&gatt_cb.sr_reg[(UINT8) (index)]); +#define GATT_TRANS_ID_MAX 0x0fffffff /* 4 MSB is reserved */ + +/* security action for GATT write and read request */ +#define GATT_SEC_NONE 0 +#define GATT_SEC_OK 1 +#define GATT_SEC_SIGN_DATA 2 /* compute the signature for the write cmd */ +#define GATT_SEC_ENCRYPT 3 /* encrypt the link with current key */ +#define GATT_SEC_ENCRYPT_NO_MITM 4 /* unauthenticated encryption or better */ +#define GATT_SEC_ENCRYPT_MITM 5 /* authenticated encryption */ +#define GATT_SEC_ENC_PENDING 6 /* wait for link encryption pending */ +typedef UINT8 tGATT_SEC_ACTION; + + +#define GATT_ATTR_OP_SPT_MTU (0x00000001 << 0) +#define GATT_ATTR_OP_SPT_FIND_INFO (0x00000001 << 1) +#define GATT_ATTR_OP_SPT_FIND_BY_TYPE (0x00000001 << 2) +#define GATT_ATTR_OP_SPT_READ_BY_TYPE (0x00000001 << 3) +#define GATT_ATTR_OP_SPT_READ (0x00000001 << 4) +#define GATT_ATTR_OP_SPT_MULT_READ (0x00000001 << 5) +#define GATT_ATTR_OP_SPT_READ_BLOB (0x00000001 << 6) +#define GATT_ATTR_OP_SPT_READ_BY_GRP_TYPE (0x00000001 << 7) +#define GATT_ATTR_OP_SPT_WRITE (0x00000001 << 8) +#define GATT_ATTR_OP_SPT_WRITE_CMD (0x00000001 << 9) +#define GATT_ATTR_OP_SPT_PREP_WRITE (0x00000001 << 10) +#define GATT_ATTR_OP_SPT_EXE_WRITE (0x00000001 << 11) +#define GATT_ATTR_OP_SPT_HDL_VALUE_CONF (0x00000001 << 12) +#define GATT_ATTR_OP_SP_SIGN_WRITE (0x00000001 << 13) + +#define GATT_INDEX_INVALID 0xff + +#define GATT_PENDING_REQ_NONE 0 + + +#define GATT_WRITE_CMD_MASK 0xc0 /*0x1100-0000*/ +#define GATT_AUTH_SIGN_MASK 0x80 /*0x1000-0000*/ +#define GATT_AUTH_SIGN_LEN 12 + +#define GATT_HDR_SIZE 3 /* 1B opcode + 2B handle */ + +/* wait for ATT cmd response timeout value */ +#define GATT_WAIT_FOR_RSP_TOUT 30 +#define GATT_WAIT_FOR_DISC_RSP_TOUT 5 +#define GATT_REQ_RETRY_LIMIT 2 + +/* characteristic descriptor type */ +#define GATT_DESCR_EXT_DSCPTOR 1 /* Characteristic Extended Properties */ +#define GATT_DESCR_USER_DSCPTOR 2 /* Characteristic User Description */ +#define GATT_DESCR_CLT_CONFIG 3 /* Client Characteristic Configuration */ +#define GATT_DESCR_SVR_CONFIG 4 /* Server Characteristic Configuration */ +#define GATT_DESCR_PRES_FORMAT 5 /* Characteristic Presentation Format */ +#define GATT_DESCR_AGGR_FORMAT 6 /* Characteristic Aggregate Format */ +#define GATT_DESCR_VALID_RANGE 7 /* Characteristic Valid Range */ +#define GATT_DESCR_UNKNOWN 0xff + +#define GATT_SEC_FLAG_LKEY_UNAUTHED BTM_SEC_FLAG_LKEY_KNOWN +#define GATT_SEC_FLAG_LKEY_AUTHED BTM_SEC_FLAG_LKEY_AUTHED +#define GATT_SEC_FLAG_ENCRYPTED BTM_SEC_FLAG_ENCRYPTED +typedef UINT8 tGATT_SEC_FLAG; + +/* Find Information Response Type +*/ +#define GATT_INFO_TYPE_PAIR_16 0x01 +#define GATT_INFO_TYPE_PAIR_128 0x02 + +/* GATT client FIND_TYPE_VALUE_Request data */ +typedef struct +{ + tBT_UUID uuid; /* type of attribute to be found */ + UINT16 s_handle; /* starting handle */ + UINT16 e_handle; /* ending handle */ + UINT16 value_len; /* length of the attribute value */ + UINT8 value[GATT_MAX_MTU_SIZE]; /* pointer to the attribute value to be found */ +} tGATT_FIND_TYPE_VALUE; + +/* client request message to ATT protocol +*/ +typedef union +{ + tGATT_READ_BY_TYPE browse; /* read by type request */ + tGATT_FIND_TYPE_VALUE find_type_value;/* find by type value */ + tGATT_READ_MULTI read_multi; /* read multiple request */ + tGATT_READ_PARTIAL read_blob; /* read blob */ + tGATT_VALUE attr_value; /* write request */ + /* prepare write */ + /* write blob */ + UINT16 handle; /* read, handle value confirmation */ + UINT16 mtu; + tGATT_EXEC_FLAG exec_write; /* execute write */ +}tGATT_CL_MSG; + +/* error response strucutre */ +typedef struct +{ + UINT16 handle; + UINT8 cmd_code; + UINT8 reason; +}tGATT_ERROR; + +/* server response message to ATT protocol +*/ +typedef union +{ + /* data type member event */ + tGATT_VALUE attr_value; /* READ, HANDLE_VALUE_IND, PREPARE_WRITE */ + /* READ_BLOB, READ_BY_TYPE */ + tGATT_ERROR error; /* ERROR_RSP */ + UINT16 handle; /* WRITE, WRITE_BLOB */ + UINT16 mtu; /* exchange MTU request */ +} tGATT_SR_MSG; + +/* Characteristic declaration attribute value +*/ +typedef struct +{ + tGATT_CHAR_PROP property; + UINT16 char_val_handle; +} tGATT_CHAR_DECL; + +/* attribute value maintained in the server database +*/ +typedef union +{ + tBT_UUID uuid; /* service declaration */ + tGATT_CHAR_DECL char_decl; /* characteristic declaration */ + tGATT_INCL_SRVC incl_handle; /* included service */ + +} tGATT_ATTR_VALUE; + +/* Attribute UUID type +*/ +#define GATT_ATTR_UUID_TYPE_16 0 +#define GATT_ATTR_UUID_TYPE_128 1 +#define GATT_ATTR_UUID_TYPE_32 2 +typedef UINT8 tGATT_ATTR_UUID_TYPE; + +/* 16 bits UUID Attribute in server database +*/ +typedef struct +{ + void *p_next; /* pointer to the next attribute, + either tGATT_ATTR16 or tGATT_ATTR128 */ + tGATT_ATTR_VALUE *p_value; + tGATT_ATTR_UUID_TYPE uuid_type; + tGATT_PERM permission; + UINT16 handle; + UINT16 uuid; +} tGATT_ATTR16; + +/* 32 bits UUID Attribute in server database +*/ +typedef struct +{ + void *p_next; /* pointer to the next attribute, + either tGATT_ATTR16, tGATT_ATTR32 or tGATT_ATTR128 */ + tGATT_ATTR_VALUE *p_value; + tGATT_ATTR_UUID_TYPE uuid_type; + tGATT_PERM permission; + UINT16 handle; + UINT32 uuid; +} tGATT_ATTR32; + + +/* 128 bits UUID Attribute in server database +*/ +typedef struct +{ + void *p_next; /* pointer to the next attribute, + either tGATT_ATTR16 or tGATT_ATTR128 */ + tGATT_ATTR_VALUE *p_value; + tGATT_ATTR_UUID_TYPE uuid_type; + tGATT_PERM permission; + UINT16 handle; + UINT8 uuid[LEN_UUID_128]; +} tGATT_ATTR128; + +/* Service Database definition +*/ +typedef struct +{ + void *p_attr_list; /* pointer to the first attribute, + either tGATT_ATTR16 or tGATT_ATTR128 */ + UINT8 *p_free_mem; /* Pointer to free memory */ + BUFFER_Q svc_buffer; /* buffer queue used for service database */ + UINT32 mem_free; /* Memory still available */ + UINT16 end_handle; /* Last handle number */ + UINT16 next_handle; /* Next usable handle value */ +} tGATT_SVC_DB; + +/* Data Structure used for GATT server */ +/* A GATT registration record consists of a handle, and 1 or more attributes */ +/* A service registration information record consists of beginning and ending */ +/* attribute handle, service UUID and a set of GATT server callback. */ +typedef struct +{ + tGATT_SVC_DB *p_db; /* pointer to the service database */ + tBT_UUID app_uuid; /* applicatino UUID */ + UINT32 sdp_handle; /* primamry service SDP handle */ + UINT16 service_instance; /* service instance number */ + UINT16 type; /* service type UUID, primary or secondary */ + UINT16 s_hdl; /* service starting handle */ + UINT16 e_hdl; /* service ending handle */ + tGATT_IF gatt_if; /* this service is belong to which application */ + BOOLEAN in_use; +} tGATT_SR_REG; + +#define GATT_LISTEN_TO_ALL 0xff +#define GATT_LISTEN_TO_NONE 0 + +/* Data Structure used for GATT server */ +/* An GATT registration record consists of a handle, and 1 or more attributes */ +/* A service registration information record consists of beginning and ending */ +/* attribute handle, service UUID and a set of GATT server callback. */ + +typedef struct +{ + tBT_UUID app_uuid128; + tGATT_CBACK app_cb; + tGATT_IF gatt_if; /* one based */ + BOOLEAN in_use; + UINT8 listening; /* if adv for all has been enabled */ +} tGATT_REG; + + + + +/* command queue for each connection */ +typedef struct +{ + BT_HDR *p_cmd; + UINT16 clcb_idx; + UINT8 op_code; + BOOLEAN to_send; +}tGATT_CMD_Q; + + +#if GATT_MAX_SR_PROFILES <= 8 +typedef UINT8 tGATT_APP_MASK; +#elif GATT_MAX_SR_PROFILES <= 16 +typedef UINT16 tGATT_APP_MASK; +#elif GATT_MAX_SR_PROFILES <= 32 +typedef UINT32 tGATT_APP_MASK; +#endif + +/* command details for each connection */ +typedef struct +{ + BT_HDR *p_rsp_msg; + UINT32 trans_id; + tGATT_READ_MULTI multi_req; + BUFFER_Q multi_rsp_q; + UINT16 handle; + UINT8 op_code; + UINT8 status; + UINT8 cback_cnt[GATT_MAX_APPS]; +} tGATT_SR_CMD; + +#define GATT_CH_CLOSE 0 +#define GATT_CH_CLOSING 1 +#define GATT_CH_CONN 2 +#define GATT_CH_CFG 3 +#define GATT_CH_OPEN 4 + +typedef UINT8 tGATT_CH_STATE; + +#define GATT_GATT_START_HANDLE 1 +#define GATT_GAP_START_HANDLE 20 +#define GATT_APP_START_HANDLE 40 + +typedef struct hdl_cfg +{ + UINT16 gatt_start_hdl; + UINT16 gap_start_hdl; + UINT16 app_start_hdl; +}tGATT_HDL_CFG; + +typedef struct hdl_list_elem +{ + struct hdl_list_elem *p_next; + struct hdl_list_elem *p_prev; + tGATTS_HNDL_RANGE asgn_range; /* assigned handle range */ + tGATT_SVC_DB svc_db; + BOOLEAN in_use; +}tGATT_HDL_LIST_ELEM; + +typedef struct +{ + tGATT_HDL_LIST_ELEM *p_first; + tGATT_HDL_LIST_ELEM *p_last; + UINT16 count; +}tGATT_HDL_LIST_INFO; + + +typedef struct srv_list_elem +{ + struct srv_list_elem *p_next; + struct srv_list_elem *p_prev; + UINT16 s_hdl; + UINT8 i_sreg; + BOOLEAN in_use; + BOOLEAN is_primary; +}tGATT_SRV_LIST_ELEM; + + +typedef struct +{ + tGATT_SRV_LIST_ELEM *p_last_primary; + tGATT_SRV_LIST_ELEM *p_first; + tGATT_SRV_LIST_ELEM *p_last; + UINT16 count; +}tGATT_SRV_LIST_INFO; + +typedef struct +{ + BUFFER_Q pending_enc_clcb; /* pending encryption channel q */ + tGATT_SEC_ACTION sec_act; + BD_ADDR peer_bda; + tBT_TRANSPORT transport; + UINT32 trans_id; + + UINT16 att_lcid; /* L2CAP channel ID for ATT */ + UINT16 payload_size; + + tGATT_CH_STATE ch_state; + UINT8 ch_flags; + + tGATT_IF app_hold_link[GATT_MAX_APPS]; + + /* server needs */ + /* server response data */ + tGATT_SR_CMD sr_cmd; + UINT16 indicate_handle; + BUFFER_Q pending_ind_q; + + TIMER_LIST_ENT conf_timer_ent; /* peer confirm to indication timer */ + + UINT8 prep_cnt[GATT_MAX_APPS]; + UINT8 ind_count; + + tGATT_CMD_Q cl_cmd_q[GATT_CL_MAX_LCB]; + TIMER_LIST_ENT ind_ack_timer_ent; /* local app confirm to indication timer */ + UINT8 pending_cl_req; + UINT8 next_slot_inq; /* index of next available slot in queue */ + + BOOLEAN in_use; + UINT8 tcb_idx; +} tGATT_TCB; + + +/* logic channel */ +typedef struct +{ + UINT16 next_disc_start_hdl; /* starting handle for the next inc srvv discovery */ + tGATT_DISC_RES result; + BOOLEAN wait_for_read_rsp; +} tGATT_READ_INC_UUID128; +typedef struct +{ + tGATT_TCB *p_tcb; /* associated TCB of this CLCB */ + tGATT_REG *p_reg; /* owner of this CLCB */ + UINT8 sccb_idx; + UINT8 *p_attr_buf; /* attribute buffer for read multiple, prepare write */ + tBT_UUID uuid; + UINT16 conn_id; /* connection handle */ + UINT16 clcb_idx; + UINT16 s_handle; /* starting handle of the active request */ + UINT16 e_handle; /* ending handle of the active request */ + UINT16 counter; /* used as offset, attribute length, num of prepare write */ + UINT16 start_offset; + tGATT_AUTH_REQ auth_req; /* authentication requirement */ + UINT8 operation; /* one logic channel can have one operation active */ + UINT8 op_subtype; /* operation subtype */ + UINT8 status; /* operation status */ + BOOLEAN first_read_blob_after_read; + tGATT_READ_INC_UUID128 read_uuid128; + BOOLEAN in_use; + TIMER_LIST_ENT rsp_timer_ent; /* peer response timer */ + UINT8 retry_count; + +} tGATT_CLCB; + +typedef struct +{ + tGATT_CLCB *p_clcb; +}tGATT_PENDING_ENC_CLCB; + + +#define GATT_SIGN_WRITE 1 +#define GATT_VERIFY_SIGN_DATA 2 + +typedef struct +{ + BT_HDR hdr; + tGATT_CLCB *p_clcb; +}tGATT_SIGN_WRITE_OP; + +typedef struct +{ + BT_HDR hdr; + tGATT_TCB *p_tcb; + BT_HDR *p_data; + +}tGATT_VERIFY_SIGN_OP; + + +typedef struct +{ + UINT16 clcb_idx; + BOOLEAN in_use; +} tGATT_SCCB; + +typedef struct +{ + UINT16 handle; + UINT16 uuid; + UINT32 service_change; +}tGATT_SVC_CHG; + +typedef struct +{ + tGATT_IF gatt_if[GATT_MAX_APPS]; + tGATT_IF listen_gif[GATT_MAX_APPS]; + BD_ADDR remote_bda; + BOOLEAN in_use; +}tGATT_BG_CONN_DEV; + +#define GATT_SVC_CHANGED_CONNECTING 1 /* wait for connection */ +#define GATT_SVC_CHANGED_SERVICE 2 /* GATT service discovery */ +#define GATT_SVC_CHANGED_CHARACTERISTIC 3 /* service change char discovery */ +#define GATT_SVC_CHANGED_DESCRIPTOR 4 /* service change CCC discoery */ +#define GATT_SVC_CHANGED_CONFIGURE_CCCD 5 /* config CCC */ + +typedef struct +{ + UINT16 conn_id; + BOOLEAN in_use; + BOOLEAN connected; + BD_ADDR bda; + tBT_TRANSPORT transport; + + /* GATT service change CCC related variables */ + UINT8 ccc_stage; + UINT8 ccc_result; + UINT16 s_handle; + UINT16 e_handle; +}tGATT_PROFILE_CLCB; + +typedef struct +{ + tGATT_TCB tcb[GATT_MAX_PHY_CHANNEL]; + BUFFER_Q sign_op_queue; + + tGATT_SR_REG sr_reg[GATT_MAX_SR_PROFILES]; + UINT16 next_handle; /* next available handle */ + tGATT_SVC_CHG gattp_attr; /* GATT profile attribute service change */ + tGATT_IF gatt_if; + tGATT_HDL_LIST_INFO hdl_list_info; + tGATT_HDL_LIST_ELEM hdl_list[GATT_MAX_SR_PROFILES]; + tGATT_SRV_LIST_INFO srv_list_info; + tGATT_SRV_LIST_ELEM srv_list[GATT_MAX_SR_PROFILES]; + + BUFFER_Q srv_chg_clt_q; /* service change clients queue */ + BUFFER_Q pending_new_srv_start_q; /* pending new service start queue */ + tGATT_REG cl_rcb[GATT_MAX_APPS]; + tGATT_CLCB clcb[GATT_CL_MAX_LCB]; /* connection link control block*/ + tGATT_SCCB sccb[GATT_MAX_SCCB]; /* sign complete callback function GATT_MAX_SCCB <= GATT_CL_MAX_LCB */ + UINT8 trace_level; + UINT16 def_mtu_size; + +#if GATT_CONFORMANCE_TESTING == TRUE + BOOLEAN enable_err_rsp; + UINT8 req_op_code; + UINT8 err_status; + UINT16 handle; +#endif + + tGATT_PROFILE_CLCB profile_clcb[GATT_MAX_APPS]; + UINT16 handle_of_h_r; /* Handle of the handles reused characteristic value */ + + tGATT_APPL_INFO cb_info; + + + + tGATT_HDL_CFG hdl_cfg; + tGATT_BG_CONN_DEV bgconn_dev[GATT_MAX_BG_CONN_DEV]; + +} tGATT_CB; + + +#define GATT_SIZE_OF_SRV_CHG_HNDL_RANGE 4 + +#ifdef __cplusplus +extern "C" { +#endif + +/* Global GATT data */ +#if GATT_DYNAMIC_MEMORY == FALSE +extern tGATT_CB gatt_cb; +#else +extern tGATT_CB *gatt_cb_ptr; +#define gatt_cb (*gatt_cb_ptr) +#endif + +#if GATT_CONFORMANCE_TESTING == TRUE +extern void gatt_set_err_rsp(BOOLEAN enable, UINT8 req_op_code, UINT8 err_status); +#endif + +#ifdef __cplusplus +} +#endif + +/* internal functions */ +extern void gatt_init (void); +extern void gatt_free(void); + +/* from gatt_main.c */ +extern BOOLEAN gatt_disconnect (tGATT_TCB *p_tcb); +extern BOOLEAN gatt_act_connect (tGATT_REG *p_reg, BD_ADDR bd_addr, tBT_TRANSPORT transport); +extern BOOLEAN gatt_connect (BD_ADDR rem_bda, tGATT_TCB *p_tcb, tBT_TRANSPORT transport); +extern void gatt_data_process (tGATT_TCB *p_tcb, BT_HDR *p_buf); +extern void gatt_update_app_use_link_flag ( tGATT_IF gatt_if, tGATT_TCB *p_tcb, BOOLEAN is_add, BOOLEAN check_acl_link); + +extern void gatt_profile_db_init(void); +extern void gatt_set_ch_state(tGATT_TCB *p_tcb, tGATT_CH_STATE ch_state); +extern tGATT_CH_STATE gatt_get_ch_state(tGATT_TCB *p_tcb); +extern void gatt_init_srv_chg(void); +extern void gatt_proc_srv_chg (void); +extern void gatt_send_srv_chg_ind (BD_ADDR peer_bda); +extern void gatt_chk_srv_chg(tGATTS_SRV_CHG *p_srv_chg_clt); +extern void gatt_add_a_bonded_dev_for_srv_chg (BD_ADDR bda); + +/* from gatt_attr.c */ +extern UINT16 gatt_profile_find_conn_id_by_bd_addr(BD_ADDR bda); + + +/* Functions provided by att_protocol.c */ +extern tGATT_STATUS attp_send_cl_msg (tGATT_TCB *p_tcb, UINT16 clcb_idx, UINT8 op_code, tGATT_CL_MSG *p_msg); +extern BT_HDR *attp_build_sr_msg(tGATT_TCB *p_tcb, UINT8 op_code, tGATT_SR_MSG *p_msg); +extern tGATT_STATUS attp_send_sr_msg (tGATT_TCB *p_tcb, BT_HDR *p_msg); +extern tGATT_STATUS attp_send_msg_to_l2cap(tGATT_TCB *p_tcb, BT_HDR *p_toL2CAP); + +/* utility functions */ +extern UINT8 * gatt_dbg_op_name(UINT8 op_code); +extern UINT32 gatt_add_sdp_record (tBT_UUID *p_uuid, UINT16 start_hdl, UINT16 end_hdl); +extern BOOLEAN gatt_parse_uuid_from_cmd(tBT_UUID *p_uuid, UINT16 len, UINT8 **p_data); +extern UINT8 gatt_build_uuid_to_stream(UINT8 **p_dst, tBT_UUID uuid); +extern BOOLEAN gatt_uuid_compare(tBT_UUID src, tBT_UUID tar); +extern void gatt_convert_uuid32_to_uuid128(UINT8 uuid_128[LEN_UUID_128], UINT32 uuid_32); +extern void gatt_sr_get_sec_info(BD_ADDR rem_bda, tBT_TRANSPORT transport, UINT8 *p_sec_flag, UINT8 *p_key_size); +extern void gatt_start_rsp_timer(UINT16 clcb_idx); +extern void gatt_start_conf_timer(tGATT_TCB *p_tcb); +extern void gatt_rsp_timeout(TIMER_LIST_ENT *p_tle); +extern void gatt_ind_ack_timeout(TIMER_LIST_ENT *p_tle); +extern void gatt_start_ind_ack_timer(tGATT_TCB *p_tcb); +extern tGATT_STATUS gatt_send_error_rsp(tGATT_TCB *p_tcb, UINT8 err_code, UINT8 op_code, UINT16 handle, BOOLEAN deq); +extern void gatt_dbg_display_uuid(tBT_UUID bt_uuid); +extern tGATT_PENDING_ENC_CLCB* gatt_add_pending_enc_channel_clcb(tGATT_TCB *p_tcb, tGATT_CLCB *p_clcb ); + +extern tGATTS_PENDING_NEW_SRV_START *gatt_sr_is_new_srv_chg(tBT_UUID *p_app_uuid128, tBT_UUID *p_svc_uuid, UINT16 svc_inst); + +extern BOOLEAN gatt_is_srv_chg_ind_pending (tGATT_TCB *p_tcb); +extern tGATTS_SRV_CHG *gatt_is_bda_in_the_srv_chg_clt_list (BD_ADDR bda); + +extern BOOLEAN gatt_find_the_connected_bda(UINT8 start_idx, BD_ADDR bda, UINT8 *p_found_idx, tBT_TRANSPORT *p_transport); +extern void gatt_set_srv_chg(void); +extern void gatt_delete_dev_from_srv_chg_clt_list(BD_ADDR bd_addr); +extern tGATT_VALUE *gatt_add_pending_ind(tGATT_TCB *p_tcb, tGATT_VALUE *p_ind); +extern tGATTS_PENDING_NEW_SRV_START *gatt_add_pending_new_srv_start( tGATTS_HNDL_RANGE *p_new_srv_start); +extern void gatt_free_srvc_db_buffer_app_id(tBT_UUID *p_app_id); +extern BOOLEAN gatt_update_listen_mode(void); +extern BOOLEAN gatt_cl_send_next_cmd_inq(tGATT_TCB *p_tcb); + +/* reserved handle list */ +extern tGATT_HDL_LIST_ELEM *gatt_find_hdl_buffer_by_app_id (tBT_UUID *p_app_uuid128, tBT_UUID *p_svc_uuid, UINT16 svc_inst); +extern tGATT_HDL_LIST_ELEM *gatt_find_hdl_buffer_by_handle(UINT16 handle); +extern tGATT_HDL_LIST_ELEM *gatt_alloc_hdl_buffer(void); +extern void gatt_free_hdl_buffer(tGATT_HDL_LIST_ELEM *p); +extern BOOLEAN gatt_is_last_attribute(tGATT_SRV_LIST_INFO *p_list, tGATT_SRV_LIST_ELEM *p_start, tBT_UUID value); +extern void gatt_update_last_pri_srv_info(tGATT_SRV_LIST_INFO *p_list); +extern BOOLEAN gatt_add_a_srv_to_list(tGATT_SRV_LIST_INFO *p_list, tGATT_SRV_LIST_ELEM *p_new); +extern BOOLEAN gatt_remove_a_srv_from_list(tGATT_SRV_LIST_INFO *p_list, tGATT_SRV_LIST_ELEM *p_remove); +extern BOOLEAN gatt_add_an_item_to_list(tGATT_HDL_LIST_INFO *p_list, tGATT_HDL_LIST_ELEM *p_new); +extern BOOLEAN gatt_remove_an_item_from_list(tGATT_HDL_LIST_INFO *p_list, tGATT_HDL_LIST_ELEM *p_remove); +extern tGATTS_SRV_CHG *gatt_add_srv_chg_clt(tGATTS_SRV_CHG *p_srv_chg); + +/* for background connection */ +extern BOOLEAN gatt_update_auto_connect_dev (tGATT_IF gatt_if, BOOLEAN add, BD_ADDR bd_addr, BOOLEAN is_initiator); +extern BOOLEAN gatt_is_bg_dev_for_app(tGATT_BG_CONN_DEV *p_dev, tGATT_IF gatt_if); +extern BOOLEAN gatt_remove_bg_dev_for_app(tGATT_IF gatt_if, BD_ADDR bd_addr); +extern UINT8 gatt_get_num_apps_for_bg_dev(BD_ADDR bd_addr); +extern BOOLEAN gatt_find_app_for_bg_dev(BD_ADDR bd_addr, tGATT_IF *p_gatt_if); +extern tGATT_BG_CONN_DEV * gatt_find_bg_dev(BD_ADDR remote_bda); +extern void gatt_deregister_bgdev_list(tGATT_IF gatt_if); +extern void gatt_reset_bgdev_list(void); + +/* server function */ +extern UINT8 gatt_sr_find_i_rcb_by_handle(UINT16 handle); +extern UINT8 gatt_sr_find_i_rcb_by_app_id(tBT_UUID *p_app_uuid128, tBT_UUID *p_svc_uuid, UINT16 svc_inst); +extern UINT8 gatt_sr_alloc_rcb(tGATT_HDL_LIST_ELEM *p_list); +extern tGATT_STATUS gatt_sr_process_app_rsp (tGATT_TCB *p_tcb, tGATT_IF gatt_if, UINT32 trans_id, UINT8 op_code, tGATT_STATUS status, tGATTS_RSP *p_msg); +extern void gatt_server_handle_client_req (tGATT_TCB *p_tcb, UINT8 op_code, + UINT16 len, UINT8 *p_data); +extern void gatt_sr_send_req_callback(UINT16 conn_id, UINT32 trans_id, + UINT8 op_code, tGATTS_DATA *p_req_data); +extern UINT32 gatt_sr_enqueue_cmd (tGATT_TCB *p_tcb, UINT8 op_code, UINT16 handle); +extern BOOLEAN gatt_cancel_open(tGATT_IF gatt_if, BD_ADDR bda); + +/* */ + +extern tGATT_REG *gatt_get_regcb (tGATT_IF gatt_if); +extern BOOLEAN gatt_is_clcb_allocated (UINT16 conn_id); +extern tGATT_CLCB *gatt_clcb_alloc (UINT16 conn_id); +extern void gatt_clcb_dealloc (tGATT_CLCB *p_clcb); + +extern void gatt_sr_copy_prep_cnt_to_cback_cnt(tGATT_TCB *p_tcb ); +extern BOOLEAN gatt_sr_is_cback_cnt_zero(tGATT_TCB *p_tcb ); +extern BOOLEAN gatt_sr_is_prep_cnt_zero(tGATT_TCB *p_tcb ); +extern void gatt_sr_reset_cback_cnt(tGATT_TCB *p_tcb ); +extern void gatt_sr_reset_prep_cnt(tGATT_TCB *p_tcb ); +extern void gatt_sr_update_cback_cnt(tGATT_TCB *p_tcb, tGATT_IF gatt_if, BOOLEAN is_inc, BOOLEAN is_reset_first); +extern void gatt_sr_update_prep_cnt(tGATT_TCB *p_tcb, tGATT_IF gatt_if, BOOLEAN is_inc, BOOLEAN is_reset_first); + +extern BOOLEAN gatt_find_app_hold_link(tGATT_TCB *p_tcb, UINT8 start_idx, UINT8 *p_found_idx, tGATT_IF *p_gatt_if); +extern UINT8 gatt_num_apps_hold_link(tGATT_TCB *p_tcb); +extern UINT8 gatt_num_clcb_by_bd_addr(BD_ADDR bda); +extern tGATT_TCB * gatt_find_tcb_by_cid(UINT16 lcid); +extern tGATT_TCB * gatt_allocate_tcb_by_bdaddr(BD_ADDR bda, tBT_TRANSPORT transport); +extern tGATT_TCB * gatt_get_tcb_by_idx(UINT8 tcb_idx); +extern tGATT_TCB * gatt_find_tcb_by_addr(BD_ADDR bda, tBT_TRANSPORT transport); +extern BOOLEAN gatt_send_ble_burst_data (BD_ADDR remote_bda, BT_HDR *p_buf); + +/* GATT client functions */ +extern void gatt_dequeue_sr_cmd (tGATT_TCB *p_tcb); +extern UINT8 gatt_send_write_msg(tGATT_TCB *p_tcb, UINT16 clcb_idx, UINT8 op_code, UINT16 handle, + UINT16 len, UINT16 offset, UINT8 *p_data); +extern void gatt_cleanup_upon_disc(BD_ADDR bda, UINT16 reason, tBT_TRANSPORT transport); +extern void gatt_end_operation(tGATT_CLCB *p_clcb, tGATT_STATUS status, void *p_data); + +extern void gatt_act_discovery(tGATT_CLCB *p_clcb); +extern void gatt_act_read(tGATT_CLCB *p_clcb, UINT16 offset); +extern void gatt_act_write(tGATT_CLCB *p_clcb, UINT8 sec_act); +extern UINT8 gatt_act_send_browse(tGATT_TCB *p_tcb, UINT16 index, UINT8 op, UINT16 s_handle, UINT16 e_handle, + tBT_UUID uuid); +extern tGATT_CLCB *gatt_cmd_dequeue(tGATT_TCB *p_tcb, UINT8 *p_opcode); +extern BOOLEAN gatt_cmd_enq(tGATT_TCB *p_tcb, UINT16 clcb_idx, BOOLEAN to_send, UINT8 op_code, BT_HDR *p_buf); +extern void gatt_client_handle_server_rsp (tGATT_TCB *p_tcb, UINT8 op_code, + UINT16 len, UINT8 *p_data); +extern void gatt_send_queue_write_cancel (tGATT_TCB *p_tcb, tGATT_CLCB *p_clcb, tGATT_EXEC_FLAG flag); + +/* gatt_auth.c */ +extern BOOLEAN gatt_security_check_start(tGATT_CLCB *p_clcb); +extern void gatt_verify_signature(tGATT_TCB *p_tcb, BT_HDR *p_buf); +extern tGATT_SEC_ACTION gatt_determine_sec_act(tGATT_CLCB *p_clcb ); +extern tGATT_STATUS gatt_get_link_encrypt_status(tGATT_TCB *p_tcb); +extern tGATT_SEC_ACTION gatt_get_sec_act(tGATT_TCB *p_tcb); +extern void gatt_set_sec_act(tGATT_TCB *p_tcb, tGATT_SEC_ACTION sec_act); + +/* gatt_db.c */ +extern BOOLEAN gatts_init_service_db (tGATT_SVC_DB *p_db, tBT_UUID *p_service, BOOLEAN is_pri, UINT16 s_hdl, UINT16 num_handle); +extern UINT16 gatts_add_included_service (tGATT_SVC_DB *p_db, UINT16 s_handle, UINT16 e_handle, tBT_UUID service); +extern UINT16 gatts_add_characteristic (tGATT_SVC_DB *p_db, tGATT_PERM perm, tGATT_CHAR_PROP property, tBT_UUID *p_char_uuid); +extern UINT16 gatts_add_char_descr (tGATT_SVC_DB *p_db, tGATT_PERM perm, tBT_UUID *p_dscp_uuid); +extern tGATT_STATUS gatts_db_read_attr_value_by_type (tGATT_TCB *p_tcb, tGATT_SVC_DB *p_db, UINT8 op_code, BT_HDR *p_rsp, UINT16 s_handle, + UINT16 e_handle, tBT_UUID type, UINT16 *p_len, tGATT_SEC_FLAG sec_flag, UINT8 key_size,UINT32 trans_id, UINT16 *p_cur_handle); +extern tGATT_STATUS gatts_read_attr_value_by_handle(tGATT_TCB *p_tcb,tGATT_SVC_DB *p_db, UINT8 op_code, UINT16 handle, UINT16 offset, + UINT8 *p_value, UINT16 *p_len, UINT16 mtu,tGATT_SEC_FLAG sec_flag,UINT8 key_size,UINT32 trans_id); +extern tGATT_STATUS gatts_write_attr_perm_check (tGATT_SVC_DB *p_db, UINT8 op_code,UINT16 handle, UINT16 offset, UINT8 *p_data, + UINT16 len, tGATT_SEC_FLAG sec_flag, UINT8 key_size); +extern tGATT_STATUS gatts_read_attr_perm_check(tGATT_SVC_DB *p_db, BOOLEAN is_long, UINT16 handle, tGATT_SEC_FLAG sec_flag,UINT8 key_size); +extern void gatts_update_srv_list_elem(UINT8 i_sreg, UINT16 handle, BOOLEAN is_primary); +extern tBT_UUID * gatts_get_service_uuid (tGATT_SVC_DB *p_db); + +extern void gatt_reset_bgdev_list(void); +#endif diff --git a/components/bt/bluedroid/stack/include/gattdefs.h b/components/bt/bluedroid/stack/include/gattdefs.h new file mode 100755 index 0000000000..3edfa8b988 --- /dev/null +++ b/components/bt/bluedroid/stack/include/gattdefs.h @@ -0,0 +1,124 @@ +/****************************************************************************** + * + * Copyright (C) 1999-2012 Broadcom Corporation + * + * 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 internally used ATT definitions + * + ******************************************************************************/ + +#ifndef _GATTDEFS_H +#define _GATTDEFS_H + +#define GATT_ILLEGAL_UUID 0 + +/* GATT attribute types +*/ +#define GATT_UUID_PRI_SERVICE 0x2800 +#define GATT_UUID_SEC_SERVICE 0x2801 +#define GATT_UUID_INCLUDE_SERVICE 0x2802 +#define GATT_UUID_CHAR_DECLARE 0x2803 /* Characteristic Declaration*/ + +#define GATT_UUID_CHAR_EXT_PROP 0x2900 /* Characteristic Extended Properties */ +#define GATT_UUID_CHAR_DESCRIPTION 0x2901 /* Characteristic User Description*/ +#define GATT_UUID_CHAR_CLIENT_CONFIG 0x2902 /* Client Characteristic Configuration */ +#define GATT_UUID_CHAR_SRVR_CONFIG 0x2903 /* Server Characteristic Configuration */ +#define GATT_UUID_CHAR_PRESENT_FORMAT 0x2904 /* Characteristic Presentation Format*/ +#define GATT_UUID_CHAR_AGG_FORMAT 0x2905 /* Characteristic Aggregate Format*/ +#define GATT_UUID_CHAR_VALID_RANGE 0x2906 /* Characteristic Valid Range */ +#define GATT_UUID_EXT_RPT_REF_DESCR 0x2907 +#define GATT_UUID_RPT_REF_DESCR 0x2908 + + +/* GAP Profile Attributes +*/ +#define GATT_UUID_GAP_DEVICE_NAME 0x2A00 +#define GATT_UUID_GAP_ICON 0x2A01 +#define GATT_UUID_GAP_PREF_CONN_PARAM 0x2A04 +#define GATT_UUID_GAP_CENTRAL_ADDR_RESOL 0x2AA6 + +/* Attribute Profile Attribute UUID */ +#define GATT_UUID_GATT_SRV_CHGD 0x2A05 +/* Attribute Protocol Test */ + +/* Link Loss Service */ +#define GATT_UUID_ALERT_LEVEL 0x2A06 /* Alert Level */ +#define GATT_UUID_TX_POWER_LEVEL 0x2A07 /* TX power level */ + +/* Time Profile */ +/* Current Time Service */ +#define GATT_UUID_CURRENT_TIME 0x2A2B /* Current Time */ +#define GATT_UUID_LOCAL_TIME_INFO 0x2A0F /* Local time info */ +#define GATT_UUID_REF_TIME_INFO 0x2A14 /* reference time information */ + +/* NwA Profile */ +#define GATT_UUID_NW_STATUS 0x2A18 /* network availability status */ +#define GATT_UUID_NW_TRIGGER 0x2A1A /* Network availability trigger */ + +/* phone alert */ +#define GATT_UUID_ALERT_STATUS 0x2A3F /* alert status */ +#define GATT_UUID_RINGER_CP 0x2A40 /* ringer control point */ +#define GATT_UUID_RINGER_SETTING 0x2A41 /* ringer setting */ + +/* Glucose Service */ +#define GATT_UUID_GM_MEASUREMENT 0x2A18 +#define GATT_UUID_GM_CONTEXT 0x2A34 +#define GATT_UUID_GM_CONTROL_POINT 0x2A52 +#define GATT_UUID_GM_FEATURE 0x2A51 + +/* device infor characteristic */ +#define GATT_UUID_SYSTEM_ID 0x2A23 +#define GATT_UUID_MODEL_NUMBER_STR 0x2A24 +#define GATT_UUID_SERIAL_NUMBER_STR 0x2A25 +#define GATT_UUID_FW_VERSION_STR 0x2A26 +#define GATT_UUID_HW_VERSION_STR 0x2A27 +#define GATT_UUID_SW_VERSION_STR 0x2A28 +#define GATT_UUID_MANU_NAME 0x2A29 +#define GATT_UUID_IEEE_DATA 0x2A2A +#define GATT_UUID_PNP_ID 0x2A50 + +/* HID characteristics */ +#define GATT_UUID_HID_INFORMATION 0x2A4A +#define GATT_UUID_HID_REPORT_MAP 0x2A4B +#define GATT_UUID_HID_CONTROL_POINT 0x2A4C +#define GATT_UUID_HID_REPORT 0x2A4D +#define GATT_UUID_HID_PROTO_MODE 0x2A4E +#define GATT_UUID_HID_BT_KB_INPUT 0x2A22 +#define GATT_UUID_HID_BT_KB_OUTPUT 0x2A32 +#define GATT_UUID_HID_BT_MOUSE_INPUT 0x2A33 + +/* Battery Service char */ +#define GATT_UUID_BATTERY_LEVEL 0x2A19 + +#define GATT_UUID_SC_CONTROL_POINT 0x2A55 +#define GATT_UUID_SENSOR_LOCATION 0x2A5D + +/* RUNNERS SPEED AND CADENCE SERVICE */ +#define GATT_UUID_RSC_MEASUREMENT 0x2A53 +#define GATT_UUID_RSC_FEATURE 0x2A54 + +/* CYCLING SPEED AND CADENCE SERVICE */ +#define GATT_UUID_CSC_MEASUREMENT 0x2A5B +#define GATT_UUID_CSC_FEATURE 0x2A5C + + +/* Scan Parameter charatceristics */ +#define GATT_UUID_SCAN_INT_WINDOW 0x2A4F +#define GATT_UUID_SCAN_REFRESH 0x2A31 + +#endif diff --git a/components/bt/bluedroid/stack/include/hcidefs.h b/components/bt/bluedroid/stack/include/hcidefs.h new file mode 100755 index 0000000000..ff9f35cf20 --- /dev/null +++ b/components/bt/bluedroid/stack/include/hcidefs.h @@ -0,0 +1,2606 @@ +/****************************************************************************** + * + * Copyright (C) 1999-2014 Broadcom Corporation + * + * 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. + * + ******************************************************************************/ + +#ifndef HCIDEFS_H +#define HCIDEFS_H + +#include "bt_target.h" + +#include "bt_types.h" + +#define HCI_PROTO_VERSION 0x01 /* Version for BT spec 1.1 */ +#define HCI_PROTO_VERSION_1_2 0x02 /* Version for BT spec 1.2 */ +#define HCI_PROTO_VERSION_2_0 0x03 /* Version for BT spec 2.0 */ +#define HCI_PROTO_VERSION_2_1 0x04 /* Version for BT spec 2.1 [Lisbon] */ +#define HCI_PROTO_VERSION_3_0 0x05 /* Version for BT spec 3.0 */ +#define HCI_PROTO_VERSION_4_0 0x06 /* Version for BT spec 4.0 */ +#define HCI_PROTO_VERSION_4_1 0x07 /* Version for BT spec 4.1 */ +#define HCI_PROTO_VERSION_4_2 0x08 /* Version for BT spec 4.2 */ +#define HCI_PROTO_REVISION 0x000C /* Current implementation version */ +/* +** Definitions for HCI groups +*/ +#define HCI_GRP_LINK_CONTROL_CMDS (0x01 << 10) /* 0x0400 */ +#define HCI_GRP_LINK_POLICY_CMDS (0x02 << 10) /* 0x0800 */ +#define HCI_GRP_HOST_CONT_BASEBAND_CMDS (0x03 << 10) /* 0x0C00 */ +#define HCI_GRP_INFORMATIONAL_PARAMS (0x04 << 10) /* 0x1000 */ +#define HCI_GRP_STATUS_PARAMS (0x05 << 10) /* 0x1400 */ +#define HCI_GRP_TESTING_CMDS (0x06 << 10) /* 0x1800 */ + +#define HCI_GRP_VENDOR_SPECIFIC (0x3F << 10) /* 0xFC00 */ + +/* Group occupies high 6 bits of the HCI command rest is opcode itself */ +#define HCI_OGF(p) (UINT8)((0xFC00 & (p)) >> 10) +#define HCI_OCF(p) ( 0x3FF & (p)) + +/* +** Definitions for Link Control Commands +*/ +/* Following opcode is used only in command complete event for flow control */ +#define HCI_COMMAND_NONE 0x0000 + +/* Commands of HCI_GRP_LINK_CONTROL_CMDS group */ +#define HCI_INQUIRY (0x0001 | HCI_GRP_LINK_CONTROL_CMDS) +#define HCI_INQUIRY_CANCEL (0x0002 | HCI_GRP_LINK_CONTROL_CMDS) +#define HCI_PERIODIC_INQUIRY_MODE (0x0003 | HCI_GRP_LINK_CONTROL_CMDS) +#define HCI_EXIT_PERIODIC_INQUIRY_MODE (0x0004 | HCI_GRP_LINK_CONTROL_CMDS) +#define HCI_CREATE_CONNECTION (0x0005 | HCI_GRP_LINK_CONTROL_CMDS) +#define HCI_DISCONNECT (0x0006 | HCI_GRP_LINK_CONTROL_CMDS) +#define HCI_ADD_SCO_CONNECTION (0x0007 | HCI_GRP_LINK_CONTROL_CMDS) +#define HCI_CREATE_CONNECTION_CANCEL (0x0008 | HCI_GRP_LINK_CONTROL_CMDS) +#define HCI_ACCEPT_CONNECTION_REQUEST (0x0009 | HCI_GRP_LINK_CONTROL_CMDS) +#define HCI_REJECT_CONNECTION_REQUEST (0x000A | HCI_GRP_LINK_CONTROL_CMDS) +#define HCI_LINK_KEY_REQUEST_REPLY (0x000B | HCI_GRP_LINK_CONTROL_CMDS) +#define HCI_LINK_KEY_REQUEST_NEG_REPLY (0x000C | HCI_GRP_LINK_CONTROL_CMDS) +#define HCI_PIN_CODE_REQUEST_REPLY (0x000D | HCI_GRP_LINK_CONTROL_CMDS) +#define HCI_PIN_CODE_REQUEST_NEG_REPLY (0x000E | HCI_GRP_LINK_CONTROL_CMDS) +#define HCI_CHANGE_CONN_PACKET_TYPE (0x000F | HCI_GRP_LINK_CONTROL_CMDS) +#define HCI_AUTHENTICATION_REQUESTED (0x0011 | HCI_GRP_LINK_CONTROL_CMDS) +#define HCI_SET_CONN_ENCRYPTION (0x0013 | HCI_GRP_LINK_CONTROL_CMDS) +#define HCI_CHANGE_CONN_LINK_KEY (0x0015 | HCI_GRP_LINK_CONTROL_CMDS) +#define HCI_MASTER_LINK_KEY (0x0017 | HCI_GRP_LINK_CONTROL_CMDS) +#define HCI_RMT_NAME_REQUEST (0x0019 | HCI_GRP_LINK_CONTROL_CMDS) +#define HCI_RMT_NAME_REQUEST_CANCEL (0x001A | HCI_GRP_LINK_CONTROL_CMDS) +#define HCI_READ_RMT_FEATURES (0x001B | HCI_GRP_LINK_CONTROL_CMDS) +#define HCI_READ_RMT_EXT_FEATURES (0x001C | HCI_GRP_LINK_CONTROL_CMDS) +#define HCI_READ_RMT_VERSION_INFO (0x001D | HCI_GRP_LINK_CONTROL_CMDS) +#define HCI_READ_RMT_CLOCK_OFFSET (0x001F | HCI_GRP_LINK_CONTROL_CMDS) +#define HCI_READ_LMP_HANDLE (0x0020 | HCI_GRP_LINK_CONTROL_CMDS) +#define HCI_SETUP_ESCO_CONNECTION (0x0028 | HCI_GRP_LINK_CONTROL_CMDS) +#define HCI_ACCEPT_ESCO_CONNECTION (0x0029 | HCI_GRP_LINK_CONTROL_CMDS) +#define HCI_REJECT_ESCO_CONNECTION (0x002A | HCI_GRP_LINK_CONTROL_CMDS) +#define HCI_IO_CAPABILITY_REQUEST_REPLY (0x002B | HCI_GRP_LINK_CONTROL_CMDS) +#define HCI_USER_CONF_REQUEST_REPLY (0x002C | HCI_GRP_LINK_CONTROL_CMDS) +#define HCI_USER_CONF_VALUE_NEG_REPLY (0x002D | HCI_GRP_LINK_CONTROL_CMDS) +#define HCI_USER_PASSKEY_REQ_REPLY (0x002E | HCI_GRP_LINK_CONTROL_CMDS) +#define HCI_USER_PASSKEY_REQ_NEG_REPLY (0x002F | HCI_GRP_LINK_CONTROL_CMDS) +#define HCI_REM_OOB_DATA_REQ_REPLY (0x0030 | HCI_GRP_LINK_CONTROL_CMDS) +#define HCI_REM_OOB_DATA_REQ_NEG_REPLY (0x0033 | HCI_GRP_LINK_CONTROL_CMDS) +#define HCI_IO_CAP_REQ_NEG_REPLY (0x0034 | HCI_GRP_LINK_CONTROL_CMDS) + +/* AMP HCI */ +#define HCI_CREATE_PHYSICAL_LINK (0x0035 | HCI_GRP_LINK_CONTROL_CMDS) +#define HCI_ACCEPT_PHYSICAL_LINK (0x0036 | HCI_GRP_LINK_CONTROL_CMDS) +#define HCI_DISCONNECT_PHYSICAL_LINK (0x0037 | HCI_GRP_LINK_CONTROL_CMDS) +#define HCI_CREATE_LOGICAL_LINK (0x0038 | HCI_GRP_LINK_CONTROL_CMDS) +#define HCI_ACCEPT_LOGICAL_LINK (0x0039 | HCI_GRP_LINK_CONTROL_CMDS) +#define HCI_DISCONNECT_LOGICAL_LINK (0x003A | HCI_GRP_LINK_CONTROL_CMDS) +#define HCI_LOGICAL_LINK_CANCEL (0x003B | HCI_GRP_LINK_CONTROL_CMDS) +#define HCI_FLOW_SPEC_MODIFY (0x003C | HCI_GRP_LINK_CONTROL_CMDS) + +#define HCI_ENH_SETUP_ESCO_CONNECTION (0x003D | HCI_GRP_LINK_CONTROL_CMDS) +#define HCI_ENH_ACCEPT_ESCO_CONNECTION (0x003E | HCI_GRP_LINK_CONTROL_CMDS) + +/* ConnectionLess Broadcast */ +#define HCI_TRUNCATED_PAGE (0x003F | HCI_GRP_LINK_CONTROL_CMDS) +#define HCI_TRUNCATED_PAGE_CANCEL (0x0040 | HCI_GRP_LINK_CONTROL_CMDS) +#define HCI_SET_CLB (0x0041 | HCI_GRP_LINK_CONTROL_CMDS) +#define HCI_RECEIVE_CLB (0x0042 | HCI_GRP_LINK_CONTROL_CMDS) +#define HCI_START_SYNC_TRAIN (0x0043 | HCI_GRP_LINK_CONTROL_CMDS) +#define HCI_RECEIVE_SYNC_TRAIN (0x0044 | HCI_GRP_LINK_CONTROL_CMDS) + +#define HCI_LINK_CTRL_CMDS_FIRST HCI_INQUIRY +#define HCI_LINK_CTRL_CMDS_LAST HCI_RECEIVE_SYNC_TRAIN + +/* Commands of HCI_GRP_LINK_POLICY_CMDS */ +#define HCI_HOLD_MODE (0x0001 | HCI_GRP_LINK_POLICY_CMDS) +#define HCI_SNIFF_MODE (0x0003 | HCI_GRP_LINK_POLICY_CMDS) +#define HCI_EXIT_SNIFF_MODE (0x0004 | HCI_GRP_LINK_POLICY_CMDS) +#define HCI_PARK_MODE (0x0005 | HCI_GRP_LINK_POLICY_CMDS) +#define HCI_EXIT_PARK_MODE (0x0006 | HCI_GRP_LINK_POLICY_CMDS) +#define HCI_QOS_SETUP (0x0007 | HCI_GRP_LINK_POLICY_CMDS) +#define HCI_ROLE_DISCOVERY (0x0009 | HCI_GRP_LINK_POLICY_CMDS) +#define HCI_SWITCH_ROLE (0x000B | HCI_GRP_LINK_POLICY_CMDS) +#define HCI_READ_POLICY_SETTINGS (0x000C | HCI_GRP_LINK_POLICY_CMDS) +#define HCI_WRITE_POLICY_SETTINGS (0x000D | HCI_GRP_LINK_POLICY_CMDS) +#define HCI_READ_DEF_POLICY_SETTINGS (0x000E | HCI_GRP_LINK_POLICY_CMDS) +#define HCI_WRITE_DEF_POLICY_SETTINGS (0x000F | HCI_GRP_LINK_POLICY_CMDS) +#define HCI_FLOW_SPECIFICATION (0x0010 | HCI_GRP_LINK_POLICY_CMDS) +#define HCI_SNIFF_SUB_RATE (0x0011 | HCI_GRP_LINK_POLICY_CMDS) + +#define HCI_LINK_POLICY_CMDS_FIRST HCI_HOLD_MODE +#define HCI_LINK_POLICY_CMDS_LAST HCI_SNIFF_SUB_RATE + + +/* Commands of HCI_GRP_HOST_CONT_BASEBAND_CMDS */ +#define HCI_SET_EVENT_MASK (0x0001 | HCI_GRP_HOST_CONT_BASEBAND_CMDS) +#define HCI_RESET (0x0003 | HCI_GRP_HOST_CONT_BASEBAND_CMDS) +#define HCI_SET_EVENT_FILTER (0x0005 | HCI_GRP_HOST_CONT_BASEBAND_CMDS) +#define HCI_FLUSH (0x0008 | HCI_GRP_HOST_CONT_BASEBAND_CMDS) +#define HCI_READ_PIN_TYPE (0x0009 | HCI_GRP_HOST_CONT_BASEBAND_CMDS) +#define HCI_WRITE_PIN_TYPE (0x000A | HCI_GRP_HOST_CONT_BASEBAND_CMDS) +#define HCI_CREATE_NEW_UNIT_KEY (0x000B | HCI_GRP_HOST_CONT_BASEBAND_CMDS) +#define HCI_GET_MWS_TRANS_LAYER_CFG (0x000C | HCI_GRP_HOST_CONT_BASEBAND_CMDS) +#define HCI_READ_STORED_LINK_KEY (0x000D | HCI_GRP_HOST_CONT_BASEBAND_CMDS) +#define HCI_WRITE_STORED_LINK_KEY (0x0011 | HCI_GRP_HOST_CONT_BASEBAND_CMDS) +#define HCI_DELETE_STORED_LINK_KEY (0x0012 | HCI_GRP_HOST_CONT_BASEBAND_CMDS) +#define HCI_CHANGE_LOCAL_NAME (0x0013 | HCI_GRP_HOST_CONT_BASEBAND_CMDS) +#define HCI_READ_LOCAL_NAME (0x0014 | HCI_GRP_HOST_CONT_BASEBAND_CMDS) +#define HCI_READ_CONN_ACCEPT_TOUT (0x0015 | HCI_GRP_HOST_CONT_BASEBAND_CMDS) +#define HCI_WRITE_CONN_ACCEPT_TOUT (0x0016 | HCI_GRP_HOST_CONT_BASEBAND_CMDS) +#define HCI_READ_PAGE_TOUT (0x0017 | HCI_GRP_HOST_CONT_BASEBAND_CMDS) +#define HCI_WRITE_PAGE_TOUT (0x0018 | HCI_GRP_HOST_CONT_BASEBAND_CMDS) +#define HCI_READ_SCAN_ENABLE (0x0019 | HCI_GRP_HOST_CONT_BASEBAND_CMDS) +#define HCI_WRITE_SCAN_ENABLE (0x001A | HCI_GRP_HOST_CONT_BASEBAND_CMDS) +#define HCI_READ_PAGESCAN_CFG (0x001B | HCI_GRP_HOST_CONT_BASEBAND_CMDS) +#define HCI_WRITE_PAGESCAN_CFG (0x001C | HCI_GRP_HOST_CONT_BASEBAND_CMDS) +#define HCI_READ_INQUIRYSCAN_CFG (0x001D | HCI_GRP_HOST_CONT_BASEBAND_CMDS) +#define HCI_WRITE_INQUIRYSCAN_CFG (0x001E | HCI_GRP_HOST_CONT_BASEBAND_CMDS) +#define HCI_READ_AUTHENTICATION_ENABLE (0x001F | HCI_GRP_HOST_CONT_BASEBAND_CMDS) +#define HCI_WRITE_AUTHENTICATION_ENABLE (0x0020 | HCI_GRP_HOST_CONT_BASEBAND_CMDS) +#define HCI_READ_ENCRYPTION_MODE (0x0021 | HCI_GRP_HOST_CONT_BASEBAND_CMDS) +#define HCI_WRITE_ENCRYPTION_MODE (0x0022 | HCI_GRP_HOST_CONT_BASEBAND_CMDS) +#define HCI_READ_CLASS_OF_DEVICE (0x0023 | HCI_GRP_HOST_CONT_BASEBAND_CMDS) +#define HCI_WRITE_CLASS_OF_DEVICE (0x0024 | HCI_GRP_HOST_CONT_BASEBAND_CMDS) +#define HCI_READ_VOICE_SETTINGS (0x0025 | HCI_GRP_HOST_CONT_BASEBAND_CMDS) +#define HCI_WRITE_VOICE_SETTINGS (0x0026 | HCI_GRP_HOST_CONT_BASEBAND_CMDS) +#define HCI_READ_AUTO_FLUSH_TOUT (0x0027 | HCI_GRP_HOST_CONT_BASEBAND_CMDS) +#define HCI_WRITE_AUTO_FLUSH_TOUT (0x0028 | HCI_GRP_HOST_CONT_BASEBAND_CMDS) +#define HCI_READ_NUM_BCAST_REXMITS (0x0029 | HCI_GRP_HOST_CONT_BASEBAND_CMDS) +#define HCI_WRITE_NUM_BCAST_REXMITS (0x002A | HCI_GRP_HOST_CONT_BASEBAND_CMDS) +#define HCI_READ_HOLD_MODE_ACTIVITY (0x002B | HCI_GRP_HOST_CONT_BASEBAND_CMDS) +#define HCI_WRITE_HOLD_MODE_ACTIVITY (0x002C | HCI_GRP_HOST_CONT_BASEBAND_CMDS) +#define HCI_READ_TRANSMIT_POWER_LEVEL (0x002D | HCI_GRP_HOST_CONT_BASEBAND_CMDS) +#define HCI_READ_SCO_FLOW_CTRL_ENABLE (0x002E | HCI_GRP_HOST_CONT_BASEBAND_CMDS) +#define HCI_WRITE_SCO_FLOW_CTRL_ENABLE (0x002F | HCI_GRP_HOST_CONT_BASEBAND_CMDS) +#define HCI_SET_HC_TO_HOST_FLOW_CTRL (0x0031 | HCI_GRP_HOST_CONT_BASEBAND_CMDS) +#define HCI_HOST_BUFFER_SIZE (0x0033 | HCI_GRP_HOST_CONT_BASEBAND_CMDS) +#define HCI_HOST_NUM_PACKETS_DONE (0x0035 | HCI_GRP_HOST_CONT_BASEBAND_CMDS) +#define HCI_READ_LINK_SUPER_TOUT (0x0036 | HCI_GRP_HOST_CONT_BASEBAND_CMDS) +#define HCI_WRITE_LINK_SUPER_TOUT (0x0037 | HCI_GRP_HOST_CONT_BASEBAND_CMDS) +#define HCI_READ_NUM_SUPPORTED_IAC (0x0038 | HCI_GRP_HOST_CONT_BASEBAND_CMDS) +#define HCI_READ_CURRENT_IAC_LAP (0x0039 | HCI_GRP_HOST_CONT_BASEBAND_CMDS) +#define HCI_WRITE_CURRENT_IAC_LAP (0x003A | HCI_GRP_HOST_CONT_BASEBAND_CMDS) +#define HCI_READ_PAGESCAN_PERIOD_MODE (0x003B | HCI_GRP_HOST_CONT_BASEBAND_CMDS) +#define HCI_WRITE_PAGESCAN_PERIOD_MODE (0x003C | HCI_GRP_HOST_CONT_BASEBAND_CMDS) +#define HCI_READ_PAGESCAN_MODE (0x003D | HCI_GRP_HOST_CONT_BASEBAND_CMDS) +#define HCI_WRITE_PAGESCAN_MODE (0x003E | HCI_GRP_HOST_CONT_BASEBAND_CMDS) +#define HCI_SET_AFH_CHANNELS (0x003F | HCI_GRP_HOST_CONT_BASEBAND_CMDS) + +#define HCI_READ_INQSCAN_TYPE (0x0042 | HCI_GRP_HOST_CONT_BASEBAND_CMDS) +#define HCI_WRITE_INQSCAN_TYPE (0x0043 | HCI_GRP_HOST_CONT_BASEBAND_CMDS) +#define HCI_READ_INQUIRY_MODE (0x0044 | HCI_GRP_HOST_CONT_BASEBAND_CMDS) +#define HCI_WRITE_INQUIRY_MODE (0x0045 | HCI_GRP_HOST_CONT_BASEBAND_CMDS) +#define HCI_READ_PAGESCAN_TYPE (0x0046 | HCI_GRP_HOST_CONT_BASEBAND_CMDS) +#define HCI_WRITE_PAGESCAN_TYPE (0x0047 | HCI_GRP_HOST_CONT_BASEBAND_CMDS) +#define HCI_READ_AFH_ASSESSMENT_MODE (0x0048 | HCI_GRP_HOST_CONT_BASEBAND_CMDS) +#define HCI_WRITE_AFH_ASSESSMENT_MODE (0x0049 | HCI_GRP_HOST_CONT_BASEBAND_CMDS) +#define HCI_READ_EXT_INQ_RESPONSE (0x0051 | HCI_GRP_HOST_CONT_BASEBAND_CMDS) +#define HCI_WRITE_EXT_INQ_RESPONSE (0x0052 | HCI_GRP_HOST_CONT_BASEBAND_CMDS) +#define HCI_REFRESH_ENCRYPTION_KEY (0x0053 | HCI_GRP_HOST_CONT_BASEBAND_CMDS) +#define HCI_READ_SIMPLE_PAIRING_MODE (0x0055 | HCI_GRP_HOST_CONT_BASEBAND_CMDS) +#define HCI_WRITE_SIMPLE_PAIRING_MODE (0x0056 | HCI_GRP_HOST_CONT_BASEBAND_CMDS) +#define HCI_READ_LOCAL_OOB_DATA (0x0057 | HCI_GRP_HOST_CONT_BASEBAND_CMDS) +#define HCI_READ_INQ_TX_POWER_LEVEL (0x0058 | HCI_GRP_HOST_CONT_BASEBAND_CMDS) +#define HCI_WRITE_INQ_TX_POWER_LEVEL (0x0059 | HCI_GRP_HOST_CONT_BASEBAND_CMDS) +#define HCI_READ_ERRONEOUS_DATA_RPT (0x005A | HCI_GRP_HOST_CONT_BASEBAND_CMDS) +#define HCI_WRITE_ERRONEOUS_DATA_RPT (0x005B | HCI_GRP_HOST_CONT_BASEBAND_CMDS) +#define HCI_ENHANCED_FLUSH (0x005F | HCI_GRP_HOST_CONT_BASEBAND_CMDS) +#define HCI_SEND_KEYPRESS_NOTIF (0x0060 | HCI_GRP_HOST_CONT_BASEBAND_CMDS) + + +/* AMP HCI */ +#define HCI_READ_LOGICAL_LINK_ACCEPT_TIMEOUT (0x0061 | HCI_GRP_HOST_CONT_BASEBAND_CMDS) +#define HCI_WRITE_LOGICAL_LINK_ACCEPT_TIMEOUT (0x0062 | HCI_GRP_HOST_CONT_BASEBAND_CMDS) +#define HCI_SET_EVENT_MASK_PAGE_2 (0x0063 | HCI_GRP_HOST_CONT_BASEBAND_CMDS) +#define HCI_READ_LOCATION_DATA (0x0064 | HCI_GRP_HOST_CONT_BASEBAND_CMDS) +#define HCI_WRITE_LOCATION_DATA (0x0065 | HCI_GRP_HOST_CONT_BASEBAND_CMDS) +#define HCI_READ_FLOW_CONTROL_MODE (0x0066 | HCI_GRP_HOST_CONT_BASEBAND_CMDS) +#define HCI_WRITE_FLOW_CONTROL_MODE (0x0067 | HCI_GRP_HOST_CONT_BASEBAND_CMDS) +#define HCI_READ_BE_FLUSH_TOUT (0x0069 | HCI_GRP_HOST_CONT_BASEBAND_CMDS) +#define HCI_WRITE_BE_FLUSH_TOUT (0x006A | HCI_GRP_HOST_CONT_BASEBAND_CMDS) +#define HCI_SHORT_RANGE_MODE (0x006B | HCI_GRP_HOST_CONT_BASEBAND_CMDS) /* 802.11 only */ +#define HCI_READ_LE_HOST_SUPPORT (0x006C | HCI_GRP_HOST_CONT_BASEBAND_CMDS) +#define HCI_WRITE_LE_HOST_SUPPORT (0x006D | HCI_GRP_HOST_CONT_BASEBAND_CMDS) + + +/* MWS coexistence */ +#define HCI_SET_MWS_CHANNEL_PARAMETERS (0x006E | HCI_GRP_HOST_CONT_BASEBAND_CMDS) +#define HCI_SET_EXTERNAL_FRAME_CONFIGURATION (0x006F | HCI_GRP_HOST_CONT_BASEBAND_CMDS) +#define HCI_SET_MWS_SIGNALING (0x0070 | HCI_GRP_HOST_CONT_BASEBAND_CMDS) +#define HCI_SET_MWS_TRANSPORT_LAYER (0x0071 | HCI_GRP_HOST_CONT_BASEBAND_CMDS) +#define HCI_SET_MWS_SCAN_FREQUENCY_TABLE (0x0072 | HCI_GRP_HOST_CONT_BASEBAND_CMDS) +#define HCI_SET_MWS_PATTERN_CONFIGURATION (0x0073 | HCI_GRP_HOST_CONT_BASEBAND_CMDS) + +/* Connectionless Broadcast */ +#define HCI_SET_RESERVED_LT_ADDR (0x0074 | HCI_GRP_HOST_CONT_BASEBAND_CMDS) +#define HCI_DELETE_RESERVED_LT_ADDR (0x0075 | HCI_GRP_HOST_CONT_BASEBAND_CMDS) +#define HCI_WRITE_CLB_DATA (0x0076 | HCI_GRP_HOST_CONT_BASEBAND_CMDS) +#define HCI_READ_SYNC_TRAIN_PARAM (0x0077 | HCI_GRP_HOST_CONT_BASEBAND_CMDS) +#define HCI_WRITE_SYNC_TRAIN_PARAM (0x0078 | HCI_GRP_HOST_CONT_BASEBAND_CMDS) + +#define HCI_READ_SECURE_CONNS_SUPPORT (0x0079 | HCI_GRP_HOST_CONT_BASEBAND_CMDS) +#define HCI_WRITE_SECURE_CONNS_SUPPORT (0x007A | HCI_GRP_HOST_CONT_BASEBAND_CMDS) +#define HCI_CONT_BASEBAND_CMDS_FIRST HCI_SET_EVENT_MASK +#define HCI_CONT_BASEBAND_CMDS_LAST HCI_READ_SYNC_TRAIN_PARAM + + +/* Commands of HCI_GRP_INFORMATIONAL_PARAMS group */ +#define HCI_READ_LOCAL_VERSION_INFO (0x0001 | HCI_GRP_INFORMATIONAL_PARAMS) +#define HCI_READ_LOCAL_SUPPORTED_CMDS (0x0002 | HCI_GRP_INFORMATIONAL_PARAMS) +#define HCI_READ_LOCAL_FEATURES (0x0003 | HCI_GRP_INFORMATIONAL_PARAMS) +#define HCI_READ_LOCAL_EXT_FEATURES (0x0004 | HCI_GRP_INFORMATIONAL_PARAMS) +#define HCI_READ_BUFFER_SIZE (0x0005 | HCI_GRP_INFORMATIONAL_PARAMS) +#define HCI_READ_COUNTRY_CODE (0x0007 | HCI_GRP_INFORMATIONAL_PARAMS) +#define HCI_READ_BD_ADDR (0x0009 | HCI_GRP_INFORMATIONAL_PARAMS) +#define HCI_READ_DATA_BLOCK_SIZE (0x000A | HCI_GRP_INFORMATIONAL_PARAMS) +#define HCI_READ_LOCAL_SUPPORTED_CODECS (0x000B | HCI_GRP_INFORMATIONAL_PARAMS) + +#define HCI_INFORMATIONAL_CMDS_FIRST HCI_READ_LOCAL_VERSION_INFO +#define HCI_INFORMATIONAL_CMDS_LAST HCI_READ_LOCAL_SUPPORTED_CODECS + + +/* Commands of HCI_GRP_STATUS_PARAMS group */ +#define HCI_READ_FAILED_CONTACT_COUNT (0x0001 | HCI_GRP_STATUS_PARAMS) +#define HCI_RESET_FAILED_CONTACT_COUNT (0x0002 | HCI_GRP_STATUS_PARAMS) +#define HCI_GET_LINK_QUALITY (0x0003 | HCI_GRP_STATUS_PARAMS) +#define HCI_READ_RSSI (0x0005 | HCI_GRP_STATUS_PARAMS) +#define HCI_READ_AFH_CH_MAP (0x0006 | HCI_GRP_STATUS_PARAMS) +#define HCI_READ_CLOCK (0x0007 | HCI_GRP_STATUS_PARAMS) +#define HCI_READ_ENCR_KEY_SIZE (0x0008 | HCI_GRP_STATUS_PARAMS) + +/* AMP HCI */ +#define HCI_READ_LOCAL_AMP_INFO (0x0009 | HCI_GRP_STATUS_PARAMS) +#define HCI_READ_LOCAL_AMP_ASSOC (0x000A | HCI_GRP_STATUS_PARAMS) +#define HCI_WRITE_REMOTE_AMP_ASSOC (0x000B | HCI_GRP_STATUS_PARAMS) + +#define HCI_STATUS_PARAMS_CMDS_FIRST HCI_READ_FAILED_CONTACT_COUNT +#define HCI_STATUS_PARAMS_CMDS_LAST HCI_WRITE_REMOTE_AMP_ASSOC + +/* Commands of HCI_GRP_TESTING_CMDS group */ +#define HCI_READ_LOOPBACK_MODE (0x0001 | HCI_GRP_TESTING_CMDS) +#define HCI_WRITE_LOOPBACK_MODE (0x0002 | HCI_GRP_TESTING_CMDS) +#define HCI_ENABLE_DEV_UNDER_TEST_MODE (0x0003 | HCI_GRP_TESTING_CMDS) +#define HCI_WRITE_SIMP_PAIR_DEBUG_MODE (0x0004 | HCI_GRP_TESTING_CMDS) + +/* AMP HCI */ +#define HCI_ENABLE_AMP_RCVR_REPORTS (0x0007 | HCI_GRP_TESTING_CMDS) +#define HCI_AMP_TEST_END (0x0008 | HCI_GRP_TESTING_CMDS) +#define HCI_AMP_TEST (0x0009 | HCI_GRP_TESTING_CMDS) + +#define HCI_TESTING_CMDS_FIRST HCI_READ_LOOPBACK_MODE +#define HCI_TESTING_CMDS_LAST HCI_AMP_TEST + +#define HCI_VENDOR_CMDS_FIRST 0x0001 +#define HCI_VENDOR_CMDS_LAST 0xFFFF +#define HCI_VSC_MULTI_AV_HANDLE 0x0AAA +#define HCI_VSC_BURST_MODE_HANDLE 0x0BBB + +/* BLE HCI */ +#define HCI_GRP_BLE_CMDS (0x08 << 10) +/* Commands of BLE Controller setup and configuration */ +#define HCI_BLE_SET_EVENT_MASK (0x0001 | HCI_GRP_BLE_CMDS) +#define HCI_BLE_READ_BUFFER_SIZE (0x0002 | HCI_GRP_BLE_CMDS) +#define HCI_BLE_READ_LOCAL_SPT_FEAT (0x0003 | HCI_GRP_BLE_CMDS) +#define HCI_BLE_WRITE_LOCAL_SPT_FEAT (0x0004 | HCI_GRP_BLE_CMDS) +#define HCI_BLE_WRITE_RANDOM_ADDR (0x0005 | HCI_GRP_BLE_CMDS) +#define HCI_BLE_WRITE_ADV_PARAMS (0x0006 | HCI_GRP_BLE_CMDS) +#define HCI_BLE_READ_ADV_CHNL_TX_POWER (0x0007 | HCI_GRP_BLE_CMDS) +#define HCI_BLE_WRITE_ADV_DATA (0x0008 | HCI_GRP_BLE_CMDS) +#define HCI_BLE_WRITE_SCAN_RSP_DATA (0x0009 | HCI_GRP_BLE_CMDS) +#define HCI_BLE_WRITE_ADV_ENABLE (0x000A | HCI_GRP_BLE_CMDS) +#define HCI_BLE_WRITE_SCAN_PARAMS (0x000B | HCI_GRP_BLE_CMDS) +#define HCI_BLE_WRITE_SCAN_ENABLE (0x000C | HCI_GRP_BLE_CMDS) +#define HCI_BLE_CREATE_LL_CONN (0x000D | HCI_GRP_BLE_CMDS) +#define HCI_BLE_CREATE_CONN_CANCEL (0x000E | HCI_GRP_BLE_CMDS) +#define HCI_BLE_READ_WHITE_LIST_SIZE (0x000F | HCI_GRP_BLE_CMDS) +#define HCI_BLE_CLEAR_WHITE_LIST (0x0010 | HCI_GRP_BLE_CMDS) +#define HCI_BLE_ADD_WHITE_LIST (0x0011 | HCI_GRP_BLE_CMDS) +#define HCI_BLE_REMOVE_WHITE_LIST (0x0012 | HCI_GRP_BLE_CMDS) +#define HCI_BLE_UPD_LL_CONN_PARAMS (0x0013 | HCI_GRP_BLE_CMDS) +#define HCI_BLE_SET_HOST_CHNL_CLASS (0x0014 | HCI_GRP_BLE_CMDS) +#define HCI_BLE_READ_CHNL_MAP (0x0015 | HCI_GRP_BLE_CMDS) +#define HCI_BLE_READ_REMOTE_FEAT (0x0016 | HCI_GRP_BLE_CMDS) +#define HCI_BLE_ENCRYPT (0x0017 | HCI_GRP_BLE_CMDS) +#define HCI_BLE_RAND (0x0018 | HCI_GRP_BLE_CMDS) +#define HCI_BLE_START_ENC (0x0019 | HCI_GRP_BLE_CMDS) +#define HCI_BLE_LTK_REQ_REPLY (0x001A | HCI_GRP_BLE_CMDS) +#define HCI_BLE_LTK_REQ_NEG_REPLY (0x001B | HCI_GRP_BLE_CMDS) +#define HCI_BLE_READ_SUPPORTED_STATES (0x001C | HCI_GRP_BLE_CMDS) + /*0x001D, 0x001E and 0x001F are reserved*/ +#define HCI_BLE_RECEIVER_TEST (0x001D | HCI_GRP_BLE_CMDS) +#define HCI_BLE_TRANSMITTER_TEST (0x001E | HCI_GRP_BLE_CMDS) +/* BLE TEST COMMANDS */ +#define HCI_BLE_TEST_END (0x001F | HCI_GRP_BLE_CMDS) +#define HCI_BLE_RC_PARAM_REQ_REPLY (0x0020 | HCI_GRP_BLE_CMDS) +#define HCI_BLE_RC_PARAM_REQ_NEG_REPLY (0x0021 | HCI_GRP_BLE_CMDS) + +#define HCI_BLE_SET_DATA_LENGTH (0x0022 | HCI_GRP_BLE_CMDS) +#define HCI_BLE_READ_DEFAULT_DATA_LENGTH (0x0023 | HCI_GRP_BLE_CMDS) +#define HCI_BLE_WRITE_DEFAULT_DATA_LENGTH (0x0024 | HCI_GRP_BLE_CMDS) + +#define HCI_BLE_ADD_DEV_RESOLVING_LIST (0x0027 | HCI_GRP_BLE_CMDS) +#define HCI_BLE_RM_DEV_RESOLVING_LIST (0x0028 | HCI_GRP_BLE_CMDS) +#define HCI_BLE_CLEAR_RESOLVING_LIST (0x0029 | HCI_GRP_BLE_CMDS) +#define HCI_BLE_READ_RESOLVING_LIST_SIZE (0x002A | HCI_GRP_BLE_CMDS) +#define HCI_BLE_READ_RESOLVABLE_ADDR_PEER (0x002B | HCI_GRP_BLE_CMDS) +#define HCI_BLE_READ_RESOLVABLE_ADDR_LOCAL (0x002C | HCI_GRP_BLE_CMDS) +#define HCI_BLE_SET_ADDR_RESOLUTION_ENABLE (0x002D | HCI_GRP_BLE_CMDS) +#define HCI_BLE_SET_RAND_PRIV_ADDR_TIMOUT (0x002E | HCI_GRP_BLE_CMDS) + +/* LE Get Vendor Capabilities Command OCF */ +#define HCI_BLE_VENDOR_CAP_OCF (0x0153 | HCI_GRP_VENDOR_SPECIFIC) + +/* Multi adv OCF */ +#define HCI_BLE_MULTI_ADV_OCF (0x0154 | HCI_GRP_VENDOR_SPECIFIC) + +/* Batch scan OCF */ +#define HCI_BLE_BATCH_SCAN_OCF (0x0156 | HCI_GRP_VENDOR_SPECIFIC) + +/* ADV filter OCF */ +#define HCI_BLE_ADV_FILTER_OCF (0x0157 | HCI_GRP_VENDOR_SPECIFIC) + +/* Tracking OCF */ +#define HCI_BLE_TRACK_ADV_OCF (0x0158 | HCI_GRP_VENDOR_SPECIFIC) + +/* Energy info OCF */ +#define HCI_BLE_ENERGY_INFO_OCF (0x0159 | HCI_GRP_VENDOR_SPECIFIC) + +/* Extended BLE Scan parameters OCF */ +#define HCI_BLE_EXTENDED_SCAN_PARAMS_OCF (0x0160 | HCI_GRP_VENDOR_SPECIFIC) + +/* subcode for multi adv feature */ +#define BTM_BLE_MULTI_ADV_SET_PARAM 0x01 +#define BTM_BLE_MULTI_ADV_WRITE_ADV_DATA 0x02 +#define BTM_BLE_MULTI_ADV_WRITE_SCAN_RSP_DATA 0x03 +#define BTM_BLE_MULTI_ADV_SET_RANDOM_ADDR 0x04 +#define BTM_BLE_MULTI_ADV_ENB 0x05 + +/* multi adv VSE subcode */ +#define HCI_VSE_SUBCODE_BLE_MULTI_ADV_ST_CHG 0x55 /* multi adv instance state change */ + +/* subcode for batch scan feature */ +#define BTM_BLE_BATCH_SCAN_ENB_DISAB_CUST_FEATURE 0x01 +#define BTM_BLE_BATCH_SCAN_SET_STORAGE_PARAM 0x02 +#define BTM_BLE_BATCH_SCAN_SET_PARAMS 0x03 +#define BTM_BLE_BATCH_SCAN_READ_RESULTS 0x04 + +/* batch scan VSE subcode */ +#define HCI_VSE_SUBCODE_BLE_THRESHOLD_SUB_EVT 0x54 /* Threshold event */ + +/* tracking sub event */ +#define HCI_VSE_SUBCODE_BLE_TRACKING_SUB_EVT 0x56 /* Tracking event */ + +/* LE supported states definition */ +#define HCI_LE_ADV_STATE 0x00000001 +#define HCI_LE_SCAN_STATE 0x00000002 +#define HCI_LE_INIT_STATE 0x00000004 +#define HCI_LE_CONN_SL_STATE 0x00000008 +#define HCI_LE_ADV_SCAN_STATE 0x00000010 +#define HCI_LE_ADV_INIT_STATE 0x00000020 +#define HCI_LE_ADV_MA_STATE 0x00000040 +#define HCI_LE_ADV_SL_STATE 0x00000080 +#define HCI_LE_SCAN_INIT_STATE 0x00000100 +#define HCI_LE_SCAN_MA_STATE 0x00000200 +#define HCI_LE_SCAN_SL_STATE 0x00000400 +#define HCI_LE_INIT_MA_STATE 0x00000800 + +/* LE Supported States */ +/* Non Connectable Adv state is supported. 0x0000000000000001 */ +#define HCI_SUPP_LE_STATES_NON_CONN_ADV_MASK 0x01 +#define HCI_SUPP_LE_STATES_NON_CONN_ADV_OFF 0 +#define HCI_LE_STATES_NON_CONN_ADV_SUPPORTED(x) ((x)[HCI_SUPP_LE_STATES_NON_CONN_ADV_OFF] & HCI_SUPP_LE_STATES_NON_CONN_ADV_MASK) + +/*Scanneable Connectable Adv state is supported. 0x0000000000000002 */ +#define HCI_SUPP_LE_STATES_SCAN_ADV_MASK 0x02 +#define HCI_SUPP_LE_STATESSCAN_ADV_OFF 0 +#define HCI_LE_STATES_SCAN_ADV_SUPPORTED(x) ((x)[HCI_SUPP_LE_STATESSCAN_ADV_OFF] & HCI_SUPP_LE_STATES_SCAN_ADV_MASK) + +/* Connectable Adv state is supported. 0x0000000000000004 */ +#define HCI_SUPP_LE_STATES_CONN_ADV_MASK 0x04 +#define HCI_SUPP_LE_STATES_CONN_ADV_OFF 0 +#define HCI_LE_STATES_CONN_ADV_SUPPORTED(x) ((x)[HCI_SUPP_LE_STATES_CONN_ADV_OFF] & HCI_SUPP_LE_STATES_CONN_ADV_MASK) + +/* Hi duty Cycle Directed Adv state is supported. 0x0000000000000008 */ +#define HCI_SUPP_LE_STATES_HI_DUTY_DIR_ADV_MASK 0x08 +#define HCI_SUPP_LE_STATES_HI_DUTY_DIR_ADV_OFF 0 +#define HCI_LE_STATES_HI_DUTY_DIR_ADV_SUPPORTED(x) ((x)[HCI_SUPP_LE_STATES_HI_DUTY_DIR_ADV_OFF] & HCI_SUPP_LE_STATES_HI_DUTY_DIR_ADV_MASK) + +/* Passive Scan state is supported. 0x0000000000000010 */ +#define HCI_SUPP_LE_STATES_PASS_SCAN_MASK 0x10 +#define HCI_SUPP_LE_STATES_PASS_SCAN_OFF 0 +#define HCI_LE_STATES_PASS_SCAN_SUPPORTED(x) ((x)[HCI_SUPP_LE_STATES_PASS_SCAN_OFF] & HCI_SUPP_LE_STATES_PASS_SCAN_MASK) + +/* Active Scan state is supported. 0x0000000000000020 */ +#define HCI_SUPP_LE_STATES_ACTIVE_SCAN_MASK 0x20 +#define HCI_SUPP_LE_STATES_ACTIVE_SCAN_OFF 0 +#define HCI_LE_STATES_ACTIVE_SCAN_SUPPORTED(x) ((x)[HCI_SUPP_LE_STATES_ACTIVE_SCAN_OFF] & HCI_SUPP_LE_STATES_ACTIVE_SCAN_MASK) + +/* Initiating state is supported. 0x0000000000000040 (or connection state in master role is also supported) */ +#define HCI_SUPP_LE_STATES_INIT_MASK 0x40 +#define HCI_SUPP_LE_STATES_INIT_OFF 0 +#define HCI_LE_STATES_INIT_SUPPORTED(x) ((x)[HCI_SUPP_LE_STATES_INIT_OFF] & HCI_SUPP_LE_STATES_INIT_MASK) + +/*connection state in slave role is also supported. 0x0000000000000080 */ +#define HCI_SUPP_LE_STATES_SLAVE_MASK 0x80 +#define HCI_SUPP_LE_STATES_SLAVE_OFF 0 +#define HCI_LE_STATES_SLAVE_SUPPORTED(x) ((x)[HCI_SUPP_LE_STATES_SLAVE_OFF] & HCI_SUPP_LE_STATES_SLAVE_MASK) + +/* Non Connectable Adv state and Passive Scanning State combination is supported. 0x0000000000000100 */ +#define HCI_SUPP_LE_STATES_NON_CONN_ADV_PASS_SCAN_MASK 0x01 +#define HCI_SUPP_LE_STATES_NON_CONN_ADV_PASS_SCAN_OFF 1 +#define HCI_LE_STATES_NON_CONN_ADV_PASS_SCAN_SUPPORTED(x) ((x)[HCI_SUPP_LE_STATES_NON_CONN_ADV_PASS_SCAN_OFF] & HCI_SUPP_LE_STATES_NON_CONN_ADV_PASS_SCAN_MASK) + +/*Scannable Adv state and Passive Scanning State combination is supported. 0x0000000000000200 */ +#define HCI_SUPP_LE_STATES_SCAN_ADV_PASS_SCAN_MASK 0x02 +#define HCI_SUPP_LE_STATES_SCAN_ADV_PASS_SCAN_OFF 1 +#define HCI_LE_STATES_SCAN_ADV_PASS_SCAN_SUPPORTED(x) ((x)[HCI_SUPP_LE_STATES_SCAN_ADV_PASS_SCAN_OFF] & HCI_SUPP_LE_STATES_SCAN_ADV_PASS_SCAN_MASK) + +/*Connectable Adv state and Passive Scanning State combination is supported. 0x0000000000000400 */ +#define HCI_SUPP_LE_STATES_CONN_ADV_PASS_SCAN_MASK 0x04 +#define HCI_SUPP_LE_STATES_CONN_ADV_PASS_SCAN_OFF 1 +#define HCI_LE_STATES_CONN_ADV_PASS_SCAN_SUPPORTED(x) ((x)[HCI_SUPP_LE_STATES_CONN_ADV_PASS_SCAN_OFF] & HCI_SUPP_LE_STATES_CONN_ADV_PASS_SCAN_MASK) + +/*High Duty Cycl Directed ADv and Passive Scanning State combination is supported. 0x0000000000000800 */ +#define HCI_SUPP_LE_STATES_HI_DUTY_DIR_ADV_PASS_SCAN_MASK 0x08 +#define HCI_SUPP_LE_STATES_HI_DUTY_DIR_ADV_PASS_SCAN_OFF 1 +#define HCI_LE_STATES_HI_DUTY_DIR_ADV_PASS_SCAN_SUPPORTED(x) ((x)[HCI_SUPP_LE_STATES_HI_DUTY_DIR_ADV_PASS_SCAN_MASK] & HCI_SUPP_LE_STATES_HI_DUTY_DIR_ADV_PASS_SCAN_OFF) + +/*Non Connectable Adv state and Passive Scanning State combination is supported. 0x0000000000001000 */ +#define HCI_SUPP_LE_STATES_NON_CONN_ADV_ACTIVE_SCAN_MASK 0x10 +#define HCI_SUPP_LE_STATES_NON_CONN_ADV_ACTIVE_SCAN_OFF 1 +#define HCI_LE_STATES_NON_CONN_ADV_ACTIVE_SCAN_SUPPORTED(x) ((x)[HCI_SUPP_LE_STATES_NON_CONN_ADV_ACTIVE_SCAN_OFF] & HCI_SUPP_LE_STATES_NON_CONN_ADV_ACTIVE_SCAN_MASK) + +/*Scannable Adv state and Active Scanning State combination is supported. 0x0000000000002000 */ +#define HCI_SUPP_LE_STATES_SCAN_ADV_ACTIVE_SCAN_MASK 0x20 +#define HCI_SUPP_LE_STATES_SCAN_ADV_ACTIVE_SCAN_OFF 1 +#define HCI_LE_STATES_SCAN_ADV_ACTIVE_SCAN_SUPPORTED(x) ((x)[HCI_SUPP_LE_STATES_SCAN_ADV_ACTIVE_SCAN_OFF] & HCI_SUPP_LE_STATES_SCAN_ADV_ACTIVE_SCAN_MASK) + +/*Connectable Adv state and Active Scanning State combination is supported. 0x0000000000004000 */ +#define HCI_SUPP_LE_STATES_CONN_ADV_ACTIVE_SCAN_MASK 0x40 +#define HCI_SUPP_LE_STATES_CONN_ADV_ACTIVE_SCAN_OFF 1 +#define HCI_LE_STATES_CONN_ADV_ACTIVE_SCAN_SUPPORTED(x) ((x)[HCI_SUPP_LE_STATES_CONN_ADV_ACTIVE_SCAN_OFF] & HCI_SUPP_LE_STATES_CONN_ADV_ACTIVE_SCAN_MASK) + +/*High Duty Cycl Directed ADv and ACtive Scanning State combination is supported. 0x0000000000008000 */ +#define HCI_SUPP_LE_STATES_HI_DUTY_DIR_ADV_ACTIVE_SCAN_MASK 0x80 +#define HCI_SUPP_LE_STATES_HI_DUTY_DIR_ADV_ACTIVE_SCAN_OFF 1 +#define HCI_LE_STATES_HI_DUTY_DIR_ADV_ACTIVE_SCAN_SUPPORTED(x) ((x)[HCI_SUPP_LE_STATES_HI_DUTY_DIR_ADV_ACTIVE_SCAN_MASK] & HCI_SUPP_LE_STATES_HI_DUTY_DIR_ADV_ACTIVE_SCAN_OFF) + +/*Non-Connectable Adv state and Initiating State combination is supported. 0x0000000000010000 */ +#define HCI_SUPP_LE_STATES_NON_CONN_INIT_MASK 0x01 +#define HCI_SUPP_LE_STATES_NON_CONN_INIT_OFF 2 +#define HCI_LE_STATES_NON_CONN_INIT_SUPPORTED(x) ((x)[HCI_SUPP_LE_STATES_NON_CONN_INIT_OFF] & HCI_SUPP_LE_STATES_NON_CONN_INIT_MASK) + +/* Scannable Adv state and Initiating State combination is supported. 0x0000000000020000 */ +#define HCI_SUPP_LE_STATES_SCAN_ADV_INIT_MASK 0x02 +#define HCI_SUPP_LE_STATES_SCAN_ADV_INIT_OFF 2 +#define HCI_LE_STATES_SCAN_ADV_INIT_SUPPORTED(x) ((x)[HCI_SUPP_LE_STATES_SCAN_ADV_INIT_OFF] & HCI_SUPP_LE_STATES_SCAN_ADV_INIT_MASK) + +/* Non-Connectable Adv state and Master Role combination is supported. 0x0000000000040000 */ +#define HCI_SUPP_LE_STATES_NON_CONN_ADV_MASTER_MASK 0x04 +#define HCI_SUPP_LE_STATES_NON_CONN_ADV_MASTER_OFF 2 +#define HCI_LE_STATES_NON_CONN_ADV_MASTER_SUPPORTED(x) ((x)[HCI_SUPP_LE_STATES_NON_CONN_ADV_MASTER_OFF] & HCI_SUPP_LE_STATES_NON_CONN_ADV_MASTER_MASK) + +/*Scannable Adv state and Master Role combination is supported. 0x0000000000040000 */ +#define HCI_SUPP_LE_STATES_SCAN_ADV_MASTER_MASK 0x08 +#define HCI_SUPP_LE_STATES_SCAN_ADV_MASTER_OFF 2 +#define HCI_LE_STATES_SCAN_ADV_MASTER_SUPPORTED(x) ((x)[HCI_SUPP_LE_STATES_SCAN_ADV_MASTER_OFF] & HCI_SUPP_LE_STATES_SCAN_ADV_MASTER_MASK) + +/* Non-Connectable Adv and Slave Role combination is supported. 0x000000000100000 */ +#define HCI_SUPP_LE_STATES_NON_CONN_ADV_SLAVE_MASK 0x10 +#define HCI_SUPP_LE_STATES_NON_CONN_ADV_SLAVE_OFF 2 +#define HCI_LE_STATES_NON_CONN_ADV_SLAVE_SUPPORTED(x) ((x)[HCI_SUPP_LE_STATES_NON_CONN_ADV_SLAVE_OFF] & HCI_SUPP_LE_STATES_NON_CONN_ADV_SLAVE_MASK) + +/*Scannable Adv and Slave Role combination is supported. 0x000000000200000 */ +#define HCI_SUPP_LE_STATES_SCAN_ADV_SLAVE_MASK 0x20 +#define HCI_SUPP_LE_STATES_SCAN_ADV_SLAVE_OFF 2 +#define HCI_LE_STATES_SCAN_ADV_SLAVE_SUPPORTED(x) ((x)[HCI_SUPP_LE_STATES_SCAN_ADV_SLAVE_OFF] & HCI_SUPP_LE_STATES_SCAN_ADV_SLAVE_MASK) + +/*Passive Scan and Initiating State combination is supported. 0x000000000400000 */ +#define HCI_SUPP_LE_STATES_PASS_SCAN_INIT_MASK 0x40 +#define HCI_SUPP_LE_STATES_PASS_SCAN_INIT_OFF 2 +#define HCI_LE_STATES_PASS_SCAN_INIT_SUPPORTED(x) ((x)[HCI_SUPP_LE_STATES_PASS_SCAN_INIT_OFF] & HCI_SUPP_LE_STATES_PASS_SCAN_INIT_MASK) + +/*Active Scan and Initiating State combination is supported. 0x000000000800000 */ +#define HCI_SUPP_LE_STATES_ACTIVE_SCAN_INIT_MASK 0x80 +#define HCI_SUPP_LE_STATES_ACTIVE_SCAN_INIT_OFF 2 +#define HCI_LE_STATES_ACTIVE_SCAN_INIT_SUPPORTED(x) ((x)[HCI_SUPP_LE_STATES_ACTIVE_SCAN_INIT_OFF] & HCI_SUPP_LE_STATES_ACTIVE_SCAN_INIT_MASK) + +/*Passive Scan and Master Role combination is supported. 0x000000001000000 */ +#define HCI_SUPP_LE_STATES_PASS_SCAN_MASTER_MASK 0x01 +#define HCI_SUPP_LE_STATES_PASS_SCAN_MASTER_OFF 3 +#define HCI_LE_STATES_PASS_SCAN_MASTER_SUPPORTED(x) ((x)[HCI_SUPP_LE_STATES_PASS_SCAN_MASTER_OFF] & HCI_SUPP_LE_STATES_PASS_SCAN_MASTER_MASK) + +/*Active Scan and Master Role combination is supported. 0x000000002000000 */ +#define HCI_SUPP_LE_STATES_ACTIVE_SCAN_MASTER_MASK 0x02 +#define HCI_SUPP_LE_STATES_ACTIVE_SCAN_MASTER_OFF 3 +#define HCI_LE_STATES_ACTIVE_SCAN_MASTER_SUPPORTED(x) ((x)[HCI_SUPP_LE_STATES_ACTIVE_SCAN_MASTER_OFF] & HCI_SUPP_LE_STATES_ACTIVE_SCAN_MASTER_MASK) + +/*Passive Scan and Slave Role combination is supported. 0x000000004000000 */ +#define HCI_SUPP_LE_STATES_PASS_SCAN_SLAVE_MASK 0x04 +#define HCI_SUPP_LE_STATES_PASS_SCAN_SLAVE_OFF 3 +#define HCI_LE_STATES_PASS_SCAN_SLAVE_SUPPORTED(x) ((x)[HCI_SUPP_LE_STATES_PASS_SCAN_SLAVE_OFF] & HCI_SUPP_LE_STATES_PASS_SCAN_SLAVE_MASK) + +/*Active Scan and Slave Role combination is supported. 0x000000008000000 */ +#define HCI_SUPP_LE_STATES_ACTIVE_SCAN_SLAVE_MASK 0x08 +#define HCI_SUPP_LE_STATES_ACTIVE_SCAN_SLAVE_OFF 3 +#define HCI_LE_STATES_ACTIVE_SCAN_SLAVE_SUPPORTED(x) ((x)[HCI_SUPP_LE_STATES_ACTIVE_SCAN_SLAVE_OFF] & HCI_SUPP_LE_STATES_ACTIVE_SCAN_SLAVE_MASK) + +/*Link Layer Topology Added States Combo */ +/*Initiating State and Master Role combination supported. + Master Role and Master Role combination is also supported. 0x0000000010000000 */ +#define HCI_SUPP_LE_STATES_INIT_MASTER_MASK 0x10 +#define HCI_SUPP_LE_STATES_INIT_MASTER_OFF 3 +#define HCI_LE_STATES_INIT_MASTER_SUPPORTED(x) ((x)[HCI_SUPP_LE_STATES_INIT_MASTER_OFF] & HCI_SUPP_LE_STATES_INIT_MASTER_MASK) + +/*Low Duty Cycle Directed Advertising State . 0x0000000020000000 */ +#define HCI_SUPP_LE_STATES_LO_DUTY_DIR_ADV_MASK 0x20 +#define HCI_SUPP_LE_STATES_LO_DUTY_DIR_ADV_OFF 3 +#define HCI_LE_STATES_LOW_DUTY_DIR_ADV_SUPPORTED(x) ((x)[HCI_SUPP_LE_STATES_LOW_DUTY_DIR_ADV_OFF] & HCI_SUPP_LE_STATES_LOW_DUTY_DIR_ADV_MASK) + +/*Low Duty Cycle Directed Advertising State and Passive scan combination. 0x0000000040000000 */ +#define HCI_SUPP_LE_STATES_LO_DUTY_DIR_ADV_PASS_SCAN_MASK 0x40 +#define HCI_SUPP_LE_STATES_LO_DUTY_DIR_ADV_PASS_SCAN_OFF 3 +#define HCI_LE_STATES_LO_DUTY_DIR_ADV_PASS_SCAN_SUPPORTED(x) ((x)[HCI_SUPP_LE_STATES_LO_DUTY_DIR_ADV_PASS_SCAN_OFF] & HCI_SUPP_LE_STATES_LO_DUTY_DIR_ADV_PASS_SCAN_MASK) + +/*Low Duty Cycle Directed Advertising State and Active scan combination . 0x0000000080000000 */ +#define HCI_SUPP_LE_STATES_LO_DUTY_DIR_ADV_ACTIVE_SCAN_MASK 0x80 +#define HCI_SUPP_LE_STATES_LO_DUTY_DIR_ADV_ACTIVE_SCAN_OFF 3 +#define HCI_LE_STATES_LO_DUTY_DIR_ADV_ACTIVE_SCAN_SUPPORTED(x) ((x)[HCI_SUPP_LE_STATES_LO_DUTY_DIR_ADV_ACTIVE_SCAN_OFF] & HCI_SUPP_LE_STATES_LO_DUTY_DIR_ADV_ACTIVE_SCAN_MASK) + +/* Connectable Advertising State and Initiating State combination supported. 0x0000000100000000 */ +#define HCI_SUPP_LE_STATES_CONN_ADV_INIT_MASK 0x01 +#define HCI_SUPP_LE_STATES_CONN_ADV_INIT_OFF 4 +#define HCI_LE_STATES_CONN_ADV_INIT_SUPPORTED(x) ((x)[HCI_SUPP_LE_STATES_CONN_ADV_INIT_OFF] & HCI_SUPP_LE_STATES_CONN_ADV_INIT_MASK) + +/* High Duty Cycle Directed Advertising State and Initiating State combination supported. */ +#define HCI_SUPP_LE_STATES_HI_DUTY_DIR_ADV_INIT_MASK 0x02 +#define HCI_SUPP_LE_STATES_HI_DUTY_DIR_ADV_INIT_OFF 4 +#define HCI_LE_STATES_HI_DUTY_DIR_ADV_INIT_SUPPORTED(x) ((x)[HCI_SUPP_LE_STATES_HI_DUTY_DIR_ADV_INIT_OFF] & HCI_SUPP_LE_STATES_HI_DUTY_DIR_ADV_INIT_MASK) + +/* Low Duty Cycle Directed Advertising State and Initiating State combination supported.*/ +#define HCI_SUPP_LE_STATES_LO_DUTY_DIR_ADV_INIT_MASK 0x04 +#define HCI_SUPP_LE_STATES_LO_DUTY_DIR_ADV_INIT_OFF 4 +#define HCI_LE_STATES_LO_DUTY_DIR_ADV_INIT_SUPPORTED(x) ((x)[HCI_SUPP_LE_STATES_LO_DUTY_DIR_ADV_INIT_OFF] & HCI_SUPP_LE_STATES_LO_DUTY_DIR_ADV_INIT_MASK) + +/* Connectable Advertising State and Master Role combination supported.*/ +#define HCI_SUPP_LE_STATES_CONN_ADV_MASTER_MASK 0x08 +#define HCI_SUPP_LE_STATES_CONN_ADV_MASTER_OFF 4 +#define HCI_LE_STATES_CONN_ADV_MASTER_SUPPORTED(x) ((x)[HCI_SUPP_LE_STATES_CONN_ADV_MASTER_OFF] & HCI_SUPP_LE_STATES_CONN_ADV_MASTER_MASK) + +/* High Duty Cycle Directed Advertising State and Master Role combination supported.*/ +#define HCI_SUPP_LE_STATES_HI_DUTY_DIR_ADV_MASTER_MASK 0x10 +#define HCI_SUPP_LE_STATES_HI_DUTY_DIR_ADV_MASTER_OFF 4 +#define HCI_LE_STATES_HI_DUTY_DIR_ADV_MASTER_SUPPORTED(x) ((x)[HCI_SUPP_LE_STATES_HI_DUTY_DIR_ADV_MASTER_OFF] & HCI_SUPP_LE_STATES_HI_DUTY_DIR_ADV_MASTER_MASK) + +/* Low Duty Cycle Directed Advertising State and Master Role combination supported.*/ +#define HCI_SUPP_LE_STATES_LO_DUTY_DIR_ADV_MASTER_MASK 0x20 +#define HCI_SUPP_LE_STATES_LO_DUTY_DIR_ADV_MASTER_OFF 4 +#define HCI_LE_STATES_LO_DUTY_DIR_ADV_MASTER_SUPPORTED(x) ((x)[HCI_SUPP_LE_STATES_LO_DUTY_DIR_ADV_MASTER_OFF] & HCI_SUPP_LE_STATES_LO_DUTY_DIR_ADV_MASTER_MASK) + +/* Connectable Advertising State and Slave Role combination supported. */ +#define HCI_SUPP_LE_STATES_CONN_ADV_SLAVE_MASK 0x40 +#define HCI_SUPP_LE_STATES_CONN_ADV_SLAVE_OFF 4 +#define HCI_LE_STATES_CONN_ADV_SLAVE_SUPPORTED(x) ((x)[HCI_SUPP_LE_STATES_CONN_ADV_SLAVE_OFF] & HCI_SUPP_LE_STATES_CONN_ADV_SLAVE_MASK) + +/* High Duty Cycle Directed Advertising State and slave Role combination supported.*/ +#define HCI_SUPP_LE_STATES_HI_DUTY_DIR_ADV_SLAVE_MASK 0x80 +#define HCI_SUPP_LE_STATES_HI_DUTY_DIR_ADV_SLAVE_OFF 4 +#define HCI_LE_STATES_HI_DUTY_DIR_ADV_SLAVE_SUPPORTED(x) ((x)[HCI_SUPP_LE_STATES_HI_DUTY_DIR_ADV_SLAVE_OFF] & HCI_SUPP_LE_STATES_HI_DUTY_DIR_ADV_SLAVE_MASK) + +/* Low Duty Cycle Directed Advertising State and slave Role combination supported.*/ +#define HCI_SUPP_LE_STATES_LO_DUTY_DIR_ADV_SLAVE_MASK 0x01 +#define HCI_SUPP_LE_STATES_LO_DUTY_DIR_ADV_SLAVE_OFF 5 +#define HCI_LE_STATES_LO_DUTY_DIR_ADV_SLAVE_SUPPORTED(x) ((x)[HCI_SUPP_LE_STATES_LO_DUTY_DIR_ADV_SLAVE_OFF] & HCI_SUPP_LE_STATES_LO_DUTY_DIR_ADV_SLAVE_MASK) + +/* Initiating State and Slave Role combination supported. + Master Role and Slave Role combination also supported. + */ +#define HCI_SUPP_LE_STATES_INIT_MASTER_SLAVE_MASK 0x02 +#define HCI_SUPP_LE_STATES_INIT_MASTER_SLAVE_OFF 5 +#define HCI_LE_STATES_INIT_MASTER_SLAVE_SUPPORTED(x) ((x)[HCI_SUPP_LE_STATES_INIT_MASTER_SLAVE_OFF] & HCI_SUPP_LE_STATES_INIT_MASTER_SLAVE_MASK) + +/* +** Definitions for HCI Events +*/ +#define HCI_INQUIRY_COMP_EVT 0x01 +#define HCI_INQUIRY_RESULT_EVT 0x02 +#define HCI_CONNECTION_COMP_EVT 0x03 +#define HCI_CONNECTION_REQUEST_EVT 0x04 +#define HCI_DISCONNECTION_COMP_EVT 0x05 +#define HCI_AUTHENTICATION_COMP_EVT 0x06 +#define HCI_RMT_NAME_REQUEST_COMP_EVT 0x07 +#define HCI_ENCRYPTION_CHANGE_EVT 0x08 +#define HCI_CHANGE_CONN_LINK_KEY_EVT 0x09 +#define HCI_MASTER_LINK_KEY_COMP_EVT 0x0A +#define HCI_READ_RMT_FEATURES_COMP_EVT 0x0B +#define HCI_READ_RMT_VERSION_COMP_EVT 0x0C +#define HCI_QOS_SETUP_COMP_EVT 0x0D +#define HCI_COMMAND_COMPLETE_EVT 0x0E +#define HCI_COMMAND_STATUS_EVT 0x0F +#define HCI_HARDWARE_ERROR_EVT 0x10 +#define HCI_FLUSH_OCCURED_EVT 0x11 +#define HCI_ROLE_CHANGE_EVT 0x12 +#define HCI_NUM_COMPL_DATA_PKTS_EVT 0x13 +#define HCI_MODE_CHANGE_EVT 0x14 +#define HCI_RETURN_LINK_KEYS_EVT 0x15 +#define HCI_PIN_CODE_REQUEST_EVT 0x16 +#define HCI_LINK_KEY_REQUEST_EVT 0x17 +#define HCI_LINK_KEY_NOTIFICATION_EVT 0x18 +#define HCI_LOOPBACK_COMMAND_EVT 0x19 +#define HCI_DATA_BUF_OVERFLOW_EVT 0x1A +#define HCI_MAX_SLOTS_CHANGED_EVT 0x1B +#define HCI_READ_CLOCK_OFF_COMP_EVT 0x1C +#define HCI_CONN_PKT_TYPE_CHANGE_EVT 0x1D +#define HCI_QOS_VIOLATION_EVT 0x1E +#define HCI_PAGE_SCAN_MODE_CHANGE_EVT 0x1F +#define HCI_PAGE_SCAN_REP_MODE_CHNG_EVT 0x20 +#define HCI_FLOW_SPECIFICATION_COMP_EVT 0x21 +#define HCI_INQUIRY_RSSI_RESULT_EVT 0x22 +#define HCI_READ_RMT_EXT_FEATURES_COMP_EVT 0x23 +#define HCI_ESCO_CONNECTION_COMP_EVT 0x2C +#define HCI_ESCO_CONNECTION_CHANGED_EVT 0x2D +#define HCI_SNIFF_SUB_RATE_EVT 0x2E +#define HCI_EXTENDED_INQUIRY_RESULT_EVT 0x2F +#define HCI_ENCRYPTION_KEY_REFRESH_COMP_EVT 0x30 +#define HCI_IO_CAPABILITY_REQUEST_EVT 0x31 +#define HCI_IO_CAPABILITY_RESPONSE_EVT 0x32 +#define HCI_USER_CONFIRMATION_REQUEST_EVT 0x33 +#define HCI_USER_PASSKEY_REQUEST_EVT 0x34 +#define HCI_REMOTE_OOB_DATA_REQUEST_EVT 0x35 +#define HCI_SIMPLE_PAIRING_COMPLETE_EVT 0x36 +#define HCI_LINK_SUPER_TOUT_CHANGED_EVT 0x38 +#define HCI_ENHANCED_FLUSH_COMPLETE_EVT 0x39 +#define HCI_USER_PASSKEY_NOTIFY_EVT 0x3B +#define HCI_KEYPRESS_NOTIFY_EVT 0x3C +#define HCI_RMT_HOST_SUP_FEAT_NOTIFY_EVT 0x3D + +/*#define HCI_GENERIC_AMP_LINK_KEY_NOTIF_EVT 0x3E Removed from spec */ +#define HCI_PHYSICAL_LINK_COMP_EVT 0x40 +#define HCI_CHANNEL_SELECTED_EVT 0x41 +#define HCI_DISC_PHYSICAL_LINK_COMP_EVT 0x42 +#define HCI_PHY_LINK_LOSS_EARLY_WARNING_EVT 0x43 +#define HCI_PHY_LINK_RECOVERY_EVT 0x44 +#define HCI_LOGICAL_LINK_COMP_EVT 0x45 +#define HCI_DISC_LOGICAL_LINK_COMP_EVT 0x46 +#define HCI_FLOW_SPEC_MODIFY_COMP_EVT 0x47 +#define HCI_NUM_COMPL_DATA_BLOCKS_EVT 0x48 +#define HCI_SHORT_RANGE_MODE_COMPLETE_EVT 0x4C +#define HCI_AMP_STATUS_CHANGE_EVT 0x4D +#define HCI_SET_TRIGGERED_CLOCK_CAPTURE_EVT 0x4E + +/* ULP HCI Event */ +#define HCI_BLE_EVENT 0x3e +/* ULP Event sub code */ +#define HCI_BLE_CONN_COMPLETE_EVT 0x01 +#define HCI_BLE_ADV_PKT_RPT_EVT 0x02 +#define HCI_BLE_LL_CONN_PARAM_UPD_EVT 0x03 +#define HCI_BLE_READ_REMOTE_FEAT_CMPL_EVT 0x04 +#define HCI_BLE_LTK_REQ_EVT 0x05 +#define HCI_BLE_RC_PARAM_REQ_EVT 0x06 +#define HCI_BLE_DATA_LENGTH_CHANGE_EVT 0x07 +#define HCI_BLE_ENHANCED_CONN_COMPLETE_EVT 0x0a +#define HCI_BLE_DIRECT_ADV_EVT 0x0b + +/* Definitions for LE Channel Map */ +#define HCI_BLE_CHNL_MAP_SIZE 5 + +#define HCI_VENDOR_SPECIFIC_EVT 0xFF /* Vendor specific events */ +#define HCI_NAP_TRACE_EVT 0xFF /* was define 0xFE, 0xFD, change to 0xFF + because conflict w/ TCI_EVT and per + specification compliant */ + +/* +** Defentions for HCI Error Codes that are past in the events +*/ +#define HCI_SUCCESS 0x00 +#define HCI_PENDING 0x00 +#define HCI_ERR_ILLEGAL_COMMAND 0x01 +#define HCI_ERR_NO_CONNECTION 0x02 +#define HCI_ERR_HW_FAILURE 0x03 +#define HCI_ERR_PAGE_TIMEOUT 0x04 +#define HCI_ERR_AUTH_FAILURE 0x05 +#define HCI_ERR_KEY_MISSING 0x06 +#define HCI_ERR_MEMORY_FULL 0x07 +#define HCI_ERR_CONNECTION_TOUT 0x08 +#define HCI_ERR_MAX_NUM_OF_CONNECTIONS 0x09 +#define HCI_ERR_MAX_NUM_OF_SCOS 0x0A +#define HCI_ERR_CONNECTION_EXISTS 0x0B +#define HCI_ERR_COMMAND_DISALLOWED 0x0C +#define HCI_ERR_HOST_REJECT_RESOURCES 0x0D +#define HCI_ERR_HOST_REJECT_SECURITY 0x0E +#define HCI_ERR_HOST_REJECT_DEVICE 0x0F +#define HCI_ERR_HOST_TIMEOUT 0x10 +#define HCI_ERR_UNSUPPORTED_VALUE 0x11 +#define HCI_ERR_ILLEGAL_PARAMETER_FMT 0x12 +#define HCI_ERR_PEER_USER 0x13 +#define HCI_ERR_PEER_LOW_RESOURCES 0x14 +#define HCI_ERR_PEER_POWER_OFF 0x15 +#define HCI_ERR_CONN_CAUSE_LOCAL_HOST 0x16 +#define HCI_ERR_REPEATED_ATTEMPTS 0x17 +#define HCI_ERR_PAIRING_NOT_ALLOWED 0x18 +#define HCI_ERR_UNKNOWN_LMP_PDU 0x19 +#define HCI_ERR_UNSUPPORTED_REM_FEATURE 0x1A +#define HCI_ERR_SCO_OFFSET_REJECTED 0x1B +#define HCI_ERR_SCO_INTERVAL_REJECTED 0x1C +#define HCI_ERR_SCO_AIR_MODE 0x1D +#define HCI_ERR_INVALID_LMP_PARAM 0x1E +#define HCI_ERR_UNSPECIFIED 0x1F +#define HCI_ERR_UNSUPPORTED_LMP_FEATURE 0x20 +#define HCI_ERR_ROLE_CHANGE_NOT_ALLOWED 0x21 +#define HCI_ERR_LMP_RESPONSE_TIMEOUT 0x22 +#define HCI_ERR_LMP_ERR_TRANS_COLLISION 0x23 +#define HCI_ERR_LMP_PDU_NOT_ALLOWED 0x24 +#define HCI_ERR_ENCRY_MODE_NOT_ACCEPTABLE 0x25 +#define HCI_ERR_UNIT_KEY_USED 0x26 +#define HCI_ERR_QOS_NOT_SUPPORTED 0x27 +#define HCI_ERR_INSTANT_PASSED 0x28 +#define HCI_ERR_PAIRING_WITH_UNIT_KEY_NOT_SUPPORTED 0x29 +#define HCI_ERR_DIFF_TRANSACTION_COLLISION 0x2A +#define HCI_ERR_UNDEFINED_0x2B 0x2B +#define HCI_ERR_QOS_UNACCEPTABLE_PARAM 0x2C +#define HCI_ERR_QOS_REJECTED 0x2D +#define HCI_ERR_CHAN_CLASSIF_NOT_SUPPORTED 0x2E +#define HCI_ERR_INSUFFCIENT_SECURITY 0x2F +#define HCI_ERR_PARAM_OUT_OF_RANGE 0x30 +#define HCI_ERR_UNDEFINED_0x31 0x31 +#define HCI_ERR_ROLE_SWITCH_PENDING 0x32 +#define HCI_ERR_UNDEFINED_0x33 0x33 +#define HCI_ERR_RESERVED_SLOT_VIOLATION 0x34 +#define HCI_ERR_ROLE_SWITCH_FAILED 0x35 +#define HCI_ERR_INQ_RSP_DATA_TOO_LARGE 0x36 +#define HCI_ERR_SIMPLE_PAIRING_NOT_SUPPORTED 0x37 +#define HCI_ERR_HOST_BUSY_PAIRING 0x38 +#define HCI_ERR_REJ_NO_SUITABLE_CHANNEL 0x39 +#define HCI_ERR_CONTROLLER_BUSY 0x3A +#define HCI_ERR_UNACCEPT_CONN_INTERVAL 0x3B +#define HCI_ERR_DIRECTED_ADVERTISING_TIMEOUT 0x3C +#define HCI_ERR_CONN_TOUT_DUE_TO_MIC_FAILURE 0x3D +#define HCI_ERR_CONN_FAILED_ESTABLISHMENT 0x3E +#define HCI_ERR_MAC_CONNECTION_FAILED 0x3F + +/* ConnectionLess Broadcast errors */ +#define HCI_ERR_LT_ADDR_ALREADY_IN_USE 0x40 +#define HCI_ERR_LT_ADDR_NOT_ALLOCATED 0x41 +#define HCI_ERR_CLB_NOT_ENABLED 0x42 +#define HCI_ERR_CLB_DATA_TOO_BIG 0x43 + +#define HCI_ERR_MAX_ERR 0x43 + +#define HCI_HINT_TO_RECREATE_AMP_PHYS_LINK 0xFF + +/* +** Definitions for HCI enable event +*/ +#define HCI_INQUIRY_COMPLETE_EV(p) (*((UINT32 *)(p)) & 0x00000001) +#define HCI_INQUIRY_RESULT_EV(p) (*((UINT32 *)(p)) & 0x00000002) +#define HCI_CONNECTION_COMPLETE_EV(p) (*((UINT32 *)(p)) & 0x00000004) +#define HCI_CONNECTION_REQUEST_EV(p) (*((UINT32 *)(p)) & 0x00000008) +#define HCI_DISCONNECTION_COMPLETE_EV(p) (*((UINT32 *)(p)) & 0x00000010) +#define HCI_AUTHENTICATION_COMPLETE_EV(p) (*((UINT32 *)(p)) & 0x00000020) +#define HCI_RMT_NAME_REQUEST_COMPL_EV(p) (*((UINT32 *)(p)) & 0x00000040) +#define HCI_CHANGE_CONN_ENCRPT_ENABLE_EV(p) (*((UINT32 *)(p)) & 0x00000080) +#define HCI_CHANGE_CONN_LINK_KEY_EV(p) (*((UINT32 *)(p)) & 0x00000100) +#define HCI_MASTER_LINK_KEY_COMPLETE_EV(p) (*((UINT32 *)(p)) & 0x00000200) +#define HCI_READ_RMT_FEATURES_COMPL_EV(p) (*((UINT32 *)(p)) & 0x00000400) +#define HCI_READ_RMT_VERSION_COMPL_EV(p) (*((UINT32 *)(p)) & 0x00000800) +#define HCI_QOS_SETUP_COMPLETE_EV(p) (*((UINT32 *)(p)) & 0x00001000) +#define HCI_COMMAND_COMPLETE_EV(p) (*((UINT32 *)(p)) & 0x00002000) +#define HCI_COMMAND_STATUS_EV(p) (*((UINT32 *)(p)) & 0x00004000) +#define HCI_HARDWARE_ERROR_EV(p) (*((UINT32 *)(p)) & 0x00008000) +#define HCI_FLASH_OCCURED_EV(p) (*((UINT32 *)(p)) & 0x00010000) +#define HCI_ROLE_CHANGE_EV(p) (*((UINT32 *)(p)) & 0x00020000) +#define HCI_NUM_COMPLETED_PKTS_EV(p) (*((UINT32 *)(p)) & 0x00040000) +#define HCI_MODE_CHANGE_EV(p) (*((UINT32 *)(p)) & 0x00080000) +#define HCI_RETURN_LINK_KEYS_EV(p) (*((UINT32 *)(p)) & 0x00100000) +#define HCI_PIN_CODE_REQUEST_EV(p) (*((UINT32 *)(p)) & 0x00200000) +#define HCI_LINK_KEY_REQUEST_EV(p) (*((UINT32 *)(p)) & 0x00400000) +#define HCI_LINK_KEY_NOTIFICATION_EV(p) (*((UINT32 *)(p)) & 0x00800000) +#define HCI_LOOPBACK_COMMAND_EV(p) (*((UINT32 *)(p)) & 0x01000000) +#define HCI_DATA_BUF_OVERFLOW_EV(p) (*((UINT32 *)(p)) & 0x02000000) +#define HCI_MAX_SLOTS_CHANGE_EV(p) (*((UINT32 *)(p)) & 0x04000000) +#define HCI_READ_CLOCK_OFFSET_COMP_EV(p) (*((UINT32 *)(p)) & 0x08000000) +#define HCI_CONN_PKT_TYPE_CHANGED_EV(p) (*((UINT32 *)(p)) & 0x10000000) +#define HCI_QOS_VIOLATION_EV(p) (*((UINT32 *)(p)) & 0x20000000) +#define HCI_PAGE_SCAN_MODE_CHANGED_EV(p) (*((UINT32 *)(p)) & 0x40000000) +#define HCI_PAGE_SCAN_REP_MODE_CHNG_EV(p) (*((UINT32 *)(p)) & 0x80000000) + +/* the default event mask for 2.1+EDR (Lisbon) does not include Lisbon events */ +#define HCI_DEFAULT_EVENT_MASK_0 0xFFFFFFFF +#define HCI_DEFAULT_EVENT_MASK_1 0x00001FFF + +/* the event mask for 2.0 + EDR and later (includes Lisbon events) */ +#define HCI_LISBON_EVENT_MASK_0 0xFFFFFFFF +#define HCI_LISBON_EVENT_MASK_1 0x1DBFFFFF +#define HCI_LISBON_EVENT_MASK "\x0D\xBF\xFF\xFF\xFF\xFF\xFF\xFF" +#define HCI_LISBON_EVENT_MASK_EXT "\x1D\xBF\xFF\xFF\xFF\xFF\xFF\xFF" +#define HCI_DUMO_EVENT_MASK_EXT "\x3D\xBF\xFF\xFF\xFF\xFF\xFF\xFF" +/* 0x00001FFF FFFFFFFF Default - no Lisbon events + 0x00000800 00000000 Synchronous Connection Complete Event + 0x00001000 00000000 Synchronous Connection Changed Event + 0x00002000 00000000 Sniff Subrate Event + 0x00004000 00000000 Extended Inquiry Result Event + 0x00008000 00000000 Encryption Key Refresh Complete Event + 0x00010000 00000000 IO Capability Request Event + 0x00020000 00000000 IO Capability Response Event + 0x00040000 00000000 User Confirmation Request Event + 0x00080000 00000000 User Passkey Request Event + 0x00100000 00000000 Remote OOB Data Request Event + 0x00200000 00000000 Simple Pairing Complete Event + 0x00400000 00000000 Generic AMP Link Key Notification Event + 0x00800000 00000000 Link Supervision Timeout Changed Event + 0x01000000 00000000 Enhanced Flush Complete Event + 0x04000000 00000000 User Passkey Notification Event + 0x08000000 00000000 Keypress Notification Event + 0x10000000 00000000 Remote Host Supported Features Notification Event + 0x20000000 00000000 LE Meta Event + */ + + +/* the event mask for AMP controllers */ +#define HCI_AMP_EVENT_MASK_3_0 "\x00\x00\x00\x00\x00\x00\x3F\xFF" + +/* 0x0000000000000000 No events specified (default) + 0x0000000000000001 Physical Link Complete Event + 0x0000000000000002 Channel Selected Event + 0x0000000000000004 Disconnection Physical Link Event + 0x0000000000000008 Physical Link Loss Early Warning Event + 0x0000000000000010 Physical Link Recovery Event + 0x0000000000000020 Logical Link Complete Event + 0x0000000000000040 Disconnection Logical Link Complete Event + 0x0000000000000080 Flow Spec Modify Complete Event + 0x0000000000000100 Number of Completed Data Blocks Event + 0x0000000000000200 AMP Start Test Event + 0x0000000000000400 AMP Test End Event + 0x0000000000000800 AMP Receiver Report Event + 0x0000000000001000 Short Range Mode Change Complete Event + 0x0000000000002000 AMP Status Change Event +*/ + +/* the event mask page 2 (CLB + CSA4) for BR/EDR controller */ +#define HCI_PAGE_2_EVENT_MASK "\x00\x00\x00\x00\x00\x7F\xC0\x00" +/* 0x0000000000004000 Triggered Clock Capture Event + 0x0000000000008000 Sync Train Complete Event + 0x0000000000010000 Sync Train Received Event + 0x0000000000020000 Connectionless Broadcast Receive Event + 0x0000000000040000 Connectionless Broadcast Timeout Event + 0x0000000000080000 Truncated Page Complete Event + 0x0000000000100000 Salve Page Response Timeout Event + 0x0000000000200000 Connectionless Broadcast Channel Map Change Event + 0x0000000000400000 Inquiry Response Notification Event +*/ +#if BLE_PRIVACY_SPT == TRUE +/* BLE event mask */ +#define HCI_BLE_EVENT_MASK_DEF "\x00\x00\x00\x00\x00\x00\x07\xff" +#else +#define HCI_BLE_EVENT_MASK_DEF "\x00\x00\x00\x00\x00\x00\x00\x7f" +#endif +/* +** Definitions for packet type masks (BT1.2 and BT2.0 definitions) +*/ +#define HCI_PKT_TYPES_MASK_NO_2_DH1 0x0002 +#define HCI_PKT_TYPES_MASK_NO_3_DH1 0x0004 +#define HCI_PKT_TYPES_MASK_DM1 0x0008 +#define HCI_PKT_TYPES_MASK_DH1 0x0010 +#define HCI_PKT_TYPES_MASK_HV1 0x0020 +#define HCI_PKT_TYPES_MASK_HV2 0x0040 +#define HCI_PKT_TYPES_MASK_HV3 0x0080 +#define HCI_PKT_TYPES_MASK_NO_2_DH3 0x0100 +#define HCI_PKT_TYPES_MASK_NO_3_DH3 0x0200 +#define HCI_PKT_TYPES_MASK_DM3 0x0400 +#define HCI_PKT_TYPES_MASK_DH3 0x0800 +#define HCI_PKT_TYPES_MASK_NO_2_DH5 0x1000 +#define HCI_PKT_TYPES_MASK_NO_3_DH5 0x2000 +#define HCI_PKT_TYPES_MASK_DM5 0x4000 +#define HCI_PKT_TYPES_MASK_DH5 0x8000 + +/* Packet type should be one of valid but at least one should be specified */ +#define HCI_VALID_SCO_PKT_TYPE(t) (((((t) & ~(HCI_PKT_TYPES_MASK_HV1 \ + | HCI_PKT_TYPES_MASK_HV2 \ + | HCI_PKT_TYPES_MASK_HV3)) == 0)) \ + && ((t) != 0)) + + + + + +/* Packet type should not be invalid and at least one should be specified */ +#define HCI_VALID_ACL_PKT_TYPE(t) (((((t) & ~(HCI_PKT_TYPES_MASK_DM1 \ + | HCI_PKT_TYPES_MASK_DH1 \ + | HCI_PKT_TYPES_MASK_DM3 \ + | HCI_PKT_TYPES_MASK_DH3 \ + | HCI_PKT_TYPES_MASK_DM5 \ + | HCI_PKT_TYPES_MASK_DH5 \ + | HCI_PKT_TYPES_MASK_NO_2_DH1 \ + | HCI_PKT_TYPES_MASK_NO_3_DH1 \ + | HCI_PKT_TYPES_MASK_NO_2_DH3 \ + | HCI_PKT_TYPES_MASK_NO_3_DH3 \ + | HCI_PKT_TYPES_MASK_NO_2_DH5 \ + | HCI_PKT_TYPES_MASK_NO_3_DH5 )) == 0)) \ + && (((t) & (HCI_PKT_TYPES_MASK_DM1 \ + | HCI_PKT_TYPES_MASK_DH1 \ + | HCI_PKT_TYPES_MASK_DM3 \ + | HCI_PKT_TYPES_MASK_DH3 \ + | HCI_PKT_TYPES_MASK_DM5 \ + | HCI_PKT_TYPES_MASK_DH5)) != 0)) + +/* +** Definitions for eSCO packet type masks (BT1.2 and BT2.0 definitions) +*/ +#define HCI_ESCO_PKT_TYPES_MASK_HV1 0x0001 +#define HCI_ESCO_PKT_TYPES_MASK_HV2 0x0002 +#define HCI_ESCO_PKT_TYPES_MASK_HV3 0x0004 +#define HCI_ESCO_PKT_TYPES_MASK_EV3 0x0008 +#define HCI_ESCO_PKT_TYPES_MASK_EV4 0x0010 +#define HCI_ESCO_PKT_TYPES_MASK_EV5 0x0020 +#define HCI_ESCO_PKT_TYPES_MASK_NO_2_EV3 0x0040 +#define HCI_ESCO_PKT_TYPES_MASK_NO_3_EV3 0x0080 +#define HCI_ESCO_PKT_TYPES_MASK_NO_2_EV5 0x0100 +#define HCI_ESCO_PKT_TYPES_MASK_NO_3_EV5 0x0200 + +/* Packet type should be one of valid but at least one should be specified for 1.2 */ +#define HCI_VALID_ESCO_PKT_TYPE(t) (((((t) & ~(HCI_ESCO_PKT_TYPES_MASK_EV3 \ + | HCI_ESCO_PKT_TYPES_MASK_EV4 \ + | HCI_ESCO_PKT_TYPES_MASK_EV5)) == 0)) \ + && ((t) != 0))/* Packet type should be one of valid but at least one should be specified */ + +#define HCI_VALID_ESCO_SCOPKT_TYPE(t) (((((t) & ~(HCI_ESCO_PKT_TYPES_MASK_HV1 \ + | HCI_ESCO_PKT_TYPES_MASK_HV2 \ + | HCI_ESCO_PKT_TYPES_MASK_HV3)) == 0)) \ + && ((t) != 0)) + +#define HCI_VALID_SCO_ALL_PKT_TYPE(t) (((((t) & ~(HCI_ESCO_PKT_TYPES_MASK_HV1 \ + | HCI_ESCO_PKT_TYPES_MASK_HV2 \ + | HCI_ESCO_PKT_TYPES_MASK_HV3 \ + | HCI_ESCO_PKT_TYPES_MASK_EV3 \ + | HCI_ESCO_PKT_TYPES_MASK_EV4 \ + | HCI_ESCO_PKT_TYPES_MASK_EV5)) == 0)) \ + && ((t) != 0)) + +/* +** Define parameters to allow role switch during create connection +*/ +#define HCI_CR_CONN_NOT_ALLOW_SWITCH 0x00 +#define HCI_CR_CONN_ALLOW_SWITCH 0x01 + +/* +** Hold Mode command destination +*/ +#define HOLD_MODE_DEST_LOCAL_DEVICE 0x00 +#define HOLD_MODE_DEST_RMT_DEVICE 0x01 + +/* +** Definitions for different HCI parameters +*/ +#define HCI_PER_INQ_MIN_MAX_PERIOD 0x0003 +#define HCI_PER_INQ_MAX_MAX_PERIOD 0xFFFF +#define HCI_PER_INQ_MIN_MIN_PERIOD 0x0002 +#define HCI_PER_INQ_MAX_MIN_PERIOD 0xFFFE + +#define HCI_MAX_INQUIRY_LENGTH 0x30 + +#define HCI_MIN_INQ_LAP 0x9E8B00 +#define HCI_MAX_INQ_LAP 0x9E8B3F + +/* HCI role defenitions */ +#define HCI_ROLE_MASTER 0x00 +#define HCI_ROLE_SLAVE 0x01 +#define HCI_ROLE_UNKNOWN 0xff + +/* HCI mode defenitions */ +#define HCI_MODE_ACTIVE 0x00 +#define HCI_MODE_HOLD 0x01 +#define HCI_MODE_SNIFF 0x02 +#define HCI_MODE_PARK 0x03 + +/* HCI Flow Control Mode defenitions */ +#define HCI_PACKET_BASED_FC_MODE 0x00 +#define HCI_BLOCK_BASED_FC_MODE 0x01 + +/* Define Packet types as requested by the Host */ +#define HCI_ACL_PKT_TYPE_NONE 0x0000 +#define HCI_ACL_PKT_TYPE_DM1 0x0008 +#define HCI_ACL_PKT_TYPE_DH1 0x0010 +#define HCI_ACL_PKT_TYPE_AUX1 0x0200 +#define HCI_ACL_PKT_TYPE_DM3 0x0400 +#define HCI_ACL_PKT_TYPE_DH3 0x0800 +#define HCI_ACL_PKT_TYPE_DM5 0x4000 +#define HCI_ACL_PKT_TYPE_DH5 0x8000 + +/* Define key type in the Master Link Key command */ +#define HCI_USE_SEMI_PERMANENT_KEY 0x00 +#define HCI_USE_TEMPORARY_KEY 0x01 + +/* Page scan period modes */ +#define HCI_PAGE_SCAN_REP_MODE_R0 0x00 +#define HCI_PAGE_SCAN_REP_MODE_R1 0x01 +#define HCI_PAGE_SCAN_REP_MODE_R2 0x02 + +/* Define limits for page scan repetition modes */ +#define HCI_PAGE_SCAN_R1_LIMIT 0x0800 +#define HCI_PAGE_SCAN_R2_LIMIT 0x1000 + +/* Page scan period modes */ +#define HCI_PAGE_SCAN_PER_MODE_P0 0x00 +#define HCI_PAGE_SCAN_PER_MODE_P1 0x01 +#define HCI_PAGE_SCAN_PER_MODE_P2 0x02 + +/* Page scan modes */ +#define HCI_MANDATARY_PAGE_SCAN_MODE 0x00 +#define HCI_OPTIONAL_PAGE_SCAN_MODE1 0x01 +#define HCI_OPTIONAL_PAGE_SCAN_MODE2 0x02 +#define HCI_OPTIONAL_PAGE_SCAN_MODE3 0x03 + +/* Page and inquiry scan types */ +#define HCI_SCAN_TYPE_STANDARD 0x00 +#define HCI_SCAN_TYPE_INTERLACED 0x01 /* 1.2 devices or later */ +#define HCI_DEF_SCAN_TYPE HCI_SCAN_TYPE_STANDARD + +/* Definitions for quality of service service types */ +#define HCI_SERVICE_NO_TRAFFIC 0x00 +#define HCI_SERVICE_BEST_EFFORT 0x01 +#define HCI_SERVICE_GUARANTEED 0x02 + +#define HCI_QOS_LATENCY_DO_NOT_CARE 0xFFFFFFFF +#define HCI_QOS_DELAY_DO_NOT_CARE 0xFFFFFFFF + +/* Definitions for Flow Specification */ +#define HCI_FLOW_SPEC_LATENCY_DO_NOT_CARE 0xFFFFFFFF + +/* Definitions for AFH Channel Map */ +#define HCI_AFH_CHANNEL_MAP_LEN 10 + +/* Definitions for Extended Inquiry Response */ +#define HCI_EXT_INQ_RESPONSE_LEN 240 +#define HCI_EIR_FLAGS_TYPE BT_EIR_FLAGS_TYPE +#define HCI_EIR_MORE_16BITS_UUID_TYPE BT_EIR_MORE_16BITS_UUID_TYPE +#define HCI_EIR_COMPLETE_16BITS_UUID_TYPE BT_EIR_COMPLETE_16BITS_UUID_TYPE +#define HCI_EIR_MORE_32BITS_UUID_TYPE BT_EIR_MORE_32BITS_UUID_TYPE +#define HCI_EIR_COMPLETE_32BITS_UUID_TYPE BT_EIR_COMPLETE_32BITS_UUID_TYPE +#define HCI_EIR_MORE_128BITS_UUID_TYPE BT_EIR_MORE_128BITS_UUID_TYPE +#define HCI_EIR_COMPLETE_128BITS_UUID_TYPE BT_EIR_COMPLETE_128BITS_UUID_TYPE +#define HCI_EIR_SHORTENED_LOCAL_NAME_TYPE BT_EIR_SHORTENED_LOCAL_NAME_TYPE +#define HCI_EIR_COMPLETE_LOCAL_NAME_TYPE BT_EIR_COMPLETE_LOCAL_NAME_TYPE +#define HCI_EIR_TX_POWER_LEVEL_TYPE BT_EIR_TX_POWER_LEVEL_TYPE +#define HCI_EIR_MANUFACTURER_SPECIFIC_TYPE BT_EIR_MANUFACTURER_SPECIFIC_TYPE +#define HCI_EIR_OOB_BD_ADDR_TYPE BT_EIR_OOB_BD_ADDR_TYPE +#define HCI_EIR_OOB_COD_TYPE BT_EIR_OOB_COD_TYPE +#define HCI_EIR_OOB_SSP_HASH_C_TYPE BT_EIR_OOB_SSP_HASH_C_TYPE +#define HCI_EIR_OOB_SSP_RAND_R_TYPE BT_EIR_OOB_SSP_RAND_R_TYPE + +/* Definitions for Write Simple Pairing Mode */ +#define HCI_SP_MODE_UNDEFINED 0x00 +#define HCI_SP_MODE_ENABLED 0x01 + +/* Definitions for Write Simple Pairing Debug Mode */ +#define HCI_SPD_MODE_DISABLED 0x00 +#define HCI_SPD_MODE_ENABLED 0x01 + +/* Definitions for Write Secure Connections Host Support */ +#define HCI_SC_MODE_DISABLED 0x00 +#define HCI_SC_MODE_ENABLED 0x01 + +/* Definitions for IO Capability Response/Command */ +#define HCI_IO_CAP_DISPLAY_ONLY 0x00 +#define HCI_IO_CAP_DISPLAY_YESNO 0x01 +#define HCI_IO_CAP_KEYBOARD_ONLY 0x02 +#define HCI_IO_CAP_NO_IO 0x03 + +#define HCI_OOB_AUTH_DATA_NOT_PRESENT 0x00 +#define HCI_OOB_REM_AUTH_DATA_PRESENT 0x01 + +#define HCI_MITM_PROTECT_NOT_REQUIRED 0x00 +#define HCI_MITM_PROTECT_REQUIRED 0x01 + + +/* Policy settings status */ +#define HCI_DISABLE_ALL_LM_MODES 0x0000 +#define HCI_ENABLE_MASTER_SLAVE_SWITCH 0x0001 +#define HCI_ENABLE_HOLD_MODE 0x0002 +#define HCI_ENABLE_SNIFF_MODE 0x0004 +#define HCI_ENABLE_PARK_MODE 0x0008 + +/* By default allow switch, because host can not allow that */ +/* that until he created the connection */ +#define HCI_DEFAULT_POLICY_SETTINGS HCI_DISABLE_ALL_LM_MODES + +/* Filters that are sent in set filter command */ +#define HCI_FILTER_TYPE_CLEAR_ALL 0x00 +#define HCI_FILTER_INQUIRY_RESULT 0x01 +#define HCI_FILTER_CONNECTION_SETUP 0x02 + +#define HCI_FILTER_COND_NEW_DEVICE 0x00 +#define HCI_FILTER_COND_DEVICE_CLASS 0x01 +#define HCI_FILTER_COND_BD_ADDR 0x02 + +#define HCI_DO_NOT_AUTO_ACCEPT_CONNECT 1 +#define HCI_DO_AUTO_ACCEPT_CONNECT 2 /* role switch disabled */ +#define HCI_DO_AUTO_ACCEPT_CONNECT_RS 3 /* role switch enabled (1.1 errata 1115) */ + +/* Auto accept flags */ +#define HCI_AUTO_ACCEPT_OFF 0x00 +#define HCI_AUTO_ACCEPT_ACL_CONNECTIONS 0x01 +#define HCI_AUTO_ACCEPT_SCO_CONNECTIONS 0x02 + +/* PIN type */ +#define HCI_PIN_TYPE_VARIABLE 0 +#define HCI_PIN_TYPE_FIXED 1 + +/* Loopback Modes */ +#define HCI_LOOPBACK_MODE_DISABLED 0 +#define HCI_LOOPBACK_MODE_LOCAL 1 +#define HCI_LOOPBACK_MODE_REMOTE 2 + +#define SLOTS_PER_10MS 16 /* 0.625 ms slots in a 10 ms tick */ + +/* Maximum connection accept timeout in 0.625msec */ +#define HCI_MAX_CONN_ACCEPT_TOUT 0xB540 /* 29 sec */ +#define HCI_DEF_CONN_ACCEPT_TOUT 0x1F40 /* 5 sec */ + +/* Page timeout is used in LC only and LC is counting down slots not using OS */ +#define HCI_DEFAULT_PAGE_TOUT 0x2000 /* 5.12 sec (in slots) */ + +/* Scan enable flags */ +#define HCI_NO_SCAN_ENABLED 0x00 +#define HCI_INQUIRY_SCAN_ENABLED 0x01 +#define HCI_PAGE_SCAN_ENABLED 0x02 + +/* Pagescan timer definitions in 0.625 ms */ +#define HCI_MIN_PAGESCAN_INTERVAL 0x12 /* 11.25 ms */ +#define HCI_MAX_PAGESCAN_INTERVAL 0x1000 /* 2.56 sec */ +#define HCI_DEF_PAGESCAN_INTERVAL 0x0800 /* 1.28 sec */ + +/* Parameter for pagescan window is passed to LC and is kept in slots */ +#define HCI_MIN_PAGESCAN_WINDOW 0x11 /* 10.625 ms */ +#define HCI_MAX_PAGESCAN_WINDOW 0x1000 /* 2.56 sec */ +#define HCI_DEF_PAGESCAN_WINDOW 0x12 /* 11.25 ms */ + +/* Inquiryscan timer definitions in 0.625 ms */ +#define HCI_MIN_INQUIRYSCAN_INTERVAL 0x12 /* 11.25 ms */ +#define HCI_MAX_INQUIRYSCAN_INTERVAL 0x1000 /* 2.56 sec */ +#define HCI_DEF_INQUIRYSCAN_INTERVAL 0x1000 /* 2.56 sec */ + +/* Parameter for inquiryscan window is passed to LC and is kept in slots */ +#define HCI_MIN_INQUIRYSCAN_WINDOW 0x11 /* 10.625 ms */ +#define HCI_MAX_INQUIRYSCAN_WINDOW 0x1000 /* 2.56 sec */ +#define HCI_DEF_INQUIRYSCAN_WINDOW 0x12 /* 11.25 ms */ + +/* Encryption modes */ +#define HCI_ENCRYPT_MODE_DISABLED 0x00 +#define HCI_ENCRYPT_MODE_POINT_TO_POINT 0x01 +#define HCI_ENCRYPT_MODE_ALL 0x02 + +/* Voice settings */ +#define HCI_INP_CODING_LINEAR 0x0000 /* 0000000000 */ +#define HCI_INP_CODING_U_LAW 0x0100 /* 0100000000 */ +#define HCI_INP_CODING_A_LAW 0x0200 /* 1000000000 */ +#define HCI_INP_CODING_MASK 0x0300 /* 1100000000 */ + +#define HCI_INP_DATA_FMT_1S_COMPLEMENT 0x0000 /* 0000000000 */ +#define HCI_INP_DATA_FMT_2S_COMPLEMENT 0x0040 /* 0001000000 */ +#define HCI_INP_DATA_FMT_SIGN_MAGNITUDE 0x0080 /* 0010000000 */ +#define HCI_INP_DATA_FMT_UNSIGNED 0x00c0 /* 0011000000 */ +#define HCI_INP_DATA_FMT_MASK 0x00c0 /* 0011000000 */ + +#define HCI_INP_SAMPLE_SIZE_8BIT 0x0000 /* 0000000000 */ +#define HCI_INP_SAMPLE_SIZE_16BIT 0x0020 /* 0000100000 */ +#define HCI_INP_SAMPLE_SIZE_MASK 0x0020 /* 0000100000 */ + +#define HCI_INP_LINEAR_PCM_BIT_POS_MASK 0x001c /* 0000011100 */ +#define HCI_INP_LINEAR_PCM_BIT_POS_OFFS 2 + +#define HCI_AIR_CODING_FORMAT_CVSD 0x0000 /* 0000000000 */ +#define HCI_AIR_CODING_FORMAT_U_LAW 0x0001 /* 0000000001 */ +#define HCI_AIR_CODING_FORMAT_A_LAW 0x0002 /* 0000000010 */ +#define HCI_AIR_CODING_FORMAT_TRANSPNT 0x0003 /* 0000000011 */ +#define HCI_AIR_CODING_FORMAT_MASK 0x0003 /* 0000000011 */ + +/* default 0001100000 */ +#define HCI_DEFAULT_VOICE_SETTINGS (HCI_INP_CODING_LINEAR \ + | HCI_INP_DATA_FMT_2S_COMPLEMENT \ + | HCI_INP_SAMPLE_SIZE_16BIT \ + | HCI_AIR_CODING_FORMAT_CVSD) + +#define HCI_CVSD_SUPPORTED(x) (((x) & HCI_AIR_CODING_FORMAT_MASK) == HCI_AIR_CODING_FORMAT_CVSD) +#define HCI_U_LAW_SUPPORTED(x) (((x) & HCI_AIR_CODING_FORMAT_MASK) == HCI_AIR_CODING_FORMAT_U_LAW) +#define HCI_A_LAW_SUPPORTED(x) (((x) & HCI_AIR_CODING_FORMAT_MASK) == HCI_AIR_CODING_FORMAT_A_LAW) +#define HCI_TRANSPNT_SUPPORTED(x) (((x) & HCI_AIR_CODING_FORMAT_MASK) == HCI_AIR_CODING_FORMAT_TRANSPNT) + +/* Retransmit timer definitions in 0.625 */ +#define HCI_MAX_AUTO_FLUSH_TOUT 0x07FF +#define HCI_DEFAULT_AUTO_FLUSH_TOUT 0 /* No auto flush */ + +/* Broadcast retransmitions */ +#define HCI_DEFAULT_NUM_BCAST_RETRAN 1 + +/* Define broadcast data types as passed in the hci data packet */ +#define HCI_DATA_POINT_TO_POINT 0x00 +#define HCI_DATA_ACTIVE_BCAST 0x01 +#define HCI_DATA_PICONET_BCAST 0x02 + +/* Hold mode activity */ +#define HCI_MAINTAIN_CUR_POWER_STATE 0x00 +#define HCI_SUSPEND_PAGE_SCAN 0x01 +#define HCI_SUSPEND_INQUIRY_SCAN 0x02 +#define HCI_SUSPEND_PERIODIC_INQUIRIES 0x04 + +/* Default Link Supervision timeoout */ +#define HCI_DEFAULT_INACT_TOUT 0x7D00 /* BR/EDR (20 seconds) */ +#define HCI_DEFAULT_AMP_INACT_TOUT 0x3E80 /* AMP (10 seconds) */ + +/* Read transmit power level parameter */ +#define HCI_READ_CURRENT 0x00 +#define HCI_READ_MAXIMUM 0x01 + +/* Link types for connection complete event */ +#define HCI_LINK_TYPE_SCO 0x00 +#define HCI_LINK_TYPE_ACL 0x01 +#define HCI_LINK_TYPE_ESCO 0x02 + +/* Link Key Notification Event (Key Type) definitions */ +#define HCI_LKEY_TYPE_COMBINATION 0x00 +#define HCI_LKEY_TYPE_LOCAL_UNIT 0x01 +#define HCI_LKEY_TYPE_REMOTE_UNIT 0x02 +#define HCI_LKEY_TYPE_DEBUG_COMB 0x03 +#define HCI_LKEY_TYPE_UNAUTH_COMB 0x04 +#define HCI_LKEY_TYPE_AUTH_COMB 0x05 +#define HCI_LKEY_TYPE_CHANGED_COMB 0x06 +#define HCI_LKEY_TYPE_UNAUTH_COMB_P_256 0x07 +#define HCI_LKEY_TYPE_AUTH_COMB_P_256 0x08 + +/* Internal definitions - not used over HCI */ +#define HCI_LKEY_TYPE_AMP_WIFI 0x80 +#define HCI_LKEY_TYPE_AMP_UWB 0x81 +#define HCI_LKEY_TYPE_UNKNOWN 0xff + +/* Read Local Version HCI Version return values (Command Complete Event) */ +#define HCI_VERSION_1_0B 0x00 +#define HCI_VERSION_1_1 0x01 + +/* Define an invalid value for a handle */ +#define HCI_INVALID_HANDLE 0xFFFF + +/* Define max ammount of data in the HCI command */ +#define HCI_COMMAND_SIZE 255 + +/* Define the preamble length for all HCI Commands. +** This is 2-bytes for opcode and 1 byte for length +*/ +#define HCIC_PREAMBLE_SIZE 3 + +/* Define the preamble length for all HCI Events +** This is 1-byte for opcode and 1 byte for length +*/ +#define HCIE_PREAMBLE_SIZE 2 +#define HCI_SCO_PREAMBLE_SIZE 3 +#define HCI_DATA_PREAMBLE_SIZE 4 + +/* local Bluetooth controller id for AMP HCI */ +#define LOCAL_BR_EDR_CONTROLLER_ID 0 + +/* controller id types for AMP HCI */ +#define HCI_CONTROLLER_TYPE_BR_EDR 0 +#define HCI_CONTROLLER_TYPE_802_11 1 +#define HCI_CONTROLLER_TYPE_ECMA 2 +#define HCI_MAX_CONTROLLER_TYPES 3 + +/* ConnectionLess Broadcast */ +#define HCI_CLB_DISABLE 0x00 +#define HCI_CLB_ENABLE 0x01 + +/* ConnectionLess Broadcast Data fragment */ +#define HCI_CLB_FRAGMENT_CONT 0x00 +#define HCI_CLB_FRAGMENT_START 0x01 +#define HCI_CLB_FRAGMENT_END 0x02 +#define HCI_CLB_FRAGMENT_SINGLE 0x03 + +/* AMP Controller Status codes +*/ +#define HCI_AMP_CTRLR_PHYSICALLY_DOWN 0 +#define HCI_AMP_CTRLR_USABLE_BY_BT 1 +#define HCI_AMP_CTRLR_UNUSABLE_FOR_BT 2 +#define HCI_AMP_CTRLR_LOW_CAP_FOR_BT 3 +#define HCI_AMP_CTRLR_MED_CAP_FOR_BT 4 +#define HCI_AMP_CTRLR_HIGH_CAP_FOR_BT 5 +#define HCI_AMP_CTRLR_FULL_CAP_FOR_BT 6 + +#define HCI_MAX_AMP_STATUS_TYPES 7 + + +/* Define the extended flow specification fields used by AMP */ +typedef struct +{ + UINT8 id; + UINT8 stype; + UINT16 max_sdu_size; + UINT32 sdu_inter_time; + UINT32 access_latency; + UINT32 flush_timeout; +} tHCI_EXT_FLOW_SPEC; + + +/* HCI message type definitions (for H4 messages) */ +#define HCIT_TYPE_COMMAND 1 +#define HCIT_TYPE_ACL_DATA 2 +#define HCIT_TYPE_SCO_DATA 3 +#define HCIT_TYPE_EVENT 4 +#define HCIT_TYPE_LM_DIAG 7 +#define HCIT_TYPE_NFC 16 + +#define HCIT_LM_DIAG_LENGTH 63 + +/* Parameter information for HCI_BRCM_SET_ACL_PRIORITY */ +#define HCI_BRCM_ACL_PRIORITY_PARAM_SIZE 3 +#define HCI_BRCM_ACL_PRIORITY_LOW 0x00 +#define HCI_BRCM_ACL_PRIORITY_HIGH 0xFF +#define HCI_BRCM_SET_ACL_PRIORITY (0x0057 | HCI_GRP_VENDOR_SPECIFIC) + +/* Define values for LMP Test Control parameters +** Test Scenario, Hopping Mode, Power Control Mode +*/ +#define LMP_TESTCTL_TESTSC_PAUSE 0 +#define LMP_TESTCTL_TESTSC_TXTEST_0 1 +#define LMP_TESTCTL_TESTSC_TXTEST_1 2 +#define LMP_TESTCTL_TESTSC_TXTEST_1010 3 +#define LMP_TESTCTL_TESTSC_PSRND_BITSEQ 4 +#define LMP_TESTCTL_TESTSC_CLOSEDLB_ACL 5 +#define LMP_TESTCTL_TESTSC_CLOSEDLB_SCO 6 +#define LMP_TESTCTL_TESTSC_ACL_NOWHIT 7 +#define LMP_TESTCTL_TESTSC_SCO_NOWHIT 8 +#define LMP_TESTCTL_TESTSC_TXTEST_11110000 9 +#define LMP_TESTCTL_TESTSC_EXITTESTMODE 255 + +#define LMP_TESTCTL_HOPMOD_RXTX1FREQ 0 +#define LMP_TESTCTL_HOPMOD_HOP_EURUSA 1 +#define LMP_TESTCTL_HOPMOD_HOP_JAPAN 2 +#define LMP_TESTCTL_HOPMOD_HOP_FRANCE 3 +#define LMP_TESTCTL_HOPMOD_HOP_SPAIN 4 +#define LMP_TESTCTL_HOPMOD_REDUCED_HOP 5 + +#define LMP_TESTCTL_POWCTL_FIXEDTX_OP 0 +#define LMP_TESTCTL_POWCTL_ADAPTIVE 1 + +// TODO(zachoverflow): remove this once broadcom specific hacks are removed +#define LMP_COMPID_BROADCOM 15 + +/* +** Define the packet types in the packet header, and a couple extra +*/ +#define PKT_TYPE_NULL 0x00 +#define PKT_TYPE_POLL 0x01 +#define PKT_TYPE_FHS 0x02 +#define PKT_TYPE_DM1 0x03 + +#define PKT_TYPE_DH1 0x04 +#define PKT_TYPE_HV1 0x05 +#define PKT_TYPE_HV2 0x06 +#define PKT_TYPE_HV3 0x07 +#define PKT_TYPE_DV 0x08 +#define PKT_TYPE_AUX1 0x09 + +#define PKT_TYPE_DM3 0x0a +#define PKT_TYPE_DH3 0x0b + +#define PKT_TYPE_DM5 0x0e +#define PKT_TYPE_DH5 0x0f + + +#define PKT_TYPE_ID 0x10 /* Internally used packet types */ +#define PKT_TYPE_BAD 0x11 +#define PKT_TYPE_NONE 0x12 + +/* +** Define packet size +*/ +#define HCI_DM1_PACKET_SIZE 17 +#define HCI_DH1_PACKET_SIZE 27 +#define HCI_DM3_PACKET_SIZE 121 +#define HCI_DH3_PACKET_SIZE 183 +#define HCI_DM5_PACKET_SIZE 224 +#define HCI_DH5_PACKET_SIZE 339 +#define HCI_AUX1_PACKET_SIZE 29 +#define HCI_HV1_PACKET_SIZE 10 +#define HCI_HV2_PACKET_SIZE 20 +#define HCI_HV3_PACKET_SIZE 30 +#define HCI_DV_PACKET_SIZE 9 +#define HCI_EDR2_DH1_PACKET_SIZE 54 +#define HCI_EDR2_DH3_PACKET_SIZE 367 +#define HCI_EDR2_DH5_PACKET_SIZE 679 +#define HCI_EDR3_DH1_PACKET_SIZE 83 +#define HCI_EDR3_DH3_PACKET_SIZE 552 +#define HCI_EDR3_DH5_PACKET_SIZE 1021 + +/* Feature Pages */ +#define HCI_EXT_FEATURES_PAGE_0 0 /* Extended Feature Page 0 (regular features) */ +#define HCI_EXT_FEATURES_PAGE_1 1 /* Extended Feature Page 1 */ +#define HCI_EXT_FEATURES_PAGE_2 2 /* Extended Feature Page 2 */ +#define HCI_EXT_FEATURES_PAGE_MAX HCI_EXT_FEATURES_PAGE_2 + +#define HCI_FEATURE_BYTES_PER_PAGE 8 + +#define HCI_FEATURES_KNOWN(x) ((x[0] | x[1] | x[2] | x[3] | x[4] | x[5] | x[6] | x[7]) != 0) + +/* +** LMP features encoding - page 0 +*/ +#define HCI_FEATURE_3_SLOT_PACKETS_MASK 0x01 +#define HCI_FEATURE_3_SLOT_PACKETS_OFF 0 +#define HCI_3_SLOT_PACKETS_SUPPORTED(x) ((x)[HCI_FEATURE_3_SLOT_PACKETS_OFF] & HCI_FEATURE_3_SLOT_PACKETS_MASK) + +#define HCI_FEATURE_5_SLOT_PACKETS_MASK 0x02 +#define HCI_FEATURE_5_SLOT_PACKETS_OFF 0 +#define HCI_5_SLOT_PACKETS_SUPPORTED(x) ((x)[HCI_FEATURE_5_SLOT_PACKETS_OFF] & HCI_FEATURE_5_SLOT_PACKETS_MASK) + +#define HCI_FEATURE_ENCRYPTION_MASK 0x04 +#define HCI_FEATURE_ENCRYPTION_OFF 0 +#define HCI_ENCRYPTION_SUPPORTED(x) ((x)[HCI_FEATURE_ENCRYPTION_OFF] & HCI_FEATURE_ENCRYPTION_MASK) + +#define HCI_FEATURE_SLOT_OFFSET_MASK 0x08 +#define HCI_FEATURE_SLOT_OFFSET_OFF 0 +#define HCI_SLOT_OFFSET_SUPPORTED(x) ((x)[HCI_FEATURE_SLOT_OFFSET_OFF] & HCI_FEATURE_SLOT_OFFSET_MASK) + +#define HCI_FEATURE_TIMING_ACC_MASK 0x10 +#define HCI_FEATURE_TIMING_ACC_OFF 0 +#define HCI_TIMING_ACC_SUPPORTED(x) ((x)[HCI_FEATURE_TIMING_ACC_OFF] & HCI_FEATURE_TIMING_ACC_MASK) + +#define HCI_FEATURE_SWITCH_MASK 0x20 +#define HCI_FEATURE_SWITCH_OFF 0 +#define HCI_SWITCH_SUPPORTED(x) ((x)[HCI_FEATURE_SWITCH_OFF] & HCI_FEATURE_SWITCH_MASK) + +#define HCI_FEATURE_HOLD_MODE_MASK 0x40 +#define HCI_FEATURE_HOLD_MODE_OFF 0 +#define HCI_HOLD_MODE_SUPPORTED(x) ((x)[HCI_FEATURE_HOLD_MODE_OFF] & HCI_FEATURE_HOLD_MODE_MASK) + +#define HCI_FEATURE_SNIFF_MODE_MASK 0x80 +#define HCI_FEATURE_SNIFF_MODE_OFF 0 +#define HCI_SNIFF_MODE_SUPPORTED(x) ((x)[HCI_FEATURE_SNIFF_MODE_OFF] & HCI_FEATURE_SNIFF_MODE_MASK) + +#define HCI_FEATURE_PARK_MODE_MASK 0x01 +#define HCI_FEATURE_PARK_MODE_OFF 1 +#define HCI_PARK_MODE_SUPPORTED(x) ((x)[HCI_FEATURE_PARK_MODE_OFF] & HCI_FEATURE_PARK_MODE_MASK) + +#define HCI_FEATURE_RSSI_MASK 0x02 +#define HCI_FEATURE_RSSI_OFF 1 +#define HCI_RSSI_SUPPORTED(x) ((x)[HCI_FEATURE_RSSI_OFF] & HCI_FEATURE_RSSI_MASK) + +#define HCI_FEATURE_CQM_DATA_RATE_MASK 0x04 +#define HCI_FEATURE_CQM_DATA_RATE_OFF 1 +#define HCI_CQM_DATA_RATE_SUPPORTED(x) ((x)[HCI_FEATURE_CQM_DATA_RATE_OFF] & HCI_FEATURE_CQM_DATA_RATE_MASK) + +#define HCI_FEATURE_SCO_LINK_MASK 0x08 +#define HCI_FEATURE_SCO_LINK_OFF 1 +#define HCI_SCO_LINK_SUPPORTED(x) ((x)[HCI_FEATURE_SCO_LINK_OFF] & HCI_FEATURE_SCO_LINK_MASK) + +#define HCI_FEATURE_HV2_PACKETS_MASK 0x10 +#define HCI_FEATURE_HV2_PACKETS_OFF 1 +#define HCI_HV2_PACKETS_SUPPORTED(x) ((x)[HCI_FEATURE_HV2_PACKETS_OFF] & HCI_FEATURE_HV2_PACKETS_MASK) + +#define HCI_FEATURE_HV3_PACKETS_MASK 0x20 +#define HCI_FEATURE_HV3_PACKETS_OFF 1 +#define HCI_HV3_PACKETS_SUPPORTED(x) ((x)[HCI_FEATURE_HV3_PACKETS_OFF] & HCI_FEATURE_HV3_PACKETS_MASK) + +#define HCI_FEATURE_U_LAW_MASK 0x40 +#define HCI_FEATURE_U_LAW_OFF 1 +#define HCI_LMP_U_LAW_SUPPORTED(x) ((x)[HCI_FEATURE_U_LAW_OFF] & HCI_FEATURE_U_LAW_MASK) + +#define HCI_FEATURE_A_LAW_MASK 0x80 +#define HCI_FEATURE_A_LAW_OFF 1 +#define HCI_LMP_A_LAW_SUPPORTED(x) ((x)[HCI_FEATURE_A_LAW_OFF] & HCI_FEATURE_A_LAW_MASK) + +#define HCI_FEATURE_CVSD_MASK 0x01 +#define HCI_FEATURE_CVSD_OFF 2 +#define HCI_LMP_CVSD_SUPPORTED(x) ((x)[HCI_FEATURE_CVSD_OFF] & HCI_FEATURE_CVSD_MASK) + +#define HCI_FEATURE_PAGING_SCHEME_MASK 0x02 +#define HCI_FEATURE_PAGING_SCHEME_OFF 2 +#define HCI_PAGING_SCHEME_SUPPORTED(x) ((x)[HCI_FEATURE_PAGING_SCHEME_OFF] & HCI_FEATURE_PAGING_SCHEME_MASK) + +#define HCI_FEATURE_POWER_CTRL_MASK 0x04 +#define HCI_FEATURE_POWER_CTRL_OFF 2 +#define HCI_POWER_CTRL_SUPPORTED(x) ((x)[HCI_FEATURE_POWER_CTRL_OFF] & HCI_FEATURE_POWER_CTRL_MASK) + +#define HCI_FEATURE_TRANSPNT_MASK 0x08 +#define HCI_FEATURE_TRANSPNT_OFF 2 +#define HCI_LMP_TRANSPNT_SUPPORTED(x) ((x)[HCI_FEATURE_TRANSPNT_OFF] & HCI_FEATURE_TRANSPNT_MASK) + +#define HCI_FEATURE_FLOW_CTRL_LAG_MASK 0x70 +#define HCI_FEATURE_FLOW_CTRL_LAG_OFF 2 +#define HCI_FLOW_CTRL_LAG_VALUE(x) (((x)[HCI_FEATURE_FLOW_CTRL_LAG_OFF] & HCI_FEATURE_FLOW_CTRL_LAG_MASK) >> 4) + +#define HCI_FEATURE_BROADCAST_ENC_MASK 0x80 +#define HCI_FEATURE_BROADCAST_ENC_OFF 2 +#define HCI_LMP_BCAST_ENC_SUPPORTED(x) ((x)[HCI_FEATURE_BROADCAST_ENC_OFF] & HCI_FEATURE_BROADCAST_ENC_MASK) + +#define HCI_FEATURE_SCATTER_MODE_MASK 0x01 +#define HCI_FEATURE_SCATTER_MODE_OFF 3 +#define HCI_LMP_SCATTER_MODE_SUPPORTED(x) ((x)[HCI_FEATURE_SCATTER_MODE_OFF] & HCI_FEATURE_SCATTER_MODE_MASK) + +#define HCI_FEATURE_EDR_ACL_2MPS_MASK 0x02 +#define HCI_FEATURE_EDR_ACL_2MPS_OFF 3 +#define HCI_EDR_ACL_2MPS_SUPPORTED(x) ((x)[HCI_FEATURE_EDR_ACL_2MPS_OFF] & HCI_FEATURE_EDR_ACL_2MPS_MASK) + +#define HCI_FEATURE_EDR_ACL_3MPS_MASK 0x04 +#define HCI_FEATURE_EDR_ACL_3MPS_OFF 3 +#define HCI_EDR_ACL_3MPS_SUPPORTED(x) ((x)[HCI_FEATURE_EDR_ACL_3MPS_OFF] & HCI_FEATURE_EDR_ACL_3MPS_MASK) + +#define HCI_FEATURE_ENHANCED_INQ_MASK 0x08 +#define HCI_FEATURE_ENHANCED_INQ_OFF 3 +#define HCI_ENHANCED_INQ_SUPPORTED(x) ((x)[HCI_FEATURE_ENHANCED_INQ_OFF] & HCI_FEATURE_ENHANCED_INQ_MASK) + +#define HCI_FEATURE_INTERLACED_INQ_SCAN_MASK 0x10 +#define HCI_FEATURE_INTERLACED_INQ_SCAN_OFF 3 +#define HCI_LMP_INTERLACED_INQ_SCAN_SUPPORTED(x) ((x)[HCI_FEATURE_INTERLACED_INQ_SCAN_OFF] & HCI_FEATURE_INTERLACED_INQ_SCAN_MASK) + +#define HCI_FEATURE_INTERLACED_PAGE_SCAN_MASK 0x20 +#define HCI_FEATURE_INTERLACED_PAGE_SCAN_OFF 3 +#define HCI_LMP_INTERLACED_PAGE_SCAN_SUPPORTED(x) ((x)[HCI_FEATURE_INTERLACED_PAGE_SCAN_OFF] & HCI_FEATURE_INTERLACED_PAGE_SCAN_MASK) + +#define HCI_FEATURE_INQ_RSSI_MASK 0x40 +#define HCI_FEATURE_INQ_RSSI_OFF 3 +#define HCI_LMP_INQ_RSSI_SUPPORTED(x) ((x)[HCI_FEATURE_INQ_RSSI_OFF] & HCI_FEATURE_INQ_RSSI_MASK) + +#define HCI_FEATURE_ESCO_EV3_MASK 0x80 +#define HCI_FEATURE_ESCO_EV3_OFF 3 +#define HCI_ESCO_EV3_SUPPORTED(x) ((x)[HCI_FEATURE_ESCO_EV3_OFF] & HCI_FEATURE_ESCO_EV3_MASK) + +#define HCI_FEATURE_ESCO_EV4_MASK 0x01 +#define HCI_FEATURE_ESCO_EV4_OFF 4 +#define HCI_ESCO_EV4_SUPPORTED(x) ((x)[HCI_FEATURE_ESCO_EV4_OFF] & HCI_FEATURE_ESCO_EV4_MASK) + +#define HCI_FEATURE_ESCO_EV5_MASK 0x02 +#define HCI_FEATURE_ESCO_EV5_OFF 4 +#define HCI_ESCO_EV5_SUPPORTED(x) ((x)[HCI_FEATURE_ESCO_EV5_OFF] & HCI_FEATURE_ESCO_EV5_MASK) + +#define HCI_FEATURE_ABSENCE_MASKS_MASK 0x04 +#define HCI_FEATURE_ABSENCE_MASKS_OFF 4 +#define HCI_LMP_ABSENCE_MASKS_SUPPORTED(x) ((x)[HCI_FEATURE_ABSENCE_MASKS_OFF] & HCI_FEATURE_ABSENCE_MASKS_MASK) + +#define HCI_FEATURE_AFH_CAP_SLAVE_MASK 0x08 +#define HCI_FEATURE_AFH_CAP_SLAVE_OFF 4 +#define HCI_LMP_AFH_CAP_SLAVE_SUPPORTED(x) ((x)[HCI_FEATURE_AFH_CAP_SLAVE_OFF] & HCI_FEATURE_AFH_CAP_SLAVE_MASK) + +#define HCI_FEATURE_AFH_CLASS_SLAVE_MASK 0x10 +#define HCI_FEATURE_AFH_CLASS_SLAVE_OFF 4 +#define HCI_LMP_AFH_CLASS_SLAVE_SUPPORTED(x) ((x)[HCI_FEATURE_AFH_CLASS_SLAVE_OFF] & HCI_FEATURE_AFH_CLASS_SLAVE_MASK) + +#if 1 +#define HCI_FEATURE_BREDR_NOT_SPT_MASK 0x20 +#define HCI_FEATURE_BREDR_NOT_SPT_OFF 4 +#define HCI_BREDR_NOT_SPT_SUPPORTED(x) ((x)[HCI_FEATURE_BREDR_NOT_SPT_OFF] & HCI_FEATURE_BREDR_NOT_SPT_MASK) + +#define HCI_FEATURE_LE_SPT_MASK 0x40 +#define HCI_FEATURE_LE_SPT_OFF 4 +#define HCI_LE_SPT_SUPPORTED(x) ((x)[HCI_FEATURE_LE_SPT_OFF] & HCI_FEATURE_LE_SPT_MASK) +#else + +#define HCI_FEATURE_ALIAS_AUTH_MASK 0x20 +#define HCI_FEATURE_ALIAS_AUTH_OFF 4 +#define HCI_LMP_ALIAS_AUTH_SUPPORTED(x) ((x)[HCI_FEATURE_ALIAS_AUTH_OFF] & HCI_FEATURE_ALIAS_AUTH_MASK) + +#define HCI_FEATURE_ANON_MODE_MASK 0x40 +#define HCI_FEATURE_ANON_MODE_OFF 4 +#define HCI_LMP_ANON_MODE_SUPPORTED(x) ((x)[HCI_FEATURE_ANON_MODE_OFF] & HCI_FEATURE_ANON_MODE_MASK) +#endif + +#define HCI_FEATURE_3_SLOT_EDR_ACL_MASK 0x80 +#define HCI_FEATURE_3_SLOT_EDR_ACL_OFF 4 +#define HCI_3_SLOT_EDR_ACL_SUPPORTED(x) ((x)[HCI_FEATURE_3_SLOT_EDR_ACL_OFF] & HCI_FEATURE_3_SLOT_EDR_ACL_MASK) + +#define HCI_FEATURE_5_SLOT_EDR_ACL_MASK 0x01 +#define HCI_FEATURE_5_SLOT_EDR_ACL_OFF 5 +#define HCI_5_SLOT_EDR_ACL_SUPPORTED(x) ((x)[HCI_FEATURE_5_SLOT_EDR_ACL_OFF] & HCI_FEATURE_5_SLOT_EDR_ACL_MASK) + +#define HCI_FEATURE_SNIFF_SUB_RATE_MASK 0x02 +#define HCI_FEATURE_SNIFF_SUB_RATE_OFF 5 +#define HCI_SNIFF_SUB_RATE_SUPPORTED(x) ((x)[HCI_FEATURE_SNIFF_SUB_RATE_OFF] & HCI_FEATURE_SNIFF_SUB_RATE_MASK) + +#define HCI_FEATURE_ATOMIC_ENCRYPT_MASK 0x04 +#define HCI_FEATURE_ATOMIC_ENCRYPT_OFF 5 +#define HCI_ATOMIC_ENCRYPT_SUPPORTED(x) ((x)[HCI_FEATURE_ATOMIC_ENCRYPT_OFF] & HCI_FEATURE_ATOMIC_ENCRYPT_MASK) + +#define HCI_FEATURE_AFH_CAP_MASTR_MASK 0x08 +#define HCI_FEATURE_AFH_CAP_MASTR_OFF 5 +#define HCI_LMP_AFH_CAP_MASTR_SUPPORTED(x) ((x)[HCI_FEATURE_AFH_CAP_MASTR_OFF] & HCI_FEATURE_AFH_CAP_MASTR_MASK) + +#define HCI_FEATURE_AFH_CLASS_MASTR_MASK 0x10 +#define HCI_FEATURE_AFH_CLASS_MASTR_OFF 5 +#define HCI_LMP_AFH_CLASS_MASTR_SUPPORTED(x) ((x)[HCI_FEATURE_AFH_CLASS_MASTR_OFF] & HCI_FEATURE_AFH_CLASS_MASTR_MASK) + +#define HCI_FEATURE_EDR_ESCO_2MPS_MASK 0x20 +#define HCI_FEATURE_EDR_ESCO_2MPS_OFF 5 +#define HCI_EDR_ESCO_2MPS_SUPPORTED(x) ((x)[HCI_FEATURE_EDR_ESCO_2MPS_OFF] & HCI_FEATURE_EDR_ESCO_2MPS_MASK) + +#define HCI_FEATURE_EDR_ESCO_3MPS_MASK 0x40 +#define HCI_FEATURE_EDR_ESCO_3MPS_OFF 5 +#define HCI_EDR_ESCO_3MPS_SUPPORTED(x) ((x)[HCI_FEATURE_EDR_ESCO_3MPS_OFF] & HCI_FEATURE_EDR_ESCO_3MPS_MASK) + +#define HCI_FEATURE_3_SLOT_EDR_ESCO_MASK 0x80 +#define HCI_FEATURE_3_SLOT_EDR_ESCO_OFF 5 +#define HCI_3_SLOT_EDR_ESCO_SUPPORTED(x) ((x)[HCI_FEATURE_3_SLOT_EDR_ESCO_OFF] & HCI_FEATURE_3_SLOT_EDR_ESCO_MASK) + +#define HCI_FEATURE_EXT_INQ_RSP_MASK 0x01 +#define HCI_FEATURE_EXT_INQ_RSP_OFF 6 +#define HCI_EXT_INQ_RSP_SUPPORTED(x) ((x)[HCI_FEATURE_EXT_INQ_RSP_OFF] & HCI_FEATURE_EXT_INQ_RSP_MASK) + +#if 1 /* TOKYO spec definition */ +#define HCI_FEATURE_SIMUL_LE_BREDR_MASK 0x02 +#define HCI_FEATURE_SIMUL_LE_BREDR_OFF 6 +#define HCI_SIMUL_LE_BREDR_SUPPORTED(x) ((x)[HCI_FEATURE_SIMUL_LE_BREDR_OFF] & HCI_FEATURE_SIMUL_LE_BREDR_MASK) + +#else +#define HCI_FEATURE_ANUM_PIN_AWARE_MASK 0x02 +#define HCI_FEATURE_ANUM_PIN_AWARE_OFF 6 +#define HCI_ANUM_PIN_AWARE_SUPPORTED(x) ((x)[HCI_FEATURE_ANUM_PIN_AWARE_OFF] & HCI_FEATURE_ANUM_PIN_AWARE_MASK) +#endif + +#define HCI_FEATURE_ANUM_PIN_CAP_MASK 0x04 +#define HCI_FEATURE_ANUM_PIN_CAP_OFF 6 +#define HCI_ANUM_PIN_CAP_SUPPORTED(x) ((x)[HCI_FEATURE_ANUM_PIN_CAP_OFF] & HCI_FEATURE_ANUM_PIN_CAP_MASK) + +#define HCI_FEATURE_SIMPLE_PAIRING_MASK 0x08 +#define HCI_FEATURE_SIMPLE_PAIRING_OFF 6 +#define HCI_SIMPLE_PAIRING_SUPPORTED(x) ((x)[HCI_FEATURE_SIMPLE_PAIRING_OFF] & HCI_FEATURE_SIMPLE_PAIRING_MASK) + +#define HCI_FEATURE_ENCAP_PDU_MASK 0x10 +#define HCI_FEATURE_ENCAP_PDU_OFF 6 +#define HCI_ENCAP_PDU_SUPPORTED(x) ((x)[HCI_FEATURE_ENCAP_PDU_OFF] & HCI_FEATURE_ENCAP_PDU_MASK) + +#define HCI_FEATURE_ERROR_DATA_MASK 0x20 +#define HCI_FEATURE_ERROR_DATA_OFF 6 +#define HCI_ERROR_DATA_SUPPORTED(x) ((x)[HCI_FEATURE_ERROR_DATA_OFF] & HCI_FEATURE_ERROR_DATA_MASK) + +#define HCI_FEATURE_NON_FLUSHABLE_PB_MASK 0x40 +#define HCI_FEATURE_NON_FLUSHABLE_PB_OFF 6 + +/* This feature is causing frequent link drops when doing call switch with certain av/hfp headsets */ +#define HCI_NON_FLUSHABLE_PB_SUPPORTED(x) (0)//((x)[HCI_FEATURE_NON_FLUSHABLE_PB_OFF] & HCI_FEATURE_NON_FLUSHABLE_PB_MASK) + +#define HCI_FEATURE_LINK_SUP_TO_EVT_MASK 0x01 +#define HCI_FEATURE_LINK_SUP_TO_EVT_OFF 7 +#define HCI_LINK_SUP_TO_EVT_SUPPORTED(x) ((x)[HCI_FEATURE_LINK_SUP_TO_EVT_OFF] & HCI_FEATURE_LINK_SUP_TO_EVT_MASK) + +#define HCI_FEATURE_INQ_RESP_TX_MASK 0x02 +#define HCI_FEATURE_INQ_RESP_TX_OFF 7 +#define HCI_INQ_RESP_TX_SUPPORTED(x) ((x)[HCI_FEATURE_INQ_RESP_TX_OFF] & HCI_FEATURE_INQ_RESP_TX_MASK) + +#define HCI_FEATURE_EXTENDED_MASK 0x80 +#define HCI_FEATURE_EXTENDED_OFF 7 +#define HCI_LMP_EXTENDED_SUPPORTED(x) ((x)[HCI_FEATURE_EXTENDED_OFF] & HCI_FEATURE_EXTENDED_MASK) + +/* +** LMP features encoding - page 1 +*/ +#define HCI_EXT_FEATURE_SSP_HOST_MASK 0x01 +#define HCI_EXT_FEATURE_SSP_HOST_OFF 0 +#define HCI_SSP_HOST_SUPPORTED(x) ((x)[HCI_EXT_FEATURE_SSP_HOST_OFF] & HCI_EXT_FEATURE_SSP_HOST_MASK) + +#define HCI_EXT_FEATURE_LE_HOST_MASK 0x02 +#define HCI_EXT_FEATURE_LE_HOST_OFF 0 +#define HCI_LE_HOST_SUPPORTED(x) ((x)[HCI_EXT_FEATURE_LE_HOST_OFF] & HCI_EXT_FEATURE_LE_HOST_MASK) + +#define HCI_EXT_FEATURE_SIMUL_DUMO_HOST_MASK 0x04 +#define HCI_EXT_FEATURE_SIMUL_DUMO_HOST_OFF 0 +#define HCI_SIMUL_DUMO_HOST_SUPPORTED(x) ((x)[HCI_EXT_FEATURE_SIMUL_DUMO_HOST_OFF] & HCI_EXT_FEATURE_SIMUL_DUMO_HOST_MASK) + +#define HCI_EXT_FEATURE_SC_HOST_MASK 0x08 +#define HCI_EXT_FEATURE_SC_HOST_OFF 0 +#define HCI_SC_HOST_SUPPORTED(x) ((x)[HCI_EXT_FEATURE_SC_HOST_OFF] & HCI_EXT_FEATURE_SC_HOST_MASK) + +/* +** LMP features encoding - page 2 +*/ +#define HCI_EXT_FEATURE_CSB_MASTER_MASK 0x01 +#define HCI_EXT_FEATURE_CSB_MASTER_OFF 0 +#define HCI_CSB_MASTER_SUPPORTED(x) ((x)[HCI_EXT_FEATURE_CSB_MASTER_OFF] & HCI_EXT_FEATURE_CSB_MASTER_MASK) + +#define HCI_EXT_FEATURE_CSB_SLAVE_MASK 0x02 +#define HCI_EXT_FEATURE_CSB_SLAVE_OFF 0 +#define HCI_CSB_SLAVE_SUPPORTED(x) ((x)[HCI_EXT_FEATURE_CSB_SLAVE_OFF] & HCI_EXT_FEATURE_CSB_SLAVE_MASK) + +#define HCI_EXT_FEATURE_SYNC_TRAIN_MASTER_MASK 0x04 +#define HCI_EXT_FEATURE_SYNC_TRAIN_MASTER_OFF 0 +#define HCI_SYNC_TRAIN_MASTER_SUPPORTED(x) ((x)[HCI_EXT_FEATURE_SYNC_TRAIN_MASTER_OFF] & HCI_EXT_FEATURE_SYNC_TRAIN_MASTER_MASK) + +#define HCI_EXT_FEATURE_SYNC_SCAN_SLAVE_MASK 0x08 +#define HCI_EXT_FEATURE_SYNC_SCAN_SLAVE_OFF 0 +#define HCI_SYNC_SCAN_SLAVE_SUPPORTED(x) ((x)[HCI_EXT_FEATURE_SYNC_SCAN_SLAVE_OFF] & HCI_EXT_FEATURE_SYNC_SCAN_SLAVE_MASK) + +#define HCI_EXT_FEATURE_INQ_RESP_NOTIF_MASK 0x10 +#define HCI_EXT_FEATURE_INQ_RESP_NOTIF_OFF 0 +#define HCI_INQ_RESP_NOTIF_SUPPORTED(x) ((x)[HCI_EXT_FEATURE_INQ_RESP_NOTIF_OFF] & HCI_EXT_FEATURE_INQ_RESP_NOTIF_MASK) + +#define HCI_EXT_FEATURE_SC_CTRLR_MASK 0x01 +#define HCI_EXT_FEATURE_SC_CTRLR_OFF 1 +#define HCI_SC_CTRLR_SUPPORTED(x) ((x)[HCI_EXT_FEATURE_SC_CTRLR_OFF] & HCI_EXT_FEATURE_SC_CTRLR_MASK) + +#define HCI_EXT_FEATURE_PING_MASK 0x02 +#define HCI_EXT_FEATURE_PING_OFF 1 +#define HCI_PING_SUPPORTED(x) ((x)[HCI_EXT_FEATURE_PING_OFF] & HCI_EXT_FEATURE_PING_MASK) + +/* +** LE features encoding - page 0 (the only page for now) +*/ +/* LE Encryption */ +#define HCI_LE_FEATURE_LE_ENCRYPTION_MASK 0x01 +#define HCI_LE_FEATURE_LE_ENCRYPTION_OFF 0 +#define HCI_LE_ENCRYPTION_SUPPORTED(x) ((x)[HCI_LE_FEATURE_LE_ENCRYPTION_OFF] & HCI_LE_FEATURE_LE_ENCRYPTION_MASK) + +/* Connection Parameters Request Procedure */ +#define HCI_LE_FEATURE_CONN_PARAM_REQ_MASK 0x02 +#define HCI_LE_FEATURE_CONN_PARAM_REQ_OFF 0 +#define HCI_LE_CONN_PARAM_REQ_SUPPORTED(x) ((x)[HCI_LE_FEATURE_CONN_PARAM_REQ_OFF] & HCI_LE_FEATURE_CONN_PARAM_REQ_MASK) + +/* Extended Reject Indication */ +#define HCI_LE_FEATURE_EXT_REJ_IND_MASK 0x04 +#define HCI_LE_FEATURE_EXT_REJ_IND_OFF 0 +#define HCI_LE_EXT_REJ_IND_SUPPORTED(x) ((x)[HCI_LE_FEATURE_EXT_REJ_IND_OFF] & HCI_LE_FEATURE_EXT_REJ_IND_MASK) + +/* Slave-initiated Features Exchange */ +#define HCI_LE_FEATURE_SLAVE_INIT_FEAT_EXC_MASK 0x08 +#define HCI_LE_FEATURE_SLAVE_INIT_FEAT_EXC_OFF 0 +#define HCI_LE_SLAVE_INIT_FEAT_EXC_SUPPORTED(x) ((x)[HCI_LE_FEATURE_SLAVE_INIT_FEAT_EXC_OFF] & HCI_LE_FEATURE_SLAVE_INIT_FEAT_EXC_MASK) + +/* Enhanced privacy Feature: bit 6 */ +#define HCI_LE_FEATURE_ENHANCED_PRIVACY_MASK 0x40 +#define HCI_LE_FEATURE_ENHANCED_PRIVACY_OFF 0 +#define HCI_LE_ENHANCED_PRIVACY_SUPPORTED(x) ((x)[HCI_LE_FEATURE_ENHANCED_PRIVACY_OFF] & HCI_LE_FEATURE_ENHANCED_PRIVACY_MASK) + +/* Extended scanner filter policy : 7 */ +#define HCI_LE_FEATURE_EXT_SCAN_FILTER_POLICY_MASK 0x80 +#define HCI_LE_FEATURE_EXT_SCAN_FILTER_POLICY_OFF 0 +#define HCI_LE_EXT_SCAN_FILTER_POLICY_SUPPORTED(x) ((x)[HCI_LE_FEATURE_EXT_SCAN_FILTER_POLICY_OFF] & HCI_LE_FEATURE_EXT_SCAN_FILTER_POLICY_MASK) + +/* Slave-initiated Features Exchange */ +#define HCI_LE_FEATURE_DATA_LEN_EXT_MASK 0x20 +#define HCI_LE_FEATURE_DATA_LEN_EXT_OFF 0 +#define HCI_LE_DATA_LEN_EXT_SUPPORTED(x) ((x)[HCI_LE_FEATURE_DATA_LEN_EXT_OFF] & HCI_LE_FEATURE_DATA_LEN_EXT_MASK) + +/* +** Local Supported Commands encoding +*/ +#define HCI_NUM_SUPP_COMMANDS_BYTES 64 + +/* Supported Commands Byte 0 */ +#define HCI_SUPP_COMMANDS_INQUIRY_MASK 0x01 +#define HCI_SUPP_COMMANDS_INQUIRY_OFF 0 +#define HCI_INQUIRY_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_INQUIRY_OFF] & HCI_SUPP_COMMANDS_INQUIRY_MASK) + +#define HCI_SUPP_COMMANDS_INQUIRY_CANCEL_MASK 0x02 +#define HCI_SUPP_COMMANDS_INQUIRY_CANCEL_OFF 0 +#define HCI_INQUIRY_CANCEL_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_INQUIRY_CANCEL_OFF] & HCI_SUPP_COMMANDS_INQUIRY_CANCEL_MASK) + +#define HCI_SUPP_COMMANDS_PERIODIC_INQUIRY_MASK 0x04 +#define HCI_SUPP_COMMANDS_PERIODIC_INQUIRY_OFF 0 +#define HCI_PERIODIC_INQUIRY_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_PERIODIC_INQUIRY_OFF] & HCI_SUPP_COMMANDS_PERIODIC_INQUIRY_MASK) + +#define HCI_SUPP_COMMANDS_EXIT_PERIODIC_INQUIRY_MASK 0x08 +#define HCI_SUPP_COMMANDS_EXIT_PERIODIC_INQUIRY_OFF 0 +#define HCI_EXIT_PERIODIC_INQUIRY_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_EXIT_PERIODIC_INQUIRY_OFF] & HCI_SUPP_COMMANDS_EXIT_PERIODIC_INQUIRY_MASK) + +#define HCI_SUPP_COMMANDS_CREATE_CONN_MASK 0x10 +#define HCI_SUPP_COMMANDS_CREATE_CONN_OFF 0 +#define HCI_CREATE_CONN_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_CREATE_CONN_OFF] & HCI_SUPP_COMMANDS_CREATE_CONN_MASK) + +#define HCI_SUPP_COMMANDS_DISCONNECT_MASK 0x20 +#define HCI_SUPP_COMMANDS_DISCONNECT_OFF 0 +#define HCI_DISCONNECT_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_DISCONNECT_OFF] & HCI_SUPP_COMMANDS_DISCONNECT_MASK) + +#define HCI_SUPP_COMMANDS_ADD_SCO_CONN_MASK 0x40 +#define HCI_SUPP_COMMANDS_ADD_SCO_CONN_OFF 0 +#define HCI_ADD_SCO_CONN_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_ADD_SCO_CONN_OFF] & HCI_SUPP_COMMANDS_ADD_SCO_CONN_MASK) + +#define HCI_SUPP_COMMANDS_CANCEL_CREATE_CONN_MASK 0x80 +#define HCI_SUPP_COMMANDS_CANCEL_CREATE_CONN_OFF 0 +#define HCI_CANCEL_CREATE_CONN_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_CANCEL_CREATE_CONN_OFF] & HCI_SUPP_COMMANDS_CANCEL_CREATE_CONN_MASK) + +#define HCI_SUPP_COMMANDS_ACCEPT_CONN_REQUEST_MASK 0x01 +#define HCI_SUPP_COMMANDS_ACCEPT_CONN_REQUEST_OFF 1 +#define HCI_ACCEPT_CONN_REQUEST_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_ACCEPT_CONN_REQUEST_OFF] & HCI_SUPP_COMMANDS_ACCEPT_CONN_REQUEST_MASK) + +#define HCI_SUPP_COMMANDS_REJECT_CONN_REQUEST_MASK 0x02 +#define HCI_SUPP_COMMANDS_REJECT_CONN_REQUEST_OFF 1 +#define HCI_REJECT_CONN_REQUEST_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_REJECT_CONN_REQUEST_OFF] & HCI_SUPP_COMMANDS_REJECT_CONN_REQUEST_MASK) + +#define HCI_SUPP_COMMANDS_LINK_KEY_REQUEST_REPLY_MASK 0x04 +#define HCI_SUPP_COMMANDS_LINK_KEY_REQUEST_REPLY_OFF 1 +#define HCI_LINK_KEY_REQUEST_REPLY_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_LINK_KEY_REQUEST_REPLY_OFF] & HCI_SUPP_COMMANDS_LINK_KEY_REQUEST_REPLY_MASK) + +#define HCI_SUPP_COMMANDS_LINK_KEY_REQUEST_NEG_REPLY_MASK 0x08 +#define HCI_SUPP_COMMANDS_LINK_KEY_REQUEST_NEG_REPLY_OFF 1 +#define HCI_LINK_KEY_REQUEST_NEG_REPLY_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_LINK_KEY_REQUEST_NEG_REPLY_OFF] & HCI_SUPP_COMMANDS_LINK_KEY_REQUEST_NEG_REPLY_MASK) + +#define HCI_SUPP_COMMANDS_PIN_CODE_REQUEST_REPLY_MASK 0x10 +#define HCI_SUPP_COMMANDS_PIN_CODE_REQUEST_REPLY_OFF 1 +#define HCI_PIN_CODE_REQUEST_REPLY_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_PIN_CODE_REQUEST_REPLY_OFF] & HCI_SUPP_COMMANDS_PIN_CODE_REQUEST_REPLY_MASK) + +#define HCI_SUPP_COMMANDS_PIN_CODE_REQUEST_NEG_REPLY_MASK 0x20 +#define HCI_SUPP_COMMANDS_PIN_CODE_REQUEST_NEG_REPLY_OFF 1 +#define HCI_PIN_CODE_REQUEST_NEG_REPLY_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_PIN_CODE_REQUEST_NEG_REPLY_OFF] & HCI_SUPP_COMMANDS_PIN_CODE_REQUEST_NEG_REPLY_MASK) + +#define HCI_SUPP_COMMANDS_CHANGE_CONN_PKT_TYPE_MASK 0x40 +#define HCI_SUPP_COMMANDS_CHANGE_CONN_PKT_TYPE_OFF 1 +#define HCI_CHANGE_CONN_PKT_TYPE_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_CHANGE_CONN_PKT_TYPE_OFF] & HCI_SUPP_COMMANDS_CHANGE_CONN_PKT_TYPE_MASK) + +#define HCI_SUPP_COMMANDS_AUTH_REQUEST_MASK 0x80 +#define HCI_SUPP_COMMANDS_AUTH_REQUEST_OFF 1 +#define HCI_AUTH_REQUEST_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_AUTH_REQUEST_OFF] & HCI_SUPP_COMMANDS_AUTH_REQUEST_MASK) + +#define HCI_SUPP_COMMANDS_SET_CONN_ENCRYPTION_MASK 0x01 +#define HCI_SUPP_COMMANDS_SET_CONN_ENCRYPTION_OFF 2 +#define HCI_SET_CONN_ENCRYPTION_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_SET_CONN_ENCRYPTION_OFF] & HCI_SUPP_COMMANDS_SET_CONN_ENCRYPTION_MASK) + +#define HCI_SUPP_COMMANDS_CHANGE_CONN_LINK_KEY_MASK 0x02 +#define HCI_SUPP_COMMANDS_CHANGE_CONN_LINK_KEY_OFF 2 +#define HCI_CHANGE_CONN_LINK_KEY_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_CHANGE_CONN_LINK_KEY_OFF] & HCI_SUPP_COMMANDS_CHANGE_CONN_LINK_KEY_MASK) + +#define HCI_SUPP_COMMANDS_MASTER_LINK_KEY_MASK 0x04 +#define HCI_SUPP_COMMANDS_MASTER_LINK_KEY_OFF 2 +#define HCI_MASTER_LINK_KEY_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_MASTER_LINK_KEY_OFF] & HCI_SUPP_COMMANDS_MASTER_LINK_KEY_MASK) + +#define HCI_SUPP_COMMANDS_REMOTE_NAME_REQUEST_MASK 0x08 +#define HCI_SUPP_COMMANDS_REMOTE_NAME_REQUEST_OFF 2 +#define HCI_REMOTE_NAME_REQUEST_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_REMOTE_NAME_REQUEST_OFF] & HCI_SUPP_COMMANDS_REMOTE_NAME_REQUEST_MASK) + +#define HCI_SUPP_COMMANDS_CANCEL_REMOTE_NAME_REQUEST_MASK 0x10 +#define HCI_SUPP_COMMANDS_CANCEL_REMOTE_NAME_REQUEST_OFF 2 +#define HCI_CANCEL_REMOTE_NAME_REQUEST_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_CANCEL_REMOTE_NAME_REQUEST_OFF] & HCI_SUPP_COMMANDS_CANCEL_REMOTE_NAME_REQUEST_MASK) + +#define HCI_SUPP_COMMANDS_READ_REMOTE_SUPP_FEATURES_MASK 0x20 +#define HCI_SUPP_COMMANDS_READ_REMOTE_SUPP_FEATURES_OFF 2 +#define HCI_READ_REMOTE_SUPP_FEATURES_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_READ_REMOTE_SUPP_FEATURES_OFF] & HCI_SUPP_COMMANDS_READ_REMOTE_SUPP_FEATURES_MASK) + +#define HCI_SUPP_COMMANDS_READ_REMOTE_EXT_FEATURES_MASK 0x40 +#define HCI_SUPP_COMMANDS_READ_REMOTE_EXT_FEATURES_OFF 2 +#define HCI_READ_REMOTE_EXT_FEATURES_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_READ_REMOTE_EXT_FEATURES_OFF] & HCI_SUPP_COMMANDS_READ_REMOTE_EXT_FEATURES_MASK) + +#define HCI_SUPP_COMMANDS_READ_REMOTE_VER_INFO_MASK 0x80 +#define HCI_SUPP_COMMANDS_READ_REMOTE_VER_INFO_OFF 2 +#define HCI_READ_REMOTE_VER_INFO_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_READ_REMOTE_VER_INFO_OFF] & HCI_SUPP_COMMANDS_READ_REMOTE_VER_INFO_MASK) + +#define HCI_SUPP_COMMANDS_READ_CLOCK_OFFSET_MASK 0x01 +#define HCI_SUPP_COMMANDS_READ_CLOCK_OFFSET_OFF 3 +#define HCI_READ_CLOCK_OFFSET_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_READ_CLOCK_OFFSET_OFF] & HCI_SUPP_COMMANDS_READ_CLOCK_OFFSET_MASK) + +#define HCI_SUPP_COMMANDS_READ_LMP_HANDLE_MASK 0x02 +#define HCI_SUPP_COMMANDS_READ_LMP_HANDLE_OFF 3 +#define HCI_READ_LMP_HANDLE_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_READ_LMP_HANDLE_OFF] & HCI_SUPP_COMMANDS_READ_LMP_HANDLE_MASK) + +#define HCI_SUPP_COMMANDS_HOLD_MODE_CMD_MASK 0x02 +#define HCI_SUPP_COMMANDS_HOLD_MODE_CMD_OFF 4 +#define HCI_HOLD_MODE_CMD_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_HOLD_MODE_CMD_OFF] & HCI_SUPP_COMMANDS_HOLD_MODE_CMD_MASK) + +#define HCI_SUPP_COMMANDS_SNIFF_MODE_CMD_MASK 0x04 +#define HCI_SUPP_COMMANDS_SNIFF_MODE_CMD_OFF 4 +#define HCI_SNIFF_MODE_CMD_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_SNIFF_MODE_CMD_OFF] & HCI_SUPP_COMMANDS_SNIFF_MODE_CMD_MASK) + +#define HCI_SUPP_COMMANDS_EXIT_SNIFF_MODE_MASK 0x08 +#define HCI_SUPP_COMMANDS_EXIT_SNIFF_MODE_OFF 4 +#define HCI_EXIT_SNIFF_MODE_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_EXIT_SNIFF_MODE_OFF] & HCI_SUPP_COMMANDS_EXIT_SNIFF_MODE_MASK) + +#define HCI_SUPP_COMMANDS_PARK_STATE_MASK 0x10 +#define HCI_SUPP_COMMANDS_PARK_STATE_OFF 4 +#define HCI_PARK_STATE_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_PARK_STATE_OFF] & HCI_SUPP_COMMANDS_PARK_STATE_MASK) + +#define HCI_SUPP_COMMANDS_EXIT_PARK_STATE_MASK 0x20 +#define HCI_SUPP_COMMANDS_EXIT_PARK_STATE_OFF 4 +#define HCI_EXIT_PARK_STATE_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_EXIT_PARK_STATE_OFF] & HCI_SUPP_COMMANDS_EXIT_PARK_STATE_MASK) + +#define HCI_SUPP_COMMANDS_QOS_SETUP_MASK 0x40 +#define HCI_SUPP_COMMANDS_QOS_SETUP_OFF 4 +#define HCI_QOS_SETUP_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_QOS_SETUP_OFF] & HCI_SUPP_COMMANDS_QOS_SETUP_MASK) + +#define HCI_SUPP_COMMANDS_ROLE_DISCOVERY_MASK 0x80 +#define HCI_SUPP_COMMANDS_ROLE_DISCOVERY_OFF 4 +#define HCI_ROLE_DISCOVERY_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_ROLE_DISCOVERY_OFF] & HCI_SUPP_COMMANDS_ROLE_DISCOVERY_MASK) + +#define HCI_SUPP_COMMANDS_SWITCH_ROLE_MASK 0x01 +#define HCI_SUPP_COMMANDS_SWITCH_ROLE_OFF 5 +#define HCI_SWITCH_ROLE_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_SWITCH_ROLE_OFF] & HCI_SUPP_COMMANDS_SWITCH_ROLE_MASK) + +#define HCI_SUPP_COMMANDS_READ_LINK_POLICY_SET_MASK 0x02 +#define HCI_SUPP_COMMANDS_READ_LINK_POLICY_SET_OFF 5 +#define HCI_READ_LINK_POLICY_SET_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_READ_LINK_POLICY_SET_OFF] & HCI_SUPP_COMMANDS_READ_LINK_POLICY_SET_MASK) + +#define HCI_SUPP_COMMANDS_WRITE_LINK_POLICY_SET_MASK 0x04 +#define HCI_SUPP_COMMANDS_WRITE_LINK_POLICY_SET_OFF 5 +#define HCI_WRITE_LINK_POLICY_SET_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_WRITE_LINK_POLICY_SET_OFF] & HCI_SUPP_COMMANDS_WRITE_LINK_POLICY_SET_MASK) + +#define HCI_SUPP_COMMANDS_READ_DEF_LINK_POLICY_SET_MASK 0x08 +#define HCI_SUPP_COMMANDS_READ_DEF_LINK_POLICY_SET_OFF 5 +#define HCI_READ_DEF_LINK_POLICY_SET_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_READ_DEF_LINK_POLICY_SET_OFF] & HCI_SUPP_COMMANDS_READ_DEF_LINK_POLICY_SET_MASK) + +#define HCI_SUPP_COMMANDS_WRITE_DEF_LINK_POLICY_SET_MASK 0x10 +#define HCI_SUPP_COMMANDS_WRITE_DEF_LINK_POLICY_SET_OFF 5 +#define HCI_WRITE_DEF_LINK_POLICY_SET_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_WRITE_DEF_LINK_POLICY_SET_OFF] & HCI_SUPP_COMMANDS_WRITE_DEF_LINK_POLICY_SET_MASK) + +#define HCI_SUPP_COMMANDS_FLOW_SPECIFICATION_MASK 0x20 +#define HCI_SUPP_COMMANDS_FLOW_SPECIFICATION_OFF 5 +#define HCI_FLOW_SPECIFICATION_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_FLOW_SPECIFICATION_OFF] & HCI_SUPP_COMMANDS_FLOW_SPECIFICATION_MASK) + +#define HCI_SUPP_COMMANDS_SET_EVENT_MASK_MASK 0x40 +#define HCI_SUPP_COMMANDS_SET_EVENT_MASK_OFF 5 +#define HCI_SET_EVENT_MASK_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_SET_EVENT_MASK_OFF] & HCI_SUPP_COMMANDS_SET_EVENT_MASK_MASK) + +#define HCI_SUPP_COMMANDS_RESET_MASK 0x80 +#define HCI_SUPP_COMMANDS_RESET_OFF 5 +#define HCI_RESET_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_RESET_OFF] & HCI_SUPP_COMMANDS_RESET_MASK) + +#define HCI_SUPP_COMMANDS_SET_EVENT_FILTER_MASK 0x01 +#define HCI_SUPP_COMMANDS_SET_EVENT_FILTER_OFF 6 +#define HCI_SET_EVENT_FILTER_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_SET_EVENT_FILTER_OFF] & HCI_SUPP_COMMANDS_SET_EVENT_FILTER_MASK) + +#define HCI_SUPP_COMMANDS_FLUSH_MASK 0x02 +#define HCI_SUPP_COMMANDS_FLUSH_OFF 6 +#define HCI_FLUSH_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_FLUSH_OFF] & HCI_SUPP_COMMANDS_FLUSH_MASK) + +#define HCI_SUPP_COMMANDS_READ_PIN_TYPE_MASK 0x04 +#define HCI_SUPP_COMMANDS_READ_PIN_TYPE_OFF 6 +#define HCI_READ_PIN_TYPE_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_READ_PIN_TYPE_OFF] & HCI_SUPP_COMMANDS_READ_PIN_TYPE_MASK) + +#define HCI_SUPP_COMMANDS_WRITE_PIN_TYPE_MASK 0x08 +#define HCI_SUPP_COMMANDS_WRITE_PIN_TYPE_OFF 6 +#define HCI_WRITE_PIN_TYPE_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_WRITE_PIN_TYPE_OFF] & HCI_SUPP_COMMANDS_WRITE_PIN_TYPE_MASK) + +#define HCI_SUPP_COMMANDS_CREATE_NEW_UNIT_KEY_MASK 0x10 +#define HCI_SUPP_COMMANDS_CREATE_NEW_UNIT_KEY_OFF 6 +#define HCI_CREATE_NEW_UNIT_KEY_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_CREATE_NEW_UNIT_KEY_OFF] & HCI_SUPP_COMMANDS_CREATE_NEW_UNIT_KEY_MASK) + +#define HCI_SUPP_COMMANDS_READ_STORED_LINK_KEY_MASK 0x20 +#define HCI_SUPP_COMMANDS_READ_STORED_LINK_KEY_OFF 6 +#define HCI_READ_STORED_LINK_KEY_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_READ_STORED_LINK_KEY_OFF] & HCI_SUPP_COMMANDS_READ_STORED_LINK_KEY_MASK) + +#define HCI_SUPP_COMMANDS_WRITE_STORED_LINK_KEY_MASK 0x40 +#define HCI_SUPP_COMMANDS_WRITE_STORED_LINK_KEY_OFF 6 +#define HCI_WRITE_STORED_LINK_KEY_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_WRITE_STORED_LINK_KEY_OFF] & HCI_SUPP_COMMANDS_WRITE_STORED_LINK_KEY_MASK) + +#define HCI_SUPP_COMMANDS_DELETE_STORED_LINK_KEY_MASK 0x80 +#define HCI_SUPP_COMMANDS_DELETE_STORED_LINK_KEY_OFF 6 +#define HCI_DELETE_STORED_LINK_KEY_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_DELETE_STORED_LINK_KEY_OFF] & HCI_SUPP_COMMANDS_DELETE_STORED_LINK_KEY_MASK) + +#define HCI_SUPP_COMMANDS_WRITE_LOCAL_NAME_MASK 0x01 +#define HCI_SUPP_COMMANDS_WRITE_LOCAL_NAME_OFF 7 +#define HCI_WRITE_LOCAL_NAME_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_WRITE_LOCAL_NAME_OFF] & HCI_SUPP_COMMANDS_WRITE_LOCAL_NAME_MASK) + +#define HCI_SUPP_COMMANDS_READ_LOCAL_NAME_MASK 0x02 +#define HCI_SUPP_COMMANDS_READ_LOCAL_NAME_OFF 7 +#define HCI_READ_LOCAL_NAME_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_READ_LOCAL_NAME_OFF] & HCI_SUPP_COMMANDS_READ_LOCAL_NAME_MASK) + +#define HCI_SUPP_COMMANDS_READ_CONN_ACCEPT_TOUT_MASK 0x04 +#define HCI_SUPP_COMMANDS_READ_CONN_ACCEPT_TOUT_OFF 7 +#define HCI_READ_CONN_ACCEPT_TOUT_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_READ_CONN_ACCEPT_TOUT_OFF] & HCI_SUPP_COMMANDS_READ_CONN_ACCEPT_TOUT_MASK) + +#define HCI_SUPP_COMMANDS_WRITE_CONN_ACCEPT_TOUT_MASK 0x08 +#define HCI_SUPP_COMMANDS_WRITE_CONN_ACCEPT_TOUT_OFF 7 +#define HCI_WRITE_CONN_ACCEPT_TOUT_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_WRITE_CONN_ACCEPT_TOUT_OFF] & HCI_SUPP_COMMANDS_WRITE_CONN_ACCEPT_TOUT_MASK) + +#define HCI_SUPP_COMMANDS_READ_PAGE_TOUT_MASK 0x10 +#define HCI_SUPP_COMMANDS_READ_PAGE_TOUT_OFF 7 +#define HCI_READ_PAGE_TOUT_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_READ_PAGE_TOUT_OFF] & HCI_SUPP_COMMANDS_READ_PAGE_TOUT_MASK) + +#define HCI_SUPP_COMMANDS_WRITE_PAGE_TOUT_MASK 0x20 +#define HCI_SUPP_COMMANDS_WRITE_PAGE_TOUT_OFF 7 +#define HCI_WRITE_PAGE_TOUT_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_WRITE_PAGE_TOUT_OFF] & HCI_SUPP_COMMANDS_WRITE_PAGE_TOUT_MASK) + +#define HCI_SUPP_COMMANDS_READ_SCAN_ENABLE_MASK 0x40 +#define HCI_SUPP_COMMANDS_READ_SCAN_ENABLE_OFF 7 +#define HCI_READ_SCAN_ENABLE_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_READ_SCAN_ENABLE_OFF] & HCI_SUPP_COMMANDS_READ_SCAN_ENABLE_MASK) + +#define HCI_SUPP_COMMANDS_WRITE_SCAN_ENABLE_MASK 0x80 +#define HCI_SUPP_COMMANDS_WRITE_SCAN_ENABLE_OFF 7 +#define HCI_WRITE_SCAN_ENABLE_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_WRITE_SCAN_ENABLE_OFF] & HCI_SUPP_COMMANDS_WRITE_SCAN_ENABLE_MASK) + +#define HCI_SUPP_COMMANDS_READ_PAGE_SCAN_ACTIVITY_MASK 0x01 +#define HCI_SUPP_COMMANDS_READ_PAGE_SCAN_ACTIVITY_OFF 8 +#define HCI_READ_PAGE_SCAN_ACTIVITY_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_READ_PAGE_SCAN_ACTIVITY_OFF] & HCI_SUPP_COMMANDS_READ_PAGE_SCAN_ACTIVITY_MASK) + +#define HCI_SUPP_COMMANDS_WRITE_PAGE_SCAN_ACTIVITY_MASK 0x02 +#define HCI_SUPP_COMMANDS_WRITE_PAGE_SCAN_ACTIVITY_OFF 8 +#define HCI_WRITE_PAGE_SCAN_ACTIVITY_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_WRITE_PAGE_SCAN_ACTIVITY_OFF] & HCI_SUPP_COMMANDS_WRITE_PAGE_SCAN_ACTIVITY_MASK) + +#define HCI_SUPP_COMMANDS_READ_INQURIY_SCAN_ACTIVITY_MASK 0x04 +#define HCI_SUPP_COMMANDS_READ_INQURIY_SCAN_ACTIVITY_OFF 8 +#define HCI_READ_INQURIY_SCAN_ACTIVITY_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_READ_INQURIY_SCAN_ACTIVITY_OFF] & HCI_SUPP_COMMANDS_READ_INQURIY_SCAN_ACTIVITY_MASK) + +#define HCI_SUPP_COMMANDS_WRITE_INQURIY_SCAN_ACTIVITY_MASK 0x08 +#define HCI_SUPP_COMMANDS_WRITE_INQURIY_SCAN_ACTIVITY_OFF 8 +#define HCI_WRITE_INQURIY_SCAN_ACTIVITY_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_WRITE_INQURIY_SCAN_ACTIVITY_OFF] & HCI_SUPP_COMMANDS_WRITE_INQURIY_SCAN_ACTIVITY_MASK) + +#define HCI_SUPP_COMMANDS_READ_AUTH_ENABLE_MASK 0x10 +#define HCI_SUPP_COMMANDS_READ_AUTH_ENABLE_OFF 8 +#define HCI_READ_AUTH_ENABLE_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_READ_AUTH_ENABLE_OFF] & HCI_SUPP_COMMANDS_READ_AUTH_ENABLE_MASK) + +#define HCI_SUPP_COMMANDS_WRITE_AUTH_ENABLE_MASK 0x20 +#define HCI_SUPP_COMMANDS_WRITE_AUTH_ENABLE_OFF 8 +#define HCI_WRITE_AUTH_ENABLE_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_WRITE_AUTH_ENABLE_OFF] & HCI_SUPP_COMMANDS_WRITE_AUTH_ENABLE_MASK) + +#define HCI_SUPP_COMMANDS_READ_ENCRYPT_ENABLE_MASK 0x40 +#define HCI_SUPP_COMMANDS_READ_ENCRYPT_ENABLE_OFF 8 +#define HCI_READ_ENCRYPT_ENABLE_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_READ_ENCRYPT_ENABLE_OFF] & HCI_SUPP_COMMANDS_READ_ENCRYPT_ENABLE_MASK) + +#define HCI_SUPP_COMMANDS_WRITE_ENCRYPT_ENABLE_MASK 0x80 +#define HCI_SUPP_COMMANDS_WRITE_ENCRYPT_ENABLE_OFF 8 +#define HCI_WRITE_ENCRYPT_ENABLE_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_WRITE_ENCRYPT_ENABLE_OFF] & HCI_SUPP_COMMANDS_WRITE_ENCRYPT_ENABLE_MASK) + +#define HCI_SUPP_COMMANDS_READ_CLASS_DEVICE_MASK 0x01 +#define HCI_SUPP_COMMANDS_READ_CLASS_DEVICE_OFF 9 +#define HCI_READ_CLASS_DEVICE_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_READ_CLASS_DEVICE_OFF] & HCI_SUPP_COMMANDS_READ_CLASS_DEVICE_MASK) + +#define HCI_SUPP_COMMANDS_WRITE_CLASS_DEVICE_MASK 0x02 +#define HCI_SUPP_COMMANDS_WRITE_CLASS_DEVICE_OFF 9 +#define HCI_WRITE_CLASS_DEVICE_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_WRITE_CLASS_DEVICE_OFF] & HCI_SUPP_COMMANDS_WRITE_CLASS_DEVICE_MASK) + +#define HCI_SUPP_COMMANDS_READ_VOICE_SETTING_MASK 0x04 +#define HCI_SUPP_COMMANDS_READ_VOICE_SETTING_OFF 9 +#define HCI_READ_VOICE_SETTING_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_READ_VOICE_SETTING_OFF] & HCI_SUPP_COMMANDS_READ_VOICE_SETTING_MASK) + +#define HCI_SUPP_COMMANDS_WRITE_VOICE_SETTING_MASK 0x08 +#define HCI_SUPP_COMMANDS_WRITE_VOICE_SETTING_OFF 9 +#define HCI_WRITE_VOICE_SETTING_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_WRITE_VOICE_SETTING_OFF] & HCI_SUPP_COMMANDS_WRITE_VOICE_SETTING_MASK) + +#define HCI_SUPP_COMMANDS_READ_AUTO_FLUSH_TOUT_MASK 0x10 +#define HCI_SUPP_COMMANDS_READ_AUTO_FLUSH_TOUT_OFF 9 +#define HCI_READ_AUTO_FLUSH_TOUT_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_READ_AUTO_FLUSH_TOUT_OFF] & HCI_SUPP_COMMANDS_READ_AUTO_FLUSH_TOUT_MASK) + +#define HCI_SUPP_COMMANDS_WRITE_AUTO_FLUSH_TOUT_MASK 0x20 +#define HCI_SUPP_COMMANDS_WRITE_AUTO_FLUSH_TOUT_OFF 9 +#define HCI_WRITE_AUTO_FLUSH_TOUT_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_WRITE_AUTO_FLUSH_TOUT_OFF] & HCI_SUPP_COMMANDS_WRITE_AUTO_FLUSH_TOUT_MASK) + +#define HCI_SUPP_COMMANDS_READ_NUM_BROAD_RETRANS_MASK 0x40 +#define HCI_SUPP_COMMANDS_READ_NUM_BROAD_RETRANS_OFF 9 +#define HCI_READ_NUM_BROAD_RETRANS_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_READ_NUM_BROAD_RETRANS_OFF] & HCI_SUPP_COMMANDS_READ_NUM_BROAD_RETRANS_MASK) + +#define HCI_SUPP_COMMANDS_WRITE_NUM_BROAD_RETRANS_MASK 0x80 +#define HCI_SUPP_COMMANDS_WRITE_NUM_BROAD_RETRANS_OFF 9 +#define HCI_WRITE_NUM_BROAD_RETRANS_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_WRITE_NUM_BROAD_RETRANS_OFF] & HCI_SUPP_COMMANDS_WRITE_NUM_BROAD_RETRANS_MASK) + +#define HCI_SUPP_COMMANDS_READ_HOLD_MODE_ACTIVITY_MASK 0x01 +#define HCI_SUPP_COMMANDS_READ_HOLD_MODE_ACTIVITY_OFF 10 +#define HCI_READ_HOLD_MODE_ACTIVITY_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_READ_HOLD_MODE_ACTIVITY_OFF] & HCI_SUPP_COMMANDS_READ_HOLD_MODE_ACTIVITY_MASK) + +#define HCI_SUPP_COMMANDS_WRITE_HOLD_MODE_ACTIVITY_MASK 0x02 +#define HCI_SUPP_COMMANDS_WRITE_HOLD_MODE_ACTIVITY_OFF 10 +#define HCI_WRITE_HOLD_MODE_ACTIVITY_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_WRITE_HOLD_MODE_ACTIVITY_OFF] & HCI_SUPP_COMMANDS_WRITE_HOLD_MODE_ACTIVITY_MASK) + +#define HCI_SUPP_COMMANDS_READ_TRANS_PWR_LEVEL_MASK 0x04 +#define HCI_SUPP_COMMANDS_READ_TRANS_PWR_LEVEL_OFF 10 +#define HCI_READ_TRANS_PWR_LEVEL_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_READ_TRANS_PWR_LEVEL_OFF] & HCI_SUPP_COMMANDS_READ_TRANS_PWR_LEVEL_MASK) + +#define HCI_SUPP_COMMANDS_READ_SYNCH_FLOW_CTRL_ENABLE_MASK 0x08 +#define HCI_SUPP_COMMANDS_READ_SYNCH_FLOW_CTRL_ENABLE_OFF 10 +#define HCI_READ_SYNCH_FLOW_CTRL_ENABLE_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_READ_SYNCH_FLOW_CTRL_ENABLE_OFF] & HCI_SUPP_COMMANDS_READ_SYNCH_FLOW_CTRL_ENABLE_MASK) + +#define HCI_SUPP_COMMANDS_WRITE_SYNCH_FLOW_CTRL_ENABLE_MASK 0x10 +#define HCI_SUPP_COMMANDS_WRITE_SYNCH_FLOW_CTRL_ENABLE_OFF 10 +#define HCI_WRITE_SYNCH_FLOW_CTRL_ENABLE_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_WRITE_SYNCH_FLOW_CTRL_ENABLE_OFF] & HCI_SUPP_COMMANDS_WRITE_SYNCH_FLOW_CTRL_ENABLE_MASK) + +#define HCI_SUPP_COMMANDS_SET_HOST_CTRLR_TO_HOST_FC_MASK 0x20 +#define HCI_SUPP_COMMANDS_SET_HOST_CTRLR_TO_HOST_FC_OFF 10 +#define HCI_SET_HOST_CTRLR_TO_HOST_FC_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_SET_HOST_CTRLR_TO_HOST_FC_OFF] & HCI_SUPP_COMMANDS_SET_HOST_CTRLR_TO_HOST_FC_MASK) + +#define HCI_SUPP_COMMANDS_HOST_BUFFER_SIZE_MASK 0x40 +#define HCI_SUPP_COMMANDS_HOST_BUFFER_SIZE_OFF 10 +#define HCI_HOST_BUFFER_SIZE_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_HOST_BUFFER_SIZE_OFF] & HCI_SUPP_COMMANDS_HOST_BUFFER_SIZE_MASK) + +#define HCI_SUPP_COMMANDS_HOST_NUM_COMPLETED_PKTS_MASK 0x80 +#define HCI_SUPP_COMMANDS_HOST_NUM_COMPLETED_PKTS_OFF 10 +#define HCI_HOST_NUM_COMPLETED_PKTS_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_HOST_NUM_COMPLETED_PKTS_OFF] & HCI_SUPP_COMMANDS_HOST_NUM_COMPLETED_PKTS_MASK) + +#define HCI_SUPP_COMMANDS_READ_LINK_SUP_TOUT_MASK 0x01 +#define HCI_SUPP_COMMANDS_READ_LINK_SUP_TOUT_OFF 11 +#define HCI_READ_LINK_SUP_TOUT_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_READ_LINK_SUP_TOUT_OFF] & HCI_SUPP_COMMANDS_READ_LINK_SUP_TOUT_MASK) + +#define HCI_SUPP_COMMANDS_WRITE_LINK_SUP_TOUT_MASK 0x02 +#define HCI_SUPP_COMMANDS_WRITE_LINK_SUP_TOUT_OFF 11 +#define HCI_WRITE_LINK_SUP_TOUT_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_WRITE_LINK_SUP_TOUT_OFF] & HCI_SUPP_COMMANDS_WRITE_LINK_SUP_TOUT_MASK) + +#define HCI_SUPP_COMMANDS_READ_NUM_SUPP_IAC_MASK 0x04 +#define HCI_SUPP_COMMANDS_READ_NUM_SUPP_IAC_OFF 11 +#define HCI_READ_NUM_SUPP_IAC_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_READ_NUM_SUPP_IAC_OFF] & HCI_SUPP_COMMANDS_READ_NUM_SUPP_IAC_MASK) + +#define HCI_SUPP_COMMANDS_READ_CURRENT_IAC_LAP_MASK 0x08 +#define HCI_SUPP_COMMANDS_READ_CURRENT_IAC_LAP_OFF 11 +#define HCI_READ_CURRENT_IAC_LAP_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_READ_CURRENT_IAC_LAP_OFF] & HCI_SUPP_COMMANDS_READ_CURRENT_IAC_LAP_MASK) + +#define HCI_SUPP_COMMANDS_WRITE_CURRENT_IAC_LAP_MASK 0x10 +#define HCI_SUPP_COMMANDS_WRITE_CURRENT_IAC_LAP_OFF 11 +#define HCI_WRITE_CURRENT_IAC_LAP_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_WRITE_CURRENT_IAC_LAP_OFF] & HCI_SUPP_COMMANDS_WRITE_CURRENT_IAC_LAP_MASK) + +#define HCI_SUPP_COMMANDS_READ_PAGE_SCAN_PER_MODE_MASK 0x20 +#define HCI_SUPP_COMMANDS_READ_PAGE_SCAN_PER_MODE_OFF 11 +#define HCI_READ_PAGE_SCAN_PER_MODE_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_READ_PAGE_SCAN_PER_MODE_OFF] & HCI_SUPP_COMMANDS_READ_PAGE_SCAN_PER_MODE_MASK) + +#define HCI_SUPP_COMMANDS_WRITE_PAGE_SCAN_PER_MODE_MASK 0x40 +#define HCI_SUPP_COMMANDS_WRITE_PAGE_SCAN_PER_MODE_OFF 11 +#define HCI_WRITE_PAGE_SCAN_PER_MODE_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_WRITE_PAGE_SCAN_PER_MODE_OFF] & HCI_SUPP_COMMANDS_WRITE_PAGE_SCAN_PER_MODE_MASK) + +#define HCI_SUPP_COMMANDS_READ_PAGE_SCAN_MODE_MASK 0x80 +#define HCI_SUPP_COMMANDS_READ_PAGE_SCAN_MODE_OFF 11 +#define HCI_READ_PAGE_SCAN_MODE_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_READ_PAGE_SCAN_MODE_OFF] & HCI_SUPP_COMMANDS_READ_PAGE_SCAN_MODE_MASK) + +#define HCI_SUPP_COMMANDS_WRITE_PAGE_SCAN_MODE_MASK 0x01 +#define HCI_SUPP_COMMANDS_WRITE_PAGE_SCAN_MODE_OFF 12 +#define HCI_WRITE_PAGE_SCAN_MODE_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_WRITE_PAGE_SCAN_MODE_OFF] & HCI_SUPP_COMMANDS_WRITE_PAGE_SCAN_MODE_MASK) + +#define HCI_SUPP_COMMANDS_SET_AFH_CHNL_CLASS_MASK 0x02 +#define HCI_SUPP_COMMANDS_SET_AFH_CHNL_CLASS_OFF 12 +#define HCI_SET_AFH_CHNL_CLASS_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_SET_AFH_CHNL_CLASS_OFF] & HCI_SUPP_COMMANDS_SET_AFH_CHNL_CLASS_MASK) + +#define HCI_SUPP_COMMANDS_READ_INQUIRY_SCAN_TYPE_MASK 0x10 +#define HCI_SUPP_COMMANDS_READ_INQUIRY_SCAN_TYPE_OFF 12 +#define HCI_READ_INQUIRY_SCAN_TYPE_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_READ_INQUIRY_SCAN_TYPE_OFF] & HCI_SUPP_COMMANDS_READ_INQUIRY_SCAN_TYPE_MASK) + +#define HCI_SUPP_COMMANDS_WRITE_INQUIRY_SCAN_TYPE_MASK 0x20 +#define HCI_SUPP_COMMANDS_WRITE_INQUIRY_SCAN_TYPE_OFF 12 +#define HCI_WRITE_INQUIRY_SCAN_TYPE_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_WRITE_INQUIRY_SCAN_TYPE_OFF] & HCI_SUPP_COMMANDS_WRITE_INQUIRY_SCAN_TYPE_MASK) + +#define HCI_SUPP_COMMANDS_READ_INQUIRY_MODE_MASK 0x40 +#define HCI_SUPP_COMMANDS_READ_INQUIRY_MODE_OFF 12 +#define HCI_READ_INQUIRY_MODE_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_READ_INQUIRY_MODE_OFF] & HCI_SUPP_COMMANDS_READ_INQUIRY_MODE_MASK) + +#define HCI_SUPP_COMMANDS_WRITE_INQUIRY_MODE_MASK 0x80 +#define HCI_SUPP_COMMANDS_WRITE_INQUIRY_MODE_OFF 12 +#define HCI_WRITE_INQUIRY_MODE_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_WRITE_INQUIRY_MODE_OFF] & HCI_SUPP_COMMANDS_WRITE_INQUIRY_MODE_MASK) + +#define HCI_SUPP_COMMANDS_READ_PAGE_SCAN_TYPE_MASK 0x01 +#define HCI_SUPP_COMMANDS_READ_PAGE_SCAN_TYPE_OFF 13 +#define HCI_READ_PAGE_SCAN_TYPE_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_READ_PAGE_SCAN_TYPE_OFF] & HCI_SUPP_COMMANDS_READ_PAGE_SCAN_TYPE_MASK) + +#define HCI_SUPP_COMMANDS_WRITE_PAGE_SCAN_TYPE_MASK 0x02 +#define HCI_SUPP_COMMANDS_WRITE_PAGE_SCAN_TYPE_OFF 13 +#define HCI_WRITE_PAGE_SCAN_TYPE_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_WRITE_PAGE_SCAN_TYPE_OFF] & HCI_SUPP_COMMANDS_WRITE_PAGE_SCAN_TYPE_MASK) + +#define HCI_SUPP_COMMANDS_READ_AFH_CHNL_ASSESS_MODE_MASK 0x04 +#define HCI_SUPP_COMMANDS_READ_AFH_CHNL_ASSESS_MODE_OFF 13 +#define HCI_READ_AFH_CHNL_ASSESS_MODE_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_READ_AFH_CHNL_ASSESS_MODE_OFF] & HCI_SUPP_COMMANDS_READ_AFH_CHNL_ASSESS_MODE_MASK) + +#define HCI_SUPP_COMMANDS_WRITE_AFH_CHNL_ASSESS_MODE_MASK 0x08 +#define HCI_SUPP_COMMANDS_WRITE_AFH_CHNL_ASSESS_MODE_OFF 13 +#define HCI_WRITE_AFH_CHNL_ASSESS_MODE_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_WRITE_AFH_CHNL_ASSESS_MODE_OFF] & HCI_SUPP_COMMANDS_WRITE_AFH_CHNL_ASSESS_MODE_MASK) + +#define HCI_SUPP_COMMANDS_READ_LOCAL_VER_INFO_MASK 0x08 +#define HCI_SUPP_COMMANDS_READ_LOCAL_VER_INFO_OFF 14 +#define HCI_READ_LOCAL_VER_INFO_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_READ_LOCAL_VER_INFO_OFF] & HCI_SUPP_COMMANDS_READ_LOCAL_VER_INFO_MASK) + +#define HCI_SUPP_COMMANDS_READ_LOCAL_SUP_CMDS_MASK 0x10 +#define HCI_SUPP_COMMANDS_READ_LOCAL_SUP_CMDS_OFF 14 +#define HCI_READ_LOCAL_SUP_CMDS_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_READ_LOCAL_SUP_CMDS_OFF] & HCI_SUPP_COMMANDS_READ_LOCAL_SUP_CMDS_MASK) + +#define HCI_SUPP_COMMANDS_READ_LOCAL_SUPP_FEATURES_MASK 0x20 +#define HCI_SUPP_COMMANDS_READ_LOCAL_SUPP_FEATURES_OFF 14 +#define HCI_READ_LOCAL_SUPP_FEATURES_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_READ_LOCAL_SUPP_FEATURES_OFF] & HCI_SUPP_COMMANDS_READ_LOCAL_SUPP_FEATURES_MASK) + +#define HCI_SUPP_COMMANDS_READ_LOCAL_EXT_FEATURES_MASK 0x40 +#define HCI_SUPP_COMMANDS_READ_LOCAL_EXT_FEATURES_OFF 14 +#define HCI_READ_LOCAL_EXT_FEATURES_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_READ_LOCAL_EXT_FEATURES_OFF] & HCI_SUPP_COMMANDS_READ_LOCAL_EXT_FEATURES_MASK) + +#define HCI_SUPP_COMMANDS_READ_BUFFER_SIZE_MASK 0x80 +#define HCI_SUPP_COMMANDS_READ_BUFFER_SIZE_OFF 14 +#define HCI_READ_BUFFER_SIZE_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_READ_BUFFER_SIZE_OFF] & HCI_SUPP_COMMANDS_READ_BUFFER_SIZE_MASK) + +#define HCI_SUPP_COMMANDS_READ_COUNTRY_CODE_MASK 0x01 +#define HCI_SUPP_COMMANDS_READ_COUNTRY_CODE_OFF 15 +#define HCI_READ_COUNTRY_CODE_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_READ_COUNTRY_CODE_OFF] & HCI_SUPP_COMMANDS_READ_COUNTRY_CODE_MASK) + +#define HCI_SUPP_COMMANDS_READ_BD_ADDR_MASK 0x02 +#define HCI_SUPP_COMMANDS_READ_BD_ADDR_OFF 15 +#define HCI_READ_BD_ADDR_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_READ_BD_ADDR_OFF] & HCI_SUPP_COMMANDS_READ_BD_ADDR_MASK) + +#define HCI_SUPP_COMMANDS_READ_FAIL_CONTACT_CNTR_MASK 0x04 +#define HCI_SUPP_COMMANDS_READ_FAIL_CONTACT_CNTR_OFF 15 +#define HCI_READ_FAIL_CONTACT_CNTR_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_READ_FAIL_CONTACT_CNTR_OFF] & HCI_SUPP_COMMANDS_READ_FAIL_CONTACT_CNTR_MASK) + +#define HCI_SUPP_COMMANDS_RESET_FAIL_CONTACT_CNTR_MASK 0x08 +#define HCI_SUPP_COMMANDS_RESET_FAIL_CONTACT_CNTR_OFF 15 +#define HCI_RESET_FAIL_CONTACT_CNTR_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_RESET_FAIL_CONTACT_CNTR_OFF] & HCI_SUPP_COMMANDS_RESET_FAIL_CONTACT_CNTR_MASK) + +#define HCI_SUPP_COMMANDS_GET_LINK_QUALITY_MASK 0x10 +#define HCI_SUPP_COMMANDS_GET_LINK_QUALITY_OFF 15 +#define HCI_GET_LINK_QUALITY_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_GET_LINK_QUALITY_OFF] & HCI_SUPP_COMMANDS_GET_LINK_QUALITY_MASK) + +#define HCI_SUPP_COMMANDS_READ_RSSI_MASK 0x20 +#define HCI_SUPP_COMMANDS_READ_RSSI_OFF 15 +#define HCI_READ_RSSI_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_READ_RSSI_OFF] & HCI_SUPP_COMMANDS_READ_RSSI_MASK) + +#define HCI_SUPP_COMMANDS_READ_AFH_CH_MAP_MASK 0x40 +#define HCI_SUPP_COMMANDS_READ_AFH_CH_MAP_OFF 15 +#define HCI_READ_AFH_CH_MAP_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_READ_AFH_CH_MAP_OFF] & HCI_SUPP_COMMANDS_READ_AFH_CH_MAP_MASK) + +#define HCI_SUPP_COMMANDS_READ_BD_CLOCK_MASK 0x80 +#define HCI_SUPP_COMMANDS_READ_BD_CLOCK_OFF 15 +#define HCI_READ_BD_CLOCK_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_READ_BD_CLOCK_OFF] & HCI_SUPP_COMMANDS_READ_BD_CLOCK_MASK) + +#define HCI_SUPP_COMMANDS_READ_LOOPBACK_MODE_MASK 0x01 +#define HCI_SUPP_COMMANDS_READ_LOOPBACK_MODE_OFF 16 +#define HCI_READ_LOOPBACK_MODE_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_READ_LOOPBACK_MODE_OFF] & HCI_SUPP_COMMANDS_READ_LOOPBACK_MODE_MASK) + +#define HCI_SUPP_COMMANDS_WRITE_LOOPBACK_MODE_MASK 0x02 +#define HCI_SUPP_COMMANDS_WRITE_LOOPBACK_MODE_OFF 16 +#define HCI_WRITE_LOOPBACK_MODE_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_WRITE_LOOPBACK_MODE_OFF] & HCI_SUPP_COMMANDS_WRITE_LOOPBACK_MODE_MASK) + +#define HCI_SUPP_COMMANDS_ENABLE_DEV_UNDER_TEST_MASK 0x04 +#define HCI_SUPP_COMMANDS_ENABLE_DEV_UNDER_TEST_OFF 16 +#define HCI_ENABLE_DEV_UNDER_TEST_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_ENABLE_DEV_UNDER_TEST_OFF] & HCI_SUPP_COMMANDS_ENABLE_DEV_UNDER_TEST_MASK) + +#define HCI_SUPP_COMMANDS_SETUP_SYNCH_CONN_MASK 0x08 +#define HCI_SUPP_COMMANDS_SETUP_SYNCH_CONN_OFF 16 +#define HCI_SETUP_SYNCH_CONN_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_SETUP_SYNCH_CONN_OFF] & HCI_SUPP_COMMANDS_SETUP_SYNCH_CONN_MASK) + +#define HCI_SUPP_COMMANDS_ACCEPT_SYNCH_CONN_MASK 0x10 +#define HCI_SUPP_COMMANDS_ACCEPT_SYNCH_CONN_OFF 16 +#define HCI_ACCEPT_SYNCH_CONN_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_ACCEPT_SYNCH_CONN_OFF] & HCI_SUPP_COMMANDS_ACCEPT_SYNCH_CONN_MASK) + +#define HCI_SUPP_COMMANDS_REJECT_SYNCH_CONN_MASK 0x20 +#define HCI_SUPP_COMMANDS_REJECT_SYNCH_CONN_OFF 16 +#define HCI_REJECT_SYNCH_CONN_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_REJECT_SYNCH_CONN_OFF] & HCI_SUPP_COMMANDS_REJECT_SYNCH_CONN_MASK) + +#define HCI_SUPP_COMMANDS_READ_EXT_INQUIRY_RESP_MASK 0x01 +#define HCI_SUPP_COMMANDS_READ_EXT_INQUIRY_RESP_OFF 17 +#define HCI_READ_EXT_INQUIRY_RESP_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_READ_EXT_INQUIRY_RESP_OFF] & HCI_SUPP_COMMANDS_READ_EXT_INQUIRY_RESP_MASK) + +#define HCI_SUPP_COMMANDS_WRITE_EXT_INQUIRY_RESP_MASK 0x02 +#define HCI_SUPP_COMMANDS_WRITE_EXT_INQUIRY_RESP_OFF 17 +#define HCI_WRITE_EXT_INQUIRY_RESP_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_WRITE_EXT_INQUIRY_RESP_OFF] & HCI_SUPP_COMMANDS_WRITE_EXT_INQUIRY_RESP_MASK) + +#define HCI_SUPP_COMMANDS_REFRESH_ENCRYPTION_KEY_MASK 0x04 +#define HCI_SUPP_COMMANDS_REFRESH_ENCRYPTION_KEY_OFF 17 +#define HCI_REFRESH_ENCRYPTION_KEY_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_REFRESH_ENCRYPTION_KEY_OFF] & HCI_SUPP_COMMANDS_REFRESH_ENCRYPTION_KEY_MASK) + +/* Octet 17, bit 3 is reserved */ + +#define HCI_SUPP_COMMANDS_SNIFF_SUB_RATE_MASK 0x10 +#define HCI_SUPP_COMMANDS_SNIFF_SUB_RATE_OFF 17 +#define HCI_SNIFF_SUB_RATE_CMD_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_SNIFF_SUB_RATE_OFF] & HCI_SUPP_COMMANDS_SNIFF_SUB_RATE_MASK) + +#define HCI_SUPP_COMMANDS_READ_SIMPLE_PAIRING_MODE_MASK 0x20 +#define HCI_SUPP_COMMANDS_READ_SIMPLE_PAIRING_MODE_OFF 17 +#define HCI_READ_SIMPLE_PAIRING_MODE_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_READ_SIMPLE_PAIRING_MODE_OFF] & HCI_SUPP_COMMANDS_READ_SIMPLE_PAIRING_MODE_MASK) + +#define HCI_SUPP_COMMANDS_WRITE_SIMPLE_PAIRING_MODE_MASK 0x40 +#define HCI_SUPP_COMMANDS_WRITE_SIMPLE_PAIRING_MODE_OFF 17 +#define HCI_WRITE_SIMPLE_PAIRING_MODE_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_WRITE_SIMPLE_PAIRING_MODE_OFF] & HCI_SUPP_COMMANDS_WRITE_SIMPLE_PAIRING_MODE_MASK) + +#define HCI_SUPP_COMMANDS_READ_LOCAL_OOB_DATA_MASK 0x80 +#define HCI_SUPP_COMMANDS_READ_LOCAL_OOB_DATA_OFF 17 +#define HCI_READ_LOCAL_OOB_DATA_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_READ_LOCAL_OOB_DATA_OFF] & HCI_SUPP_COMMANDS_READ_LOCAL_OOB_DATA_MASK) + +#define HCI_SUPP_COMMANDS_READ_INQUIRY_RESPONSE_TX_POWER_MASK 0x01 +#define HCI_SUPP_COMMANDS_READ_INQUIRY_RESPONSE_TX_POWER_OFF 18 +#define HCI_READ_INQUIRY_RESPONSE_TX_POWER_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_READ_INQUIRY_RESPONSE_TX_POWER_OFF] & HCI_SUPP_COMMANDS_READ_INQUIRY_RESPONSE_TX_POWER_MASK) + +#define HCI_SUPP_COMMANDS_WRITE_INQUIRY_RESPONSE_TX_POWER_MASK 0x02 +#define HCI_SUPP_COMMANDS_WRITE_INQUIRY_RESPONSE_TX_POWER_OFF 18 +#define HCI_WRITE_INQUIRY_RESPONSE_TX_POWER_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_WRITE_INQUIRY_RESPONSE_TX_POWER_OFF] & HCI_SUPP_COMMANDS_WRITE_INQUIRY_RESPONSE_TX_POWER_MASK) + +#define HCI_SUPP_COMMANDS_READ_DEFAULT_ERRONEOUS_DATA_REPORTING_MASK 0x04 +#define HCI_SUPP_COMMANDS_READ_DEFAULT_ERRONEOUS_DATA_REPORTING_OFF 18 +#define HCI_READ_DEFAULT_ERRONEOUS_DATA_REPORTING_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_READ_DEFAULT_ERRONEOUS_DATA_REPORTING_OFF] & HCI_SUPP_COMMANDS_READ_DEFAULT_ERRONEOUS_DATA_REPORTING_MASK) + +#define HCI_SUPP_COMMANDS_WRITE_DEFAULT_ERRONEOUS_DATA_REPORTING_MASK 0x08 +#define HCI_SUPP_COMMANDS_WRITE_DEFAULT_ERRONEOUS_DATA_REPORTING_OFF 18 +#define HCI_WRITE_DEFAULT_ERRONEOUS_DATA_REPORTING_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_WRITE_DEFAULT_ERRONEOUS_DATA_REPORTING_OFF] & HCI_SUPP_COMMANDS_WRITE_DEFAULT_ERRONEOUS_DATA_REPORTING_MASK) + +#define HCI_SUPP_COMMANDS_IO_CAPABILITY_REQUEST_REPLY_MASK 0x80 +#define HCI_SUPP_COMMANDS_IO_CAPABILITY_REQUEST_REPLY_OFF 18 +#define HCI_IO_CAPABILITY_REQUEST_REPLY_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_IO_CAPABILITY_REQUEST_REPLY_OFF] & HCI_SUPP_COMMANDS_IO_CAPABILITY_REQUEST_REPLY_MASK) + +#define HCI_SUPP_COMMANDS_USER_CONFIRMATION_REQUEST_REPLY_MASK 0x01 +#define HCI_SUPP_COMMANDS_USER_CONFIRMATION_REQUEST_REPLY_OFF 19 +#define HCI_USER_CONFIRMATION_REQUEST_REPLY_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_USER_CONFIRMATION_REQUEST_REPLY_OFF] & HCI_SUPP_COMMANDS_USER_CONFIRMATION_REQUEST_REPLY_MASK) + +#define HCI_SUPP_COMMANDS_USER_CONFIRMATION_REQUEST_NEG_REPLY_MASK 0x02 +#define HCI_SUPP_COMMANDS_USER_CONFIRMATION_REQUEST_NEG_REPLY_OFF 19 +#define HCI_USER_CONFIRMATION_REQUEST_NEG_REPLY_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_USER_CONFIRMATION_REQUEST_NEG_REPLY_OFF] & HCI_SUPP_COMMANDS_USER_CONFIRMATION_REQUEST_NEG_REPLY_MASK) + +#define HCI_SUPP_COMMANDS_USER_PASSKEY_REQUEST_REPLY_MASK 0x04 +#define HCI_SUPP_COMMANDS_USER_PASSKEY_REQUEST_REPLY_OFF 19 +#define HCI_USER_PASSKEY_REQUEST_REPLY_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_USER_PASSKEY_REQUEST_REPLY_OFF] & HCI_SUPP_COMMANDS_USER_PASSKEY_REQUEST_REPLY_MASK) + +#define HCI_SUPP_COMMANDS_USER_PASSKEY_REQUEST_NEG_REPLY_MASK 0x08 +#define HCI_SUPP_COMMANDS_USER_PASSKEY_REQUEST_NEG_REPLY_OFF 19 +#define HCI_USER_PASSKEY_REQUEST_NEG_REPLY_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_USER_PASSKEY_REQUEST_NEG_REPLY_OFF] & HCI_SUPP_COMMANDS_USER_PASSKEY_REQUEST_NEG_REPLY_MASK) + +#define HCI_SUPP_COMMANDS_REMOTE_OOB_DATA_REQUEST_REPLY_MASK 0x10 +#define HCI_SUPP_COMMANDS_REMOTE_OOB_DATA_REQUEST_REPLY_OFF 19 +#define HCI_REMOTE_OOB_DATA_REQUEST_REPLY_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_REMOTE_OOB_DATA_REQUEST_REPLY_OFF] & HCI_SUPP_COMMANDS_REMOTE_OOB_DATA_REQUEST_REPLY_MASK) + +#define HCI_SUPP_COMMANDS_WRITE_SIMPLE_PAIRING_DBG_MODE_MASK 0x20 +#define HCI_SUPP_COMMANDS_WRITE_SIMPLE_PAIRING_DBG_MODE_OFF 19 +#define HCI_WRITE_SIMPLE_PAIRING_DBG_MODE_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_WRITE_SIMPLE_PAIRING_DBG_MODE_OFF] & HCI_SUPP_COMMANDS_WRITE_SIMPLE_PAIRING_DBG_MODE_MASK) + +#define HCI_SUPP_COMMANDS_ENHANCED_FLUSH_MASK 0x40 +#define HCI_SUPP_COMMANDS_ENHANCED_FLUSH_OFF 19 +#define HCI_ENHANCED_FLUSH_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_ENHANCED_FLUSH_OFF] & HCI_SUPP_COMMANDS_ENHANCED_FLUSH_MASK) + +#define HCI_SUPP_COMMANDS_REMOTE_OOB_DATA_REQUEST_NEG_REPLY_MASK 0x80 +#define HCI_SUPP_COMMANDS_REMOTE_OOB_DATA_REQUEST_NEG_REPLY_OFF 19 +#define HCI_REMOTE_OOB_DATA_REQUEST_NEG_REPLY_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_REMOTE_OOB_DATA_REQUEST_NEG_REPLY_OFF] & HCI_SUPP_COMMANDS_REMOTE_OOB_DATA_REQUEST_NEG_REPLY_MASK) + +/* Supported Commands (Byte 20) */ +#define HCI_SUPP_COMMANDS_SEND_KEYPRESS_NOTIF_MASK 0x04 +#define HCI_SUPP_COMMANDS_SEND_KEYPRESS_NOTIF_OFF 20 +#define HCI_SEND_NOTIF_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_SEND_KEYPRESS_NOTIF_OFF] & HCI_SUPP_COMMANDS_SEND_KEYPRESS_NOTIF_MASK) + +#define HCI_SUPP_COMMANDS_IO_CAP_REQ_NEG_REPLY_MASK 0x08 +#define HCI_SUPP_COMMANDS_IO_CAP_REQ_NEG_REPLY_OFF 20 +#define HCI_IO_CAP_REQ_NEG_REPLY_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_IO_CAP_REQ_NEG_REPLY_OFF] & HCI_SUPP_COMMANDS_IO_CAP_REQ_NEG_REPLY_MASK) + +#define HCI_SUPP_COMMANDS_READ_ENCR_KEY_SIZE_MASK 0x10 +#define HCI_SUPP_COMMANDS_READ_ENCR_KEY_SIZE_OFF 20 +#define HCI_READ_ENCR_KEY_SIZE_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_READ_ENCR_KEY_SIZE_OFF] & HCI_SUPP_COMMANDS_READ_ENCR_KEY_SIZE_MASK) + +/* Supported Commands (Byte 21) */ +#define HCI_SUPP_COMMANDS_CREATE_PHYSICAL_LINK_MASK 0x01 +#define HCI_SUPP_COMMANDS_CREATE_PHYSICAL_LINK_OFF 21 +#define HCI_CREATE_PHYSICAL_LINK_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_CREATE_PHYSICAL_LINK_OFF] & HCI_SUPP_COMMANDS_CREATE_PHYSICAL_LINK_MASK) + +#define HCI_SUPP_COMMANDS_ACCEPT_PHYSICAL_LINK_MASK 0x02 +#define HCI_SUPP_COMMANDS_ACCEPT_PHYSICAL_LINK_OFF 21 +#define HCI_ACCEPT_PHYSICAL_LINK_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_ACCEPT_PHYSICAL_LINK_OFF] & HCI_SUPP_COMMANDS_ACCEPT_PHYSICAL_LINK_MASK) + +#define HCI_SUPP_COMMANDS_DISCONNECT_PHYSICAL_LINK_MASK 0x04 +#define HCI_SUPP_COMMANDS_DISCONNECT_PHYSICAL_LINK_OFF 21 +#define HCI_DISCONNECT_PHYSICAL_LINK_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_DISCONNECT_PHYSICAL_LINK_OFF] & HCI_SUPP_COMMANDS_DISCONNECT_PHYSICAL_LINK_MASK) + +#define HCI_SUPP_COMMANDS_CREATE_LOGICAL_LINK_MASK 0x08 +#define HCI_SUPP_COMMANDS_CREATE_LOGICAL_LINK_OFF 21 +#define HCI_CREATE_LOGICAL_LINK_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_CREATE_LOGICAL_LINK_OFF] & HCI_SUPP_COMMANDS_CREATE_LOGICAL_LINK_MASK) + +#define HCI_SUPP_COMMANDS_ACCEPT_LOGICAL_LINK_MASK 0x10 +#define HCI_SUPP_COMMANDS_ACCEPT_LOGICAL_LINK_OFF 21 +#define HCI_ACCEPT_LOGICAL_LINK_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_ACCEPT_LOGICAL_LINK_OFF] & HCI_SUPP_COMMANDS_ACCEPT_LOGICAL_LINK_MASK) + +#define HCI_SUPP_COMMANDS_DISCONNECT_LOGICAL_LINK_MASK 0x20 +#define HCI_SUPP_COMMANDS_DISCONNECT_LOGICAL_LINK_OFF 21 +#define HCI_DISCONNECT_LOGICAL_LINK_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_DISCONNECT_LOGICAL_LINK_OFF] & HCI_SUPP_COMMANDS_DISCONNECT_LOGICAL_LINK_MASK) + +#define HCI_SUPP_COMMANDS_LOGICAL_LINK_CANCEL_MASK 0x40 +#define HCI_SUPP_COMMANDS_LOGICAL_LINK_CANCEL_OFF 21 +#define HCI_LOGICAL_LINK_CANCEL_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_LOGICAL_LINK_CANCEL_OFF] & HCI_SUPP_COMMANDS_LOGICAL_LINK_CANCEL_MASK) + +#define HCI_SUPP_COMMANDS_FLOW_SPEC_MODIFY_MASK 0x80 +#define HCI_SUPP_COMMANDS_FLOW_SPEC_MODIFY_OFF 21 +#define HCI_FLOW_SPEC_MODIFY_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_FLOW_SPEC_MODIFY_OFF] & HCI_SUPP_COMMANDS_FLOW_SPEC_MODIFY_MASK) + +/* Supported Commands (Byte 22) */ +#define HCI_SUPP_COMMANDS_READ_LOGICAL_LINK_ACCEPT_TIMEOUT_MASK 0x01 +#define HCI_SUPP_COMMANDS_READ_LOGICAL_LINK_ACCEPT_TIMEOUT_OFF 22 +#define HCI_READ_LOGICAL_LINK_ACCEPT_TIMEOUT_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_READ_LOGICAL_LINK_ACCEPT_TIMEOUT_OFF] & HCI_SUPP_COMMANDS_READ_LOGICAL_LINK_ACCEPT_TIMEOUT_MASK) + +#define HCI_SUPP_COMMANDS_WRITE_LOGICAL_LINK_ACCEPT_TIMEOUT_MASK 0x02 +#define HCI_SUPP_COMMANDS_WRITE_LOGICAL_LINK_ACCEPT_TIMEOUT_OFF 22 +#define HCI_WRITE_LOGICAL_LINK_ACCEPT_TIMEOUT_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_WRITE_LOGICAL_LINK_ACCEPT_TIMEOUT_OFF] & HCI_SUPP_COMMANDS_WRITE_LOGICAL_LINK_ACCEPT_TIMEOUT_MASK) + +#define HCI_SUPP_COMMANDS_SET_EVENT_MASK_PAGE_2_MASK 0x04 +#define HCI_SUPP_COMMANDS_SET_EVENT_MASK_PAGE_2_OFF 22 +#define HCI_SET_EVENT_MASK_PAGE_2_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_SET_EVENT_MASK_PAGE_2_OFF] & HCI_SUPP_COMMANDS_SET_EVENT_MASK_PAGE_2_MASK) + +#define HCI_SUPP_COMMANDS_READ_LOCATION_DATA_MASK 0x08 +#define HCI_SUPP_COMMANDS_READ_LOCATION_DATA_OFF 22 +#define HCI_READ_LOCATION_DATA_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_READ_LOCATION_DATA_OFF] & HCI_SUPP_COMMANDS_READ_LOCATION_DATA_MASK) + +#define HCI_SUPP_COMMANDS_WRITE_LOCATION_DATA_MASK 0x10 +#define HCI_SUPP_COMMANDS_WRITE_LOCATION_DATA_OFF 22 +#define HCI_WRITE_LOCATION_DATA_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_WRITE_LOCATION_DATA_OFF] & HCI_SUPP_COMMANDS_WRITE_LOCATION_DATA_MASK) + +#define HCI_SUPP_COMMANDS_READ_LOCAL_AMP_INFO_MASK 0x20 +#define HCI_SUPP_COMMANDS_READ_LOCAL_AMP_INFO_OFF 22 +#define HCI_READ_LOCAL_AMP_INFO_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_READ_LOCAL_AMP_INFO_OFF] & HCI_SUPP_COMMANDS_READ_LOCAL_AMP_INFO_MASK) + +#define HCI_SUPP_COMMANDS_READ_LOCAL_AMP_ASSOC_MASK 0x40 +#define HCI_SUPP_COMMANDS_READ_LOCAL_AMP_ASSOC_OFF 22 +#define HCI_READ_LOCAL_AMP_ASSOC_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_READ_LOCAL_AMP_ASSOC_OFF] & HCI_SUPP_COMMANDS_READ_LOCAL_AMP_ASSOC_MASK) + +#define HCI_SUPP_COMMANDS_WRITE_REMOTE_AMP_ASSOC_MASK 0x80 +#define HCI_SUPP_COMMANDS_WRITE_REMOTE_AMP_ASSOC_OFF 22 +#define HCI_WRITE_REMOTE_AMP_ASSOC_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_WRITE_REMOTE_AMP_ASSOC_OFF] & HCI_SUPP_COMMANDS_WRITE_REMOTE_AMP_ASSOC_MASK) + +/* Supported Commands (Byte 23) */ +#define HCI_SUPP_COMMANDS_READ_FLOW_CONTROL_MODE_MASK 0x01 +#define HCI_SUPP_COMMANDS_READ_FLOW_CONTROL_MODE_OFF 23 +#define HCI_READ_FLOW_CONTROL_MODE_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_READ_FLOW_CONTROL_MODE_OFF] & HCI_SUPP_COMMANDS_READ_FLOW_CONTROL_MODE_MASK) + +#define HCI_SUPP_COMMANDS_WRITE_FLOW_CONTROL_MODE_MASK 0x02 +#define HCI_SUPP_COMMANDS_WRITE_FLOW_CONTROL_MODE_OFF 23 +#define HCI_WRITE_FLOW_CONTROL_MODE_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_WRITE_FLOW_CONTROL_MODE_OFF] & HCI_SUPP_COMMANDS_WRITE_FLOW_CONTROL_MODE_MASK) + +#define HCI_SUPP_COMMANDS_READ_DATA_BLOCK_SIZE_MASK 0x04 +#define HCI_SUPP_COMMANDS_READ_DATA_BLOCK_SIZE_OFF 23 +#define HCI_READ_DATA_BLOCK_SIZE_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_READ_DATA_BLOCK_SIZE_OFF] & HCI_SUPP_COMMANDS_READ_DATA_BLOCK_SIZE_MASK) + +#define HCI_SUPP_COMMANDS_ENABLE_AMP_RCVR_REPORTS_MASK 0x20 +#define HCI_SUPP_COMMANDS_ENABLE_AMP_RCVR_REPORTS_OFF 23 +#define HCI_ENABLE_AMP_RCVR_REPORTS_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_ENABLE_AMP_RCVR_REPORTS_OFF] & HCI_SUPP_COMMANDS_ENABLE_AMP_RCVR_REPORTS_MASK) + +#define HCI_SUPP_COMMANDS_AMP_TEST_END_MASK 0x40 +#define HCI_SUPP_COMMANDS_AMP_TEST_END_OFF 23 +#define HCI_AMP_TEST_END_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_AMP_TEST_END_OFF] & HCI_SUPP_COMMANDS_AMP_TEST_END_MASK) + +#define HCI_SUPP_COMMANDS_AMP_TEST_MASK 0x80 +#define HCI_SUPP_COMMANDS_AMP_TEST_OFF 23 +#define HCI_AMP_TEST_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_AMP_TEST_OFF] & HCI_SUPP_COMMANDS_AMP_TEST_MASK) + +/* Supported Commands (Byte 24) */ +#define HCI_SUPP_COMMANDS_READ_TRANSMIT_POWER_LEVEL_MASK 0x01 +#define HCI_SUPP_COMMANDS_READ_TRANSMIT_POWER_LEVEL_OFF 24 +#define HCI_READ_TRANSMIT_POWER_LEVEL_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_READ_TRANSMIT_POWER_LEVEL_OFF] & HCI_SUPP_COMMANDS_READ_TRANSMIT_POWER_LEVEL_MASK) + +#define HCI_SUPP_COMMANDS_READ_BE_FLUSH_TOUT_MASK 0x04 +#define HCI_SUPP_COMMANDS_READ_BE_FLUSH_TOUT_OFF 24 +#define HCI_READ_BE_FLUSH_TOUT_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_READ_BE_FLUSH_TOUT_OFF] & HCI_SUPP_COMMANDS_READ_BE_FLUSH_TOUT_MASK) + +#define HCI_SUPP_COMMANDS_WRITE_BE_FLUSH_TOUT_MASK 0x08 +#define HCI_SUPP_COMMANDS_WRITE_BE_FLUSH_TOUT_OFF 24 +#define HCI_WRITE_BE_FLUSH_TOUT_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_WRITE_BE_FLUSH_TOUT_OFF] & HCI_SUPP_COMMANDS_WRITE_BE_FLUSH_TOUT_MASK) + +#define HCI_SUPP_COMMANDS_SHORT_RANGE_MODE_MASK 0x10 +#define HCI_SUPP_COMMANDS_SHORT_RANGE_MODE_OFF 24 +#define HCI_SHORT_RANGE_MODE_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_SHORT_RANGE_MODE_OFF] & HCI_SUPP_COMMANDS_SHORT_RANGE_MODE_MASK) + +/* LE commands TBD +** Supported Commands (Byte 24 continued) +** Supported Commands (Byte 25) +** Supported Commands (Byte 26) +** Supported Commands (Byte 27) +** Supported Commands (Byte 28) +*/ + +/* Supported Commands (Byte 29) */ +#define HCI_SUPP_COMMANDS_ENH_SETUP_SYNCH_CONN_MASK 0x08 +#define HCI_SUPP_COMMANDS_ENH_SETUP_SYNCH_CONN_OFF 29 +#define HCI_READ_ENH_SETUP_SYNCH_CONN_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_ENH_SETUP_SYNCH_CONN_OFF] & HCI_SUPP_COMMANDS_ENH_SETUP_SYNCH_CONN_MASK) + +#define HCI_SUPP_COMMANDS_ENH_ACCEPT_SYNCH_CONN_MASK 0x10 +#define HCI_SUPP_COMMANDS_ENH_ACCEPT_SYNCH_CONN_OFF 29 +#define HCI_READ_ENH_ACCEPT_SYNCH_CONN_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_ENH_ACCEPT_SYNCH_CONN_OFF] & HCI_SUPP_COMMANDS_ENH_ACCEPT_SYNCH_CONN_MASK) + +#define HCI_SUPP_COMMANDS_READ_LOCAL_CODECS_MASK 0x20 +#define HCI_SUPP_COMMANDS_READ_LOCAL_CODECS_OFF 29 +#define HCI_READ_LOCAL_CODECS_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_READ_LOCAL_CODECS_OFF] & HCI_SUPP_COMMANDS_READ_LOCAL_CODECS_MASK) + +#define HCI_SUPP_COMMANDS_SET_MWS_CHANN_PARAM_MASK 0x40 +#define HCI_SUPP_COMMANDS_SET_MWS_CHANN_PARAM_OFF 29 +#define HCI_SET_MWS_CHANNEL_PARAMETERS_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_SET_MWS_CHANN_PARAM_OFF] & HCI_SUPP_COMMANDS_SET_MWS_CHANN_PARAM_MASK) + +#define HCI_SUPP_COMMANDS_SET_EXT_FRAME_CONF_MASK 0x80 +#define HCI_SUPP_COMMANDS_SET_EXT_FRAME_CONF_OFF 29 +#define HCI_SET_EXTERNAL_FRAME_CONFIGURATION_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_SET_EXT_FRAME_CONF_OFF] & HCI_SUPP_COMMANDS_SET_EXT_FRAME_CONF_MASK) + + +/* Supported Commands (Byte 30) */ +#define HCI_SUPP_COMMANDS_SET_MWS_SIGNALING_MASK 0x01 +#define HCI_SUPP_COMMANDS_SET_MWS_SIGNALING_OFF 30 +#define HCI_SET_MWS_SIGNALING_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_SET_MWS_SIGNALING_OFF] & HCI_SUPP_COMMANDS_SET_MWS_SIGNALING_MASK) + +#define HCI_SUPP_COMMANDS_SET_MWS_TRANS_LAYER_MASK 0x02 +#define HCI_SUPP_COMMANDS_SET_MWS_TRANS_LAYER_OFF 30 +#define HCI_SET_MWS_TRANSPORT_LAYER_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_SET_MWS_TRANS_LAYER_OFF] & HCI_SUPP_COMMANDS_SET_MWS_TRANS_LAYER_MASK) + +#define HCI_SUPP_COMMANDS_SET_MWS_SCAN_FREQ_TABLE_MASK 0x04 +#define HCI_SUPP_COMMANDS_SET_MWS_SCAN_FREQ_TABLE_OFF 30 +#define HCI_SET_MWS_SCAN_FREQUENCY_TABLE_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_SET_MWS_SCAN_FREQ_TABLE_OFF] & HCI_SUPP_COMMANDS_SET_MWS_SCAN_FREQ_TABLE_MASK) + +#define HCI_SUPP_COMMANDS_GET_TRANS_LAYER_CONF_MASK 0x08 +#define HCI_SUPP_COMMANDS_GET_TRANS_LAYER_CONF_OFF 30 +#define HCI_GET_MWS_TRANS_LAYER_CFG_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_GET_TRANS_LAYER_CONF_OFF] & HCI_SUPP_COMMANDS_GET_TRANS_LAYER_CONF_MASK) + +#define HCI_SUPP_COMMANDS_SET_MWS_PATTERN_CONF_MASK 0x10 +#define HCI_SUPP_COMMANDS_SET_MWS_PATTERN_CONF_OFF 30 +#define HCI_SET_MWS_PATTERN_CONFIGURATION_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_SET_MWS_PATTERN_CONF_OFF] & HCI_SUPP_COMMANDS_SET_MWS_PATTERN_CONF_MASK) + +/* Supported Commands (Byte 30 bit 5) */ +#define HCI_SUPP_COMMANDS_SET_TRIG_CLK_CAP_MASK 0x20 +#define HCI_SUPP_COMMANDS_SET_TRIG_CLK_CAP_OFF 30 +#define HCI_SET_TRIG_CLK_CAP_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_SET_TRIG_CLK_CAP_OFF] & HCI_SUPP_COMMANDS_SET_TRIG_CLK_CAP_MASK) + + +/* Supported Commands (Byte 30 bit 6-7) */ +#define HCI_SUPP_COMMANDS_TRUNCATED_PAGE 0x06 +#define HCI_SUPP_COMMANDS_TRUNCATED_PAGE_OFF 30 +#define HCI_TRUNCATED_PAGE_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_TRUNCATED_PAGE_OFF] & HCI_SUPP_COMMANDS_TRUNCATED_PAGE) + +#define HCI_SUPP_COMMANDS_TRUNCATED_PAGE_CANCEL 0x07 +#define HCI_SUPP_COMMANDS_TRUNCATED_PAGE_CANCEL_OFF 30 +#define HCI_TRUNCATED_PAGE_CANCEL_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_TRUNCATED_PAGE_CANCEL_OFF] & HCI_SUPP_COMMANDS_TRUNCATED_PAGE_CANCEL) + +/* Supported Commands (Byte 31 bit 6-7) */ +#define HCI_SUPP_COMMANDS_SET_CONLESS_SLAVE_BRCST 0x00 +#define HCI_SUPP_COMMANDS_SET_CONLESS_SLAVE_BRCST_OFF 31 +#define HCI_SET_CONLESS_SLAVE_BRCST_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_SET_CONLESS_SLAVE_BRCST_OFF] & HCI_SUPP_COMMANDS_SET_CONLESS_SLAVE_BRCST) + +#define HCI_SUPP_COMMANDS_SET_CONLESS_SLAVE_BRCST_RECEIVE 0x01 +#define HCI_SUPP_COMMANDS_SET_CONLESS_SLAVE_BRCST_RECEIVE_OFF 31 +#define HCI_SET_CONLESS_SLAVE_BRCST_RECEIVE_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_SET_CONLESS_SLAVE_BRCST_RECEIVE_OFF] & HCI_SUPP_COMMANDS_SET_CONLESS_SLAVE_BRCST_RECEIVE) + +#define HCI_SUPP_COMMANDS_START_SYNC_TRAIN 0x02 +#define HCI_SUPP_COMMANDS_START_SYNC_TRAIN_OFF 31 +#define HCI_START_SYNC_TRAIN_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_START_SYNC_TRAIN_OFF] & HCI_SUPP_COMMANDS_START_SYNC_TRAIN) + +#define HCI_SUPP_COMMANDS_RECEIVE_SYNC_TRAIN 0x03 +#define HCI_SUPP_COMMANDS_RECEIVE_SYNC_TRAIN_OFF 31 +#define HCI_RECEIVE_SYNC_TRAIN_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_RECEIVE_SYNC_TRAIN_OFF] & HCI_SUPP_COMMANDS_RECEIVE_SYNC_TRAIN) + +#define HCI_SUPP_COMMANDS_SET_RESERVED_LT_ADDR 0x04 +#define HCI_SUPP_COMMANDS_SET_RESERVED_LT_ADDR_OFF 31 +#define HCI_SET_RESERVED_LT_ADDR_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_SET_RESERVED_LT_ADDR_OFF] & HCI_SUPP_COMMANDS_SET_RESERVED_LT_ADDR) + +#define HCI_SUPP_COMMANDS_DELETE_RESERVED_LT_ADDR 0x05 +#define HCI_SUPP_COMMANDS_DELETE_RESERVED_LT_ADDR_OFF 31 +#define HCI_DELETE_RESERVED_LT_ADDR_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_DELETE_RESERVED_LT_ADDR_OFF] & HCI_SUPP_COMMANDS_DELETE_RESERVED_LT_ADDR) + +#define HCI_SUPP_COMMANDS_SET_CONLESS_SLAVE_BRCST_DATA 0x06 +#define HCI_SUPP_COMMANDS_SET_CONLESS_SLAVE_BRCST_DATA_OFF 31 +#define HCI_SET_CONLESS_SLAVE_BRCST_DATA_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_SET_CONLESS_SLAVE_BRCST_DATA_OFF] & HCI_SUPP_COMMANDS_SET_CONLESS_SLAVE_BRCST_DATA) + +#define HCI_SUPP_COMMANDS_READ_SYNC_TRAIN_PARAM 0x07 +#define HCI_SUPP_COMMANDS_READ_SYNC_TRAIN_PARAM_OFF 31 +#define HCI_READ_SYNC_TRAIN_PARAM_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_READ_SYNC_TRAIN_PARAM_OFF] & HCI_SUPP_COMMANDS_READ_SYNC_TRAIN_PARAM) + +/* Supported Commands (Byte 32 bit 0) */ +#define HCI_SUPP_COMMANDS_WRITE_SYNC_TRAIN_PARAM 0x00 +#define HCI_SUPP_COMMANDS_WRITE_SYNC_TRAIN_PARAM_OFF 32 +#define HCI_WRITE_SYNC_TRAIN_PARAM_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_WRITE_SYNC_TRAIN_PARAM_OFF] & HCI_SUPP_COMMANDS_WRITE_SYNC_TRAIN_PARAM) + +#define HCI_SUPP_COMMANDS_REMOTE_OOB_EXTENDED_DATA_REQUEST_REPLY_MASK 0x02 +#define HCI_SUPP_COMMANDS_REMOTE_OOB_EXTENDED_DATA_REQUEST_REPLY_OFF 32 +#define HCI_REMOTE_OOB_EXTENDED_DATA_REQUEST_REPLY_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_REMOTE_OOB_EXTENDED_DATA_REQUEST_REPLY_OFF] & HCI_SUPP_COMMANDS_REMOTE_OOB_EXTENDED_DATA_REQUEST_REPLY_MASK) + +#define HCI_SUPP_COMMANDS_READ_SECURE_CONNS_SUPPORT_MASK 0x04 +#define HCI_SUPP_COMMANDS_READ_SECURE_CONNS_SUPPORT_OFF 32 +#define HCI_READ_SECURE_CONNS_SUPPORT_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_READ_SECURE_CONNS_SUPPORT_OFF] & HCI_SUPP_COMMANDS_READ_SECURE_CONNS_SUPPORT_MASK) + +#define HCI_SUPP_COMMANDS_WRITE_SECURE_CONNS_SUPPORT_MASK 0x08 +#define HCI_SUPP_COMMANDS_WRITE_SECURE_CONNS_SUPPORT_OFF 32 +#define HCI_WRITE_SECURE_CONNS_SUPPORT_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_WRITE_SECURE_CONNS_SUPPORT_OFF] & HCI_SUPP_COMMANDS_WRITE_SECURE_CONNS_SUPPORT_MASK) + +#define HCI_SUPP_COMMANDS_READ_AUTHENT_PAYLOAD_TOUT_MASK 0x10 +#define HCI_SUPP_COMMANDS_READ_AUTHENT_PAYLOAD_TOUT_OFF 32 +#define HCI_READ_AUTHENT_PAYLOAD_TOUT_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_READ_AUTHENT_PAYLOAD_TOUT_OFF] & HCI_SUPP_COMMANDS_READ_AUTHENT_PAYLOAD_TOUT_MASK) + +#define HCI_SUPP_COMMANDS_WRITE_AUTHENT_PAYLOAD_TOUT_MASK 0x20 +#define HCI_SUPP_COMMANDS_WRITE_AUTHENT_PAYLOAD_TOUT_OFF 32 +#define HCI_WRITE_AUTHENT_PAYLOAD_TOUT_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_WRITE_AUTHENT_PAYLOAD_TOUT_OFF] & HCI_SUPP_COMMANDS_WRITE_AUTHENT_PAYLOAD_TOUT_MASK) + +#define HCI_SUPP_COMMANDS_READ_LOCAL_OOB_EXTENDED_DATA_MASK 0x40 +#define HCI_SUPP_COMMANDS_READ_LOCAL_OOB_EXTENDED_DATA_OFF 32 +#define HCI_READ_LOCAL_OOB_EXTENDED_DATA_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_READ_LOCAL_OOB_EXTENDED_DATA_OFF] & HCI_SUPP_COMMANDS_READ_LOCAL_OOB_EXTENDED_DATA_MASK) + +#define HCI_SUPP_COMMANDS_WRITE_SECURE_CONNECTIONS_TEST_MODE_MASK 0x80 +#define HCI_SUPP_COMMANDS_WRITE_SECURE_CONNECTIONS_TEST_MODE_OFF 32 +#define HCI_WRITE_SECURE_CONNECTIONS_TEST_MODE_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_WRITE_SECURE_CONNECTIONS_TEST_MODE_OFF] & HCI_SUPP_COMMANDS_WRITE_SECURE_CONNECTIONS_TEST_MODE_MASK) + +/* supported LE remote control connection parameter request reply */ +#define HCI_SUPP_COMMANDS_LE_RC_CONN_PARAM_UPD_RPY_MASK 0x10 +#define HCI_SUPP_COMMANDS_LE_RC_CONN_PARAM_UPD_RPY_OFF 33 +#define HCI_LE_RC_CONN_PARAM_UPD_RPY_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_LE_RC_CONN_PARAM_UPD_RPY_OFF] & HCI_SUPP_COMMANDS_LE_RC_CONN_PARAM_UPD_RPY_MASK) + +#define HCI_SUPP_COMMANDS_RLE_RC_CONN_PARAM_UPD_NEG_RPY_MASK 0x20 +#define HCI_SUPP_COMMANDS_LE_RC_CONN_PARAM_UPD_NEG_RPY_OFF 33 +#define HCI_LE_RC_CONN_PARAM_UPD_NEG_RPY_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_LE_RC_CONN_PARAM_UPD_NEG_RPY_OFF] & HCI_SUPP_COMMANDS_RLE_RC_CONN_PARAM_UPD_NEG_RPY_MASK) + +#endif + diff --git a/components/bt/bluedroid/stack/include/hcimsgs.h b/components/bt/bluedroid/stack/include/hcimsgs.h new file mode 100755 index 0000000000..dc440a20ce --- /dev/null +++ b/components/bt/bluedroid/stack/include/hcimsgs.h @@ -0,0 +1,811 @@ +/****************************************************************************** + * + * Copyright (C) 1999-2012 Broadcom Corporation + * + * 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. + * + ******************************************************************************/ + +#ifndef HCIMSGS_H +#define HCIMSGS_H + +#include "bt_target.h" +#include "hcidefs.h" +#include "bt_types.h" + +void bte_main_hci_send(BT_HDR *p_msg, UINT16 event); +void bte_main_lpm_allow_bt_device_sleep(void); + +/* Message by message.... */ + +BOOLEAN btsnd_hcic_inquiry(const LAP inq_lap, UINT8 duration, + UINT8 response_cnt); + +#define HCIC_PARAM_SIZE_INQUIRY 5 + + +#define HCIC_INQ_INQ_LAP_OFF 0 +#define HCIC_INQ_DUR_OFF 3 +#define HCIC_INQ_RSP_CNT_OFF 4 + /* Inquiry */ + + /* Inquiry Cancel */ +BOOLEAN btsnd_hcic_inq_cancel(void); + +#define HCIC_PARAM_SIZE_INQ_CANCEL 0 + + /* Periodic Inquiry Mode */ +BOOLEAN btsnd_hcic_per_inq_mode(UINT16 max_period, UINT16 min_period, + const LAP inq_lap, UINT8 duration, + UINT8 response_cnt); + +#define HCIC_PARAM_SIZE_PER_INQ_MODE 9 + +#define HCI_PER_INQ_MAX_INTRVL_OFF 0 +#define HCI_PER_INQ_MIN_INTRVL_OFF 2 +#define HCI_PER_INQ_INQ_LAP_OFF 4 +#define HCI_PER_INQ_DURATION_OFF 7 +#define HCI_PER_INQ_RSP_CNT_OFF 8 + /* Periodic Inquiry Mode */ + + /* Exit Periodic Inquiry Mode */ +BOOLEAN btsnd_hcic_exit_per_inq(void); + +#define HCIC_PARAM_SIZE_EXIT_PER_INQ 0 + /* Create Connection */ +BOOLEAN btsnd_hcic_create_conn(BD_ADDR dest, UINT16 packet_types, + UINT8 page_scan_rep_mode, + UINT8 page_scan_mode, + UINT16 clock_offset, + UINT8 allow_switch); + +#define HCIC_PARAM_SIZE_CREATE_CONN 13 + +#define HCIC_CR_CONN_BD_ADDR_OFF 0 +#define HCIC_CR_CONN_PKT_TYPES_OFF 6 +#define HCIC_CR_CONN_REP_MODE_OFF 8 +#define HCIC_CR_CONN_PAGE_SCAN_MODE_OFF 9 +#define HCIC_CR_CONN_CLK_OFF_OFF 10 +#define HCIC_CR_CONN_ALLOW_SWITCH_OFF 12 + /* Create Connection */ + + /* Disconnect */ +BOOLEAN btsnd_hcic_disconnect(UINT16 handle, UINT8 reason); + +#define HCIC_PARAM_SIZE_DISCONNECT 3 + +#define HCI_DISC_HANDLE_OFF 0 +#define HCI_DISC_REASON_OFF 2 + /* Disconnect */ + +#if BTM_SCO_INCLUDED == TRUE + /* Add SCO Connection */ +BOOLEAN btsnd_hcic_add_SCO_conn (UINT16 handle, UINT16 packet_types); +#endif /* BTM_SCO_INCLUDED */ + +#define HCIC_PARAM_SIZE_ADD_SCO_CONN 4 + +#define HCI_ADD_SCO_HANDLE_OFF 0 +#define HCI_ADD_SCO_PACKET_TYPES_OFF 2 + /* Add SCO Connection */ + + /* Create Connection Cancel */ +BOOLEAN btsnd_hcic_create_conn_cancel(BD_ADDR dest); + +#define HCIC_PARAM_SIZE_CREATE_CONN_CANCEL 6 + +#define HCIC_CR_CONN_CANCEL_BD_ADDR_OFF 0 + /* Create Connection Cancel */ + + /* Accept Connection Request */ +BOOLEAN btsnd_hcic_accept_conn (BD_ADDR bd_addr, UINT8 role); + +#define HCIC_PARAM_SIZE_ACCEPT_CONN 7 + +#define HCI_ACC_CONN_BD_ADDR_OFF 0 +#define HCI_ACC_CONN_ROLE_OFF 6 + /* Accept Connection Request */ + + /* Reject Connection Request */ +BOOLEAN btsnd_hcic_reject_conn (BD_ADDR bd_addr, UINT8 reason); + +#define HCIC_PARAM_SIZE_REJECT_CONN 7 + +#define HCI_REJ_CONN_BD_ADDR_OFF 0 +#define HCI_REJ_CONN_REASON_OFF 6 + /* Reject Connection Request */ + + /* Link Key Request Reply */ +BOOLEAN btsnd_hcic_link_key_req_reply (BD_ADDR bd_addr, + LINK_KEY link_key); + +#define HCIC_PARAM_SIZE_LINK_KEY_REQ_REPLY 22 + +#define HCI_LINK_KEY_REPLY_BD_ADDR_OFF 0 +#define HCI_LINK_KEY_REPLY_LINK_KEY_OFF 6 + /* Link Key Request Reply */ + + /* Link Key Request Neg Reply */ +BOOLEAN btsnd_hcic_link_key_neg_reply (BD_ADDR bd_addr); + +#define HCIC_PARAM_SIZE_LINK_KEY_NEG_REPLY 6 + +#define HCI_LINK_KEY_NEG_REP_BD_ADR_OFF 0 + /* Link Key Request Neg Reply */ + + /* PIN Code Request Reply */ +BOOLEAN btsnd_hcic_pin_code_req_reply (BD_ADDR bd_addr, + UINT8 pin_code_len, + PIN_CODE pin_code); + +#define HCIC_PARAM_SIZE_PIN_CODE_REQ_REPLY 23 + +#define HCI_PIN_CODE_REPLY_BD_ADDR_OFF 0 +#define HCI_PIN_CODE_REPLY_PIN_LEN_OFF 6 +#define HCI_PIN_CODE_REPLY_PIN_CODE_OFF 7 + /* PIN Code Request Reply */ + + /* Link Key Request Neg Reply */ +BOOLEAN btsnd_hcic_pin_code_neg_reply (BD_ADDR bd_addr); + +#define HCIC_PARAM_SIZE_PIN_CODE_NEG_REPLY 6 + +#define HCI_PIN_CODE_NEG_REP_BD_ADR_OFF 0 + /* Link Key Request Neg Reply */ + + /* Change Connection Type */ +BOOLEAN btsnd_hcic_change_conn_type (UINT16 handle, UINT16 packet_types); + +#define HCIC_PARAM_SIZE_CHANGE_CONN_TYPE 4 + +#define HCI_CHNG_PKT_TYPE_HANDLE_OFF 0 +#define HCI_CHNG_PKT_TYPE_PKT_TYPE_OFF 2 + /* Change Connection Type */ + +#define HCIC_PARAM_SIZE_CMD_HANDLE 2 + +#define HCI_CMD_HANDLE_HANDLE_OFF 0 + +BOOLEAN btsnd_hcic_auth_request (UINT16 handle); /* Authentication Request */ + + /* Set Connection Encryption */ +BOOLEAN btsnd_hcic_set_conn_encrypt (UINT16 handle, BOOLEAN enable); +#define HCIC_PARAM_SIZE_SET_CONN_ENCRYPT 3 + + +#define HCI_SET_ENCRYPT_HANDLE_OFF 0 +#define HCI_SET_ENCRYPT_ENABLE_OFF 2 + /* Set Connection Encryption */ + + /* Remote Name Request */ +BOOLEAN btsnd_hcic_rmt_name_req (BD_ADDR bd_addr, + UINT8 page_scan_rep_mode, + UINT8 page_scan_mode, + UINT16 clock_offset); + +#define HCIC_PARAM_SIZE_RMT_NAME_REQ 10 + +#define HCI_RMT_NAME_BD_ADDR_OFF 0 +#define HCI_RMT_NAME_REP_MODE_OFF 6 +#define HCI_RMT_NAME_PAGE_SCAN_MODE_OFF 7 +#define HCI_RMT_NAME_CLK_OFF_OFF 8 + /* Remote Name Request */ + + /* Remote Name Request Cancel */ +BOOLEAN btsnd_hcic_rmt_name_req_cancel(BD_ADDR bd_addr); + +#define HCIC_PARAM_SIZE_RMT_NAME_REQ_CANCEL 6 + +#define HCI_RMT_NAME_CANCEL_BD_ADDR_OFF 0 + /* Remote Name Request Cancel */ + +BOOLEAN btsnd_hcic_rmt_features_req(UINT16 handle); /* Remote Features Request */ + + /* Remote Extended Features */ +BOOLEAN btsnd_hcic_rmt_ext_features(UINT16 handle, UINT8 page_num); + +#define HCIC_PARAM_SIZE_RMT_EXT_FEATURES 3 + +#define HCI_RMT_EXT_FEATURES_HANDLE_OFF 0 +#define HCI_RMT_EXT_FEATURES_PAGE_NUM_OFF 2 + /* Remote Extended Features */ + + +BOOLEAN btsnd_hcic_rmt_ver_req(UINT16 handle); /* Remote Version Info Request */ +BOOLEAN btsnd_hcic_read_rmt_clk_offset(UINT16 handle); /* Remote Clock Offset */ +BOOLEAN btsnd_hcic_read_lmp_handle(UINT16 handle); /* Remote LMP Handle */ + +BOOLEAN btsnd_hcic_setup_esco_conn (UINT16 handle, + UINT32 tx_bw, UINT32 rx_bw, + UINT16 max_latency, UINT16 voice, + UINT8 retrans_effort, + UINT16 packet_types); +#define HCIC_PARAM_SIZE_SETUP_ESCO 17 + +#define HCI_SETUP_ESCO_HANDLE_OFF 0 +#define HCI_SETUP_ESCO_TX_BW_OFF 2 +#define HCI_SETUP_ESCO_RX_BW_OFF 6 +#define HCI_SETUP_ESCO_MAX_LAT_OFF 10 +#define HCI_SETUP_ESCO_VOICE_OFF 12 +#define HCI_SETUP_ESCO_RETRAN_EFF_OFF 14 +#define HCI_SETUP_ESCO_PKT_TYPES_OFF 15 + + +BOOLEAN btsnd_hcic_accept_esco_conn (BD_ADDR bd_addr, + UINT32 tx_bw, UINT32 rx_bw, + UINT16 max_latency, + UINT16 content_fmt, + UINT8 retrans_effort, + UINT16 packet_types); +#define HCIC_PARAM_SIZE_ACCEPT_ESCO 21 + +#define HCI_ACCEPT_ESCO_BDADDR_OFF 0 +#define HCI_ACCEPT_ESCO_TX_BW_OFF 6 +#define HCI_ACCEPT_ESCO_RX_BW_OFF 10 +#define HCI_ACCEPT_ESCO_MAX_LAT_OFF 14 +#define HCI_ACCEPT_ESCO_VOICE_OFF 16 +#define HCI_ACCEPT_ESCO_RETRAN_EFF_OFF 18 +#define HCI_ACCEPT_ESCO_PKT_TYPES_OFF 19 + + +BOOLEAN btsnd_hcic_reject_esco_conn (BD_ADDR bd_addr, UINT8 reason); +#define HCIC_PARAM_SIZE_REJECT_ESCO 7 + +#define HCI_REJECT_ESCO_BDADDR_OFF 0 +#define HCI_REJECT_ESCO_REASON_OFF 6 + +/* Hold Mode */ +BOOLEAN btsnd_hcic_hold_mode(UINT16 handle, UINT16 max_hold_period, + UINT16 min_hold_period); + +#define HCIC_PARAM_SIZE_HOLD_MODE 6 + +#define HCI_HOLD_MODE_HANDLE_OFF 0 +#define HCI_HOLD_MODE_MAX_PER_OFF 2 +#define HCI_HOLD_MODE_MIN_PER_OFF 4 + /* Hold Mode */ + + /* Sniff Mode */ +BOOLEAN btsnd_hcic_sniff_mode(UINT16 handle, + UINT16 max_sniff_period, + UINT16 min_sniff_period, + UINT16 sniff_attempt, + UINT16 sniff_timeout); + +#define HCIC_PARAM_SIZE_SNIFF_MODE 10 + + +#define HCI_SNIFF_MODE_HANDLE_OFF 0 +#define HCI_SNIFF_MODE_MAX_PER_OFF 2 +#define HCI_SNIFF_MODE_MIN_PER_OFF 4 +#define HCI_SNIFF_MODE_ATTEMPT_OFF 6 +#define HCI_SNIFF_MODE_TIMEOUT_OFF 8 + /* Sniff Mode */ + +BOOLEAN btsnd_hcic_exit_sniff_mode(UINT16 handle); /* Exit Sniff Mode */ + + /* Park Mode */ +BOOLEAN btsnd_hcic_park_mode (UINT16 handle, + UINT16 beacon_max_interval, + UINT16 beacon_min_interval); + +#define HCIC_PARAM_SIZE_PARK_MODE 6 + +#define HCI_PARK_MODE_HANDLE_OFF 0 +#define HCI_PARK_MODE_MAX_PER_OFF 2 +#define HCI_PARK_MODE_MIN_PER_OFF 4 + /* Park Mode */ + +BOOLEAN btsnd_hcic_exit_park_mode(UINT16 handle); /* Exit Park Mode */ + + /* QoS Setup */ +BOOLEAN btsnd_hcic_qos_setup (UINT16 handle, UINT8 flags, + UINT8 service_type, + UINT32 token_rate, UINT32 peak, + UINT32 latency, UINT32 delay_var); + +#define HCIC_PARAM_SIZE_QOS_SETUP 20 + +#define HCI_QOS_HANDLE_OFF 0 +#define HCI_QOS_FLAGS_OFF 2 +#define HCI_QOS_SERVICE_TYPE_OFF 3 +#define HCI_QOS_TOKEN_RATE_OFF 4 +#define HCI_QOS_PEAK_BANDWIDTH_OFF 8 +#define HCI_QOS_LATENCY_OFF 12 +#define HCI_QOS_DELAY_VAR_OFF 16 + /* QoS Setup */ + + /* Switch Role Request */ +BOOLEAN btsnd_hcic_switch_role (BD_ADDR bd_addr, UINT8 role); + +#define HCIC_PARAM_SIZE_SWITCH_ROLE 7 + +#define HCI_SWITCH_BD_ADDR_OFF 0 +#define HCI_SWITCH_ROLE_OFF 6 + /* Switch Role Request */ + + /* Write Policy Settings */ +BOOLEAN btsnd_hcic_write_policy_set(UINT16 handle, UINT16 settings); + +#define HCIC_PARAM_SIZE_WRITE_POLICY_SET 4 + +#define HCI_WRITE_POLICY_HANDLE_OFF 0 +#define HCI_WRITE_POLICY_SETTINGS_OFF 2 + /* Write Policy Settings */ + + /* Write Default Policy Settings */ +BOOLEAN btsnd_hcic_write_def_policy_set(UINT16 settings); + +#define HCIC_PARAM_SIZE_WRITE_DEF_POLICY_SET 2 + +#define HCI_WRITE_DEF_POLICY_SETTINGS_OFF 0 + /* Write Default Policy Settings */ + +/****************************************** +** Lisbon Features +*******************************************/ +#if BTM_SSR_INCLUDED == TRUE + /* Sniff Subrating */ +BOOLEAN btsnd_hcic_sniff_sub_rate(UINT16 handle, UINT16 max_lat, + UINT16 min_remote_lat, + UINT16 min_local_lat); + +#define HCIC_PARAM_SIZE_SNIFF_SUB_RATE 8 + +#define HCI_SNIFF_SUB_RATE_HANDLE_OFF 0 +#define HCI_SNIFF_SUB_RATE_MAX_LAT_OFF 2 +#define HCI_SNIFF_SUB_RATE_MIN_REM_LAT_OFF 4 +#define HCI_SNIFF_SUB_RATE_MIN_LOC_LAT_OFF 6 + /* Sniff Subrating */ + +#else /* BTM_SSR_INCLUDED == FALSE */ + +#define btsnd_hcic_sniff_sub_rate(handle, max_lat, min_remote_lat, min_local_lat) FALSE + +#endif /* BTM_SSR_INCLUDED */ + + /* Extended Inquiry Response */ +void btsnd_hcic_write_ext_inquiry_response(void *buffer, UINT8 fec_req); + +#define HCIC_PARAM_SIZE_EXT_INQ_RESP 241 + +#define HCIC_EXT_INQ_RESP_FEC_OFF 0 +#define HCIC_EXT_INQ_RESP_RESPONSE 1 + /* IO Capabilities Response */ +BOOLEAN btsnd_hcic_io_cap_req_reply (BD_ADDR bd_addr, UINT8 capability, + UINT8 oob_present, UINT8 auth_req); + +#define HCIC_PARAM_SIZE_IO_CAP_RESP 9 + +#define HCI_IO_CAP_BD_ADDR_OFF 0 +#define HCI_IO_CAPABILITY_OFF 6 +#define HCI_IO_CAP_OOB_DATA_OFF 7 +#define HCI_IO_CAP_AUTH_REQ_OFF 8 + + /* IO Capabilities Req Neg Reply */ +BOOLEAN btsnd_hcic_io_cap_req_neg_reply (BD_ADDR bd_addr, UINT8 err_code); + +#define HCIC_PARAM_SIZE_IO_CAP_NEG_REPLY 7 + +#define HCI_IO_CAP_NR_BD_ADDR_OFF 0 +#define HCI_IO_CAP_NR_ERR_CODE 6 + + /* Read Local OOB Data */ +BOOLEAN btsnd_hcic_read_local_oob_data (void); + +#define HCIC_PARAM_SIZE_R_LOCAL_OOB 0 + + +BOOLEAN btsnd_hcic_user_conf_reply (BD_ADDR bd_addr, BOOLEAN is_yes); + +#define HCIC_PARAM_SIZE_UCONF_REPLY 6 + +#define HCI_USER_CONF_BD_ADDR_OFF 0 + + +BOOLEAN btsnd_hcic_user_passkey_reply (BD_ADDR bd_addr, UINT32 value); + +#define HCIC_PARAM_SIZE_U_PKEY_REPLY 10 + +#define HCI_USER_PASSKEY_BD_ADDR_OFF 0 +#define HCI_USER_PASSKEY_VALUE_OFF 6 + + +BOOLEAN btsnd_hcic_user_passkey_neg_reply (BD_ADDR bd_addr); + +#define HCIC_PARAM_SIZE_U_PKEY_NEG_REPLY 6 + +#define HCI_USER_PASSKEY_NEG_BD_ADDR_OFF 0 + + /* Remote OOB Data Request Reply */ +BOOLEAN btsnd_hcic_rem_oob_reply (BD_ADDR bd_addr, UINT8 *p_c, + UINT8 *p_r); + +#define HCIC_PARAM_SIZE_REM_OOB_REPLY 38 + +#define HCI_REM_OOB_DATA_BD_ADDR_OFF 0 +#define HCI_REM_OOB_DATA_C_OFF 6 +#define HCI_REM_OOB_DATA_R_OFF 22 + + /* Remote OOB Data Request Negative Reply */ +BOOLEAN btsnd_hcic_rem_oob_neg_reply (BD_ADDR bd_addr); + +#define HCIC_PARAM_SIZE_REM_OOB_NEG_REPLY 6 + +#define HCI_REM_OOB_DATA_NEG_BD_ADDR_OFF 0 + + /* Read Tx Power Level */ +BOOLEAN btsnd_hcic_read_inq_tx_power (void); + +#define HCIC_PARAM_SIZE_R_TX_POWER 0 + + /* Read Default Erroneous Data Reporting */ +BOOLEAN btsnd_hcic_read_default_erroneous_data_rpt (void); + +#define HCIC_PARAM_SIZE_R_ERR_DATA_RPT 0 + +#if L2CAP_NON_FLUSHABLE_PB_INCLUDED == TRUE +BOOLEAN btsnd_hcic_enhanced_flush (UINT16 handle, UINT8 packet_type); + +#define HCIC_PARAM_SIZE_ENHANCED_FLUSH 3 +#endif + + +BOOLEAN btsnd_hcic_send_keypress_notif (BD_ADDR bd_addr, UINT8 notif); + +#define HCIC_PARAM_SIZE_SEND_KEYPRESS_NOTIF 7 + +#define HCI_SEND_KEYPRESS_NOTIF_BD_ADDR_OFF 0 +#define HCI_SEND_KEYPRESS_NOTIF_NOTIF_OFF 6 + +/**** end of Simple Pairing Commands ****/ + + /* Store Current Settings */ +#define MAX_FILT_COND (sizeof (BD_ADDR) + 1) + +BOOLEAN btsnd_hcic_set_event_filter(UINT8 filt_type, + UINT8 filt_cond_type, + UINT8 *filt_cond, + UINT8 filt_cond_len); + +#define HCIC_PARAM_SIZE_SET_EVT_FILTER 9 + +#define HCI_FILT_COND_FILT_TYPE_OFF 0 +#define HCI_FILT_COND_COND_TYPE_OFF 1 +#define HCI_FILT_COND_FILT_OFF 2 + /* Set Event Filter */ + + /* Delete Stored Key */ +BOOLEAN btsnd_hcic_delete_stored_key (BD_ADDR bd_addr, BOOLEAN delete_all_flag); + +#define HCIC_PARAM_SIZE_DELETE_STORED_KEY 7 + +#define HCI_DELETE_KEY_BD_ADDR_OFF 0 +#define HCI_DELETE_KEY_ALL_FLAG_OFF 6 + /* Delete Stored Key */ + + /* Change Local Name */ +BOOLEAN btsnd_hcic_change_name(BD_NAME name); + +#define HCIC_PARAM_SIZE_CHANGE_NAME BD_NAME_LEN + +#define HCI_CHANGE_NAME_NAME_OFF 0 + /* Change Local Name */ + + +#define HCIC_PARAM_SIZE_READ_CMD 0 + +#define HCIC_PARAM_SIZE_WRITE_PARAM1 1 + +#define HCIC_WRITE_PARAM1_PARAM_OFF 0 + +#define HCIC_PARAM_SIZE_WRITE_PARAM2 2 + +#define HCIC_WRITE_PARAM2_PARAM_OFF 0 + +#define HCIC_PARAM_SIZE_WRITE_PARAM3 3 + +#define HCIC_WRITE_PARAM3_PARAM_OFF 0 + +#define HCIC_PARAM_SIZE_SET_AFH_CHANNELS 10 + +BOOLEAN btsnd_hcic_write_pin_type(UINT8 type); /* Write PIN Type */ +BOOLEAN btsnd_hcic_write_auto_accept(UINT8 flag); /* Write Auto Accept */ +BOOLEAN btsnd_hcic_read_name (void); /* Read Local Name */ +BOOLEAN btsnd_hcic_write_page_tout(UINT16 timeout); /* Write Page Timout */ +BOOLEAN btsnd_hcic_write_scan_enable(UINT8 flag); /* Write Scan Enable */ +BOOLEAN btsnd_hcic_write_pagescan_cfg(UINT16 interval, + UINT16 window); /* Write Page Scan Activity */ + +#define HCIC_PARAM_SIZE_WRITE_PAGESCAN_CFG 4 + +#define HCI_SCAN_CFG_INTERVAL_OFF 0 +#define HCI_SCAN_CFG_WINDOW_OFF 2 + /* Write Page Scan Activity */ + + /* Write Inquiry Scan Activity */ +BOOLEAN btsnd_hcic_write_inqscan_cfg(UINT16 interval, UINT16 window); + +#define HCIC_PARAM_SIZE_WRITE_INQSCAN_CFG 4 + +#define HCI_SCAN_CFG_INTERVAL_OFF 0 +#define HCI_SCAN_CFG_WINDOW_OFF 2 + /* Write Inquiry Scan Activity */ + +BOOLEAN btsnd_hcic_write_auth_enable(UINT8 flag); /* Write Authentication Enable */ +BOOLEAN btsnd_hcic_write_dev_class(DEV_CLASS dev); /* Write Class of Device */ +BOOLEAN btsnd_hcic_write_voice_settings(UINT16 flags); /* Write Voice Settings */ + +/* Host Controller to Host flow control */ +#define HCI_HOST_FLOW_CTRL_OFF 0 +#define HCI_HOST_FLOW_CTRL_ACL_ON 1 +#define HCI_HOST_FLOW_CTRL_SCO_ON 2 +#define HCI_HOST_FLOW_CTRL_BOTH_ON 3 + +BOOLEAN btsnd_hcic_write_auto_flush_tout(UINT16 handle, + UINT16 timeout); /* Write Retransmit Timout */ + +#define HCIC_PARAM_SIZE_WRITE_AUTO_FLUSH_TOUT 4 + +#define HCI_FLUSH_TOUT_HANDLE_OFF 0 +#define HCI_FLUSH_TOUT_TOUT_OFF 2 + +BOOLEAN btsnd_hcic_read_tx_power(UINT16 handle, UINT8 type); /* Read Tx Power */ + +#define HCIC_PARAM_SIZE_READ_TX_POWER 3 + +#define HCI_READ_TX_POWER_HANDLE_OFF 0 +#define HCI_READ_TX_POWER_TYPE_OFF 2 + +/* Read transmit power level parameter */ +#define HCI_READ_CURRENT 0x00 +#define HCI_READ_MAXIMUM 0x01 + +BOOLEAN btsnd_hcic_host_num_xmitted_pkts (UINT8 num_handles, + UINT16 *handle, + UINT16 *num_pkts); /* Set Host Buffer Size */ + +#define HCIC_PARAM_SIZE_NUM_PKTS_DONE_SIZE sizeof(btmsg_hcic_num_pkts_done_t) + +#define MAX_DATA_HANDLES 10 + +#define HCI_PKTS_DONE_NUM_HANDLES_OFF 0 +#define HCI_PKTS_DONE_HANDLE_OFF 1 +#define HCI_PKTS_DONE_NUM_PKTS_OFF 3 + + /* Write Link Supervision Timeout */ +BOOLEAN btsnd_hcic_write_link_super_tout(UINT8 local_controller_id, UINT16 handle, UINT16 timeout); + +#define HCIC_PARAM_SIZE_WRITE_LINK_SUPER_TOUT 4 + +#define HCI_LINK_SUPER_TOUT_HANDLE_OFF 0 +#define HCI_LINK_SUPER_TOUT_TOUT_OFF 2 + /* Write Link Supervision Timeout */ + +BOOLEAN btsnd_hcic_write_cur_iac_lap (UINT8 num_cur_iac, + LAP * const iac_lap); /* Write Current IAC LAP */ + +#define MAX_IAC_LAPS 0x40 + +#define HCI_WRITE_IAC_LAP_NUM_OFF 0 +#define HCI_WRITE_IAC_LAP_LAP_OFF 1 + /* Write Current IAC LAP */ + +BOOLEAN btsnd_hcic_get_link_quality (UINT16 handle); /* Get Link Quality */ +BOOLEAN btsnd_hcic_read_rssi (UINT16 handle); /* Read RSSI */ +BOOLEAN btsnd_hcic_enable_test_mode (void); /* Enable Device Under Test Mode */ +BOOLEAN btsnd_hcic_write_pagescan_type(UINT8 type); /* Write Page Scan Type */ +BOOLEAN btsnd_hcic_write_inqscan_type(UINT8 type); /* Write Inquiry Scan Type */ +BOOLEAN btsnd_hcic_write_inquiry_mode(UINT8 type); /* Write Inquiry Mode */ + +#define HCI_DATA_HANDLE_MASK 0x0FFF + +#define HCID_GET_HANDLE_EVENT(p) (UINT16)((*((UINT8 *)((p) + 1) + p->offset) + \ + (*((UINT8 *)((p) + 1) + p->offset + 1) << 8))) + +#define HCID_GET_HANDLE(u16) (UINT16)((u16) & HCI_DATA_HANDLE_MASK) + +#define HCI_DATA_EVENT_MASK 3 +#define HCI_DATA_EVENT_OFFSET 12 +#define HCID_GET_EVENT(u16) (UINT8)(((u16) >> HCI_DATA_EVENT_OFFSET) & HCI_DATA_EVENT_MASK) + +#define HCI_DATA_BCAST_MASK 3 +#define HCI_DATA_BCAST_OFFSET 10 +#define HCID_GET_BCAST(u16) (UINT8)(((u16) >> HCI_DATA_BCAST_OFFSET) & HCI_DATA_BCAST_MASK) + +#define HCID_GET_ACL_LEN(p) (UINT16)((*((UINT8 *)((p) + 1) + p->offset + 2) + \ + (*((UINT8 *)((p) + 1) + p->offset + 3) << 8))) + +#define HCID_HEADER_SIZE 4 + +#define HCID_GET_SCO_LEN(p) (*((UINT8 *)((p) + 1) + p->offset + 2)) + +void btsnd_hcic_vendor_spec_cmd (void *buffer, UINT16 opcode, + UINT8 len, UINT8 *p_data, + void *p_cmd_cplt_cback); + +#if (BLE_INCLUDED == TRUE) +/******************************************************************************** +** BLE Commands +** Note: "local_controller_id" is for transport, not counted in HCI message size +*********************************************************************************/ +#define HCIC_BLE_RAND_DI_SIZE 8 +#define HCIC_BLE_ENCRYT_KEY_SIZE 16 +#define HCIC_BLE_IRK_SIZE 16 + +#define HCIC_PARAM_SIZE_SET_USED_FEAT_CMD 8 +#define HCIC_PARAM_SIZE_WRITE_RANDOM_ADDR_CMD 6 +#define HCIC_PARAM_SIZE_BLE_WRITE_ADV_PARAMS 15 +#define HCIC_PARAM_SIZE_BLE_WRITE_SCAN_RSP 31 +#define HCIC_PARAM_SIZE_WRITE_ADV_ENABLE 1 +#define HCIC_PARAM_SIZE_BLE_WRITE_SCAN_PARAM 7 +#define HCIC_PARAM_SIZE_BLE_WRITE_SCAN_ENABLE 2 +#define HCIC_PARAM_SIZE_BLE_CREATE_LL_CONN 25 +#define HCIC_PARAM_SIZE_BLE_CREATE_CONN_CANCEL 0 +#define HCIC_PARAM_SIZE_CLEAR_WHITE_LIST 0 +#define HCIC_PARAM_SIZE_ADD_WHITE_LIST 7 +#define HCIC_PARAM_SIZE_REMOVE_WHITE_LIST 7 +#define HCIC_PARAM_SIZE_BLE_UPD_LL_CONN_PARAMS 14 +#define HCIC_PARAM_SIZE_SET_HOST_CHNL_CLASS 5 +#define HCIC_PARAM_SIZE_READ_CHNL_MAP 2 +#define HCIC_PARAM_SIZE_BLE_READ_REMOTE_FEAT 2 +#define HCIC_PARAM_SIZE_BLE_ENCRYPT 32 +#define HCIC_PARAM_SIZE_BLE_RAND 0 +#define HCIC_PARAM_SIZE_WRITE_LE_HOST_SUPPORTED 2 + +#define HCIC_BLE_RAND_DI_SIZE 8 +#define HCIC_BLE_ENCRYT_KEY_SIZE 16 +#define HCIC_PARAM_SIZE_BLE_START_ENC (4 + HCIC_BLE_RAND_DI_SIZE + HCIC_BLE_ENCRYT_KEY_SIZE) +#define HCIC_PARAM_SIZE_LTK_REQ_REPLY (2 + HCIC_BLE_ENCRYT_KEY_SIZE) +#define HCIC_PARAM_SIZE_LTK_REQ_NEG_REPLY 2 +#define HCIC_BLE_CHNL_MAP_SIZE 5 +#define HCIC_PARAM_SIZE_BLE_WRITE_ADV_DATA 31 + +#define HCIC_PARAM_SIZE_BLE_ADD_DEV_RESOLVING_LIST (7 + HCIC_BLE_IRK_SIZE * 2) +#define HCIC_PARAM_SIZE_BLE_RM_DEV_RESOLVING_LIST 7 +#define HCIC_PARAM_SIZE_BLE_CLEAR_RESOLVING_LIST 0 +#define HCIC_PARAM_SIZE_BLE_READ_RESOLVING_LIST_SIZE 0 +#define HCIC_PARAM_SIZE_BLE_READ_RESOLVABLE_ADDR_PEER 7 +#define HCIC_PARAM_SIZE_BLE_READ_RESOLVABLE_ADDR_LOCAL 7 +#define HCIC_PARAM_SIZE_BLE_SET_ADDR_RESOLUTION_ENABLE 1 +#define HCIC_PARAM_SIZE_BLE_SET_RAND_PRIV_ADDR_TIMOUT 2 +#define HCIC_PARAM_SIZE_BLE_SET_DATA_LENGTH 6 +#define HCIC_PARAM_SIZE_BLE_WRITE_EXTENDED_SCAN_PARAM 11 + +/* ULP HCI command */ +BOOLEAN btsnd_hcic_ble_set_evt_mask (BT_EVENT_MASK event_mask); + +BOOLEAN btsnd_hcic_ble_read_buffer_size (void); + +BOOLEAN btsnd_hcic_ble_read_local_spt_feat (void); + +BOOLEAN btsnd_hcic_ble_set_local_used_feat (UINT8 feat_set[8]); + +BOOLEAN btsnd_hcic_ble_set_random_addr (BD_ADDR random_addr); + +BOOLEAN btsnd_hcic_ble_write_adv_params (UINT16 adv_int_min, UINT16 adv_int_max, + UINT8 adv_type, UINT8 addr_type_own, + UINT8 addr_type_dir, BD_ADDR direct_bda, + UINT8 channel_map, UINT8 adv_filter_policy); + +BOOLEAN btsnd_hcic_ble_read_adv_chnl_tx_power (void); + +BOOLEAN btsnd_hcic_ble_set_adv_data (UINT8 data_len, UINT8 *p_data); + +BOOLEAN btsnd_hcic_ble_set_scan_rsp_data (UINT8 data_len, UINT8 *p_scan_rsp); + +BOOLEAN btsnd_hcic_ble_set_adv_enable (UINT8 adv_enable); + +BOOLEAN btsnd_hcic_ble_set_scan_params (UINT8 scan_type, + UINT16 scan_int, UINT16 scan_win, + UINT8 addr_type, UINT8 scan_filter_policy); + +BOOLEAN btsnd_hcic_ble_set_scan_enable (UINT8 scan_enable, UINT8 duplicate); + +BOOLEAN btsnd_hcic_ble_create_ll_conn (UINT16 scan_int, UINT16 scan_win, + UINT8 init_filter_policy, UINT8 addr_type_peer, BD_ADDR bda_peer, UINT8 addr_type_own, + UINT16 conn_int_min, UINT16 conn_int_max, UINT16 conn_latency, UINT16 conn_timeout, + UINT16 min_ce_len, UINT16 max_ce_len); + +BOOLEAN btsnd_hcic_ble_create_conn_cancel (void); + +BOOLEAN btsnd_hcic_ble_read_white_list_size (void); + +BOOLEAN btsnd_hcic_ble_clear_white_list (void); + +BOOLEAN btsnd_hcic_ble_add_white_list (UINT8 addr_type, BD_ADDR bda); + +BOOLEAN btsnd_hcic_ble_remove_from_white_list (UINT8 addr_type, BD_ADDR bda); + +BOOLEAN btsnd_hcic_ble_upd_ll_conn_params (UINT16 handle, UINT16 conn_int_min, UINT16 conn_int_max, + UINT16 conn_latency, UINT16 conn_timeout, UINT16 min_len, UINT16 max_len); + +BOOLEAN btsnd_hcic_ble_set_host_chnl_class (UINT8 chnl_map[HCIC_BLE_CHNL_MAP_SIZE]); + +BOOLEAN btsnd_hcic_ble_read_chnl_map (UINT16 handle); + +BOOLEAN btsnd_hcic_ble_read_remote_feat ( UINT16 handle); + +BOOLEAN btsnd_hcic_ble_encrypt (UINT8* key, UINT8 key_len, UINT8* plain_text, UINT8 pt_len, void *p_cmd_cplt_cback); + +BOOLEAN btsnd_hcic_ble_rand (void *p_cmd_cplt_cback); + +BOOLEAN btsnd_hcic_ble_start_enc ( UINT16 handle, + UINT8 rand[HCIC_BLE_RAND_DI_SIZE], + UINT16 ediv, UINT8 ltk[HCIC_BLE_ENCRYT_KEY_SIZE]); + +BOOLEAN btsnd_hcic_ble_ltk_req_reply (UINT16 handle, UINT8 ltk[HCIC_BLE_ENCRYT_KEY_SIZE]); + +BOOLEAN btsnd_hcic_ble_ltk_req_neg_reply (UINT16 handle); + +BOOLEAN btsnd_hcic_ble_read_supported_states (void); + +BOOLEAN btsnd_hcic_ble_write_host_supported (UINT8 le_host_spt, UINT8 simul_le_host_spt); + +BOOLEAN btsnd_hcic_ble_read_host_supported (void); + +BOOLEAN btsnd_hcic_ble_receiver_test(UINT8 rx_freq); + +BOOLEAN btsnd_hcic_ble_transmitter_test(UINT8 tx_freq, UINT8 test_data_len, + UINT8 payload); +BOOLEAN btsnd_hcic_ble_test_end(void); + +#if (defined BLE_LLT_INCLUDED) && (BLE_LLT_INCLUDED == TRUE) + +#define HCIC_PARAM_SIZE_BLE_RC_PARAM_REQ_REPLY 14 +BOOLEAN btsnd_hcic_ble_rc_param_req_reply(UINT16 handle, + UINT16 conn_int_min, UINT16 conn_int_max, + UINT16 conn_latency, UINT16 conn_timeout, + UINT16 min_ce_len, UINT16 max_ce_len); + +#define HCIC_PARAM_SIZE_BLE_RC_PARAM_REQ_NEG_REPLY 3 +BOOLEAN btsnd_hcic_ble_rc_param_req_neg_reply(UINT16 handle, UINT8 reason); + +#endif /* BLE_LLT_INCLUDED */ + +BOOLEAN btsnd_hcic_ble_set_data_length(UINT16 conn_handle, UINT16 tx_octets, + UINT16 tx_time); + +BOOLEAN btsnd_hcic_ble_add_device_resolving_list (UINT8 addr_type_peer, + BD_ADDR bda_peer, + UINT8 irk_peer[HCIC_BLE_IRK_SIZE], + UINT8 irk_local[HCIC_BLE_IRK_SIZE]); + +BOOLEAN btsnd_hcic_ble_rm_device_resolving_list (UINT8 addr_type_peer, + BD_ADDR bda_peer); + +BOOLEAN btsnd_hcic_ble_clear_resolving_list (void); + +BOOLEAN btsnd_hcic_ble_read_resolvable_addr_peer (UINT8 addr_type_peer, + BD_ADDR bda_peer); + +BOOLEAN btsnd_hcic_ble_read_resolvable_addr_local (UINT8 addr_type_peer, + BD_ADDR bda_peer); + +BOOLEAN btsnd_hcic_ble_set_addr_resolution_enable (UINT8 addr_resolution_enable); + +BOOLEAN btsnd_hcic_ble_set_rand_priv_addr_timeout (UINT16 rpa_timout); + +#endif /* BLE_INCLUDED */ + +BOOLEAN btsnd_hcic_read_authenticated_payload_tout(UINT16 handle); + +BOOLEAN btsnd_hcic_write_authenticated_payload_tout(UINT16 handle, + UINT16 timeout); + +#define HCIC_PARAM_SIZE_WRITE_AUTHENT_PAYLOAD_TOUT 4 + +#define HCI__WRITE_AUTHENT_PAYLOAD_TOUT_HANDLE_OFF 0 +#define HCI__WRITE_AUTHENT_PAYLOAD_TOUT_TOUT_OFF 2 + +#endif diff --git a/components/bt/bluedroid/stack/include/hid_conn.h b/components/bt/bluedroid/stack/include/hid_conn.h new file mode 100755 index 0000000000..79bb496b45 --- /dev/null +++ b/components/bt/bluedroid/stack/include/hid_conn.h @@ -0,0 +1,69 @@ +/****************************************************************************** + * + * Copyright (C) 2002-2012 Broadcom Corporation + * + * 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 HID connection internal definitions + * + ******************************************************************************/ + +#ifndef HID_CONN_H +#define HID_CONN_H + + +/* Define the HID Connection Block +*/ +typedef struct hid_conn +{ +#define HID_CONN_STATE_UNUSED (0) +#define HID_CONN_STATE_CONNECTING_CTRL (1) +#define HID_CONN_STATE_CONNECTING_INTR (2) +#define HID_CONN_STATE_CONFIG (3) +#define HID_CONN_STATE_CONNECTED (4) +#define HID_CONN_STATE_DISCONNECTING (5) +#define HID_CONN_STATE_SECURITY (6) + + UINT8 conn_state; + +#define HID_CONN_FLAGS_IS_ORIG (0x01) +#define HID_CONN_FLAGS_HIS_CTRL_CFG_DONE (0x02) +#define HID_CONN_FLAGS_MY_CTRL_CFG_DONE (0x04) +#define HID_CONN_FLAGS_HIS_INTR_CFG_DONE (0x08) +#define HID_CONN_FLAGS_MY_INTR_CFG_DONE (0x10) +#define HID_CONN_FLAGS_ALL_CONFIGURED (0x1E) /* All the config done */ +#define HID_CONN_FLAGS_CONGESTED (0x20) +#define HID_CONN_FLAGS_INACTIVE (0x40) + + UINT8 conn_flags; + + UINT8 ctrl_id; + UINT16 ctrl_cid; + UINT16 intr_cid; + UINT16 rem_mtu_size; + UINT16 disc_reason; /* Reason for disconnecting (for HID_HDEV_EVT_CLOSE) */ + TIMER_LIST_ENT timer_entry; + +} tHID_CONN; + +#define HID_SEC_CHN 1 +#define HID_NOSEC_CHN 2 + +#define HIDD_SEC_CHN 3 +#define HIDD_NOSEC_CHN 4 + +#endif diff --git a/components/bt/bluedroid/stack/include/hiddefs.h b/components/bt/bluedroid/stack/include/hiddefs.h new file mode 100755 index 0000000000..bf5d0212e0 --- /dev/null +++ b/components/bt/bluedroid/stack/include/hiddefs.h @@ -0,0 +1,159 @@ +/****************************************************************************** + * + * Copyright (C) 2002-2012 Broadcom Corporation + * + * 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 HID protocol definitions + * + ******************************************************************************/ + +#ifndef HIDDEFS_H +#define HIDDEFS_H + +#include "sdp_api.h" +/* +** tHID_STATUS: HID result codes, returned by HID and device and host functions. +*/ +enum +{ + HID_SUCCESS, + HID_ERR_NOT_REGISTERED, + HID_ERR_ALREADY_REGISTERED, + HID_ERR_NO_RESOURCES, + HID_ERR_NO_CONNECTION, + HID_ERR_INVALID_PARAM, + HID_ERR_UNSUPPORTED, + HID_ERR_UNKNOWN_COMMAND, + HID_ERR_CONGESTED, + HID_ERR_CONN_IN_PROCESS, + HID_ERR_ALREADY_CONN, + HID_ERR_DISCONNECTING, + HID_ERR_SET_CONNABLE_FAIL, + /* Device specific error codes */ + HID_ERR_HOST_UNKNOWN, + HID_ERR_L2CAP_FAILED, + HID_ERR_AUTH_FAILED, + HID_ERR_SDP_BUSY, + HID_ERR_GATT, + + HID_ERR_INVALID = 0xFF +}; + +typedef UINT8 tHID_STATUS; + +#define HID_L2CAP_CONN_FAIL (0x0100) /* Connection Attempt was made but failed */ +#define HID_L2CAP_REQ_FAIL (0x0200) /* L2CAP_ConnectReq API failed */ +#define HID_L2CAP_CFG_FAIL (0x0400) /* L2CAP Configuration was rejected by peer */ + + + +/* Define the HID transaction types +*/ +#define HID_TRANS_HANDSHAKE (0) +#define HID_TRANS_CONTROL (1) +#define HID_TRANS_GET_REPORT (4) +#define HID_TRANS_SET_REPORT (5) +#define HID_TRANS_GET_PROTOCOL (6) +#define HID_TRANS_SET_PROTOCOL (7) +#define HID_TRANS_GET_IDLE (8) +#define HID_TRANS_SET_IDLE (9) +#define HID_TRANS_DATA (10) +#define HID_TRANS_DATAC (11) + +#define HID_GET_TRANS_FROM_HDR(x) ((x >> 4) & 0x0f) +#define HID_GET_PARAM_FROM_HDR(x) (x & 0x0f) +#define HID_BUILD_HDR(t,p) (UINT8)((t << 4) | (p & 0x0f)) + + +/* Parameters for Handshake +*/ +#define HID_PAR_HANDSHAKE_RSP_SUCCESS (0) +#define HID_PAR_HANDSHAKE_RSP_NOT_READY (1) +#define HID_PAR_HANDSHAKE_RSP_ERR_INVALID_REP_ID (2) +#define HID_PAR_HANDSHAKE_RSP_ERR_UNSUPPORTED_REQ (3) +#define HID_PAR_HANDSHAKE_RSP_ERR_INVALID_PARAM (4) +#define HID_PAR_HANDSHAKE_RSP_ERR_UNKNOWN (14) +#define HID_PAR_HANDSHAKE_RSP_ERR_FATAL (15) + + +/* Parameters for Control +*/ +#define HID_PAR_CONTROL_NOP (0) +#define HID_PAR_CONTROL_HARD_RESET (1) +#define HID_PAR_CONTROL_SOFT_RESET (2) +#define HID_PAR_CONTROL_SUSPEND (3) +#define HID_PAR_CONTROL_EXIT_SUSPEND (4) +#define HID_PAR_CONTROL_VIRTUAL_CABLE_UNPLUG (5) + + +/* Different report types in get, set, data +*/ +#define HID_PAR_REP_TYPE_MASK (0x03) +#define HID_PAR_REP_TYPE_OTHER (0x00) +#define HID_PAR_REP_TYPE_INPUT (0x01) +#define HID_PAR_REP_TYPE_OUTPUT (0x02) +#define HID_PAR_REP_TYPE_FEATURE (0x03) + +/* Parameters for Get Report +*/ + +/* Buffer size in two bytes after Report ID */ +#define HID_PAR_GET_REP_BUFSIZE_FOLLOWS (0x08) + + +/* Parameters for Protocol Type +*/ +#define HID_PAR_PROTOCOL_MASK (0x01) +#define HID_PAR_PROTOCOL_REPORT (0x01) +#define HID_PAR_PROTOCOL_BOOT_MODE (0x00) + +#define HID_PAR_REP_TYPE_MASK (0x03) + +/* Descriptor types in the SDP record +*/ +#define HID_SDP_DESCRIPTOR_REPORT (0x22) +#define HID_SDP_DESCRIPTOR_PHYSICAL (0x23) + +typedef struct desc_info +{ + UINT16 dl_len; + UINT8 *dsc_list; +} tHID_DEV_DSCP_INFO; + +#define HID_SSR_PARAM_INVALID 0xffff + +typedef struct sdp_info +{ + char svc_name[HID_MAX_SVC_NAME_LEN]; /*Service Name */ + char svc_descr[HID_MAX_SVC_DESCR_LEN]; /*Service Description*/ + char prov_name[HID_MAX_PROV_NAME_LEN]; /*Provider Name.*/ + UINT16 rel_num; /*Release Number */ + UINT16 hpars_ver; /*HID Parser Version.*/ + UINT16 ssr_max_latency; /* HIDSSRHostMaxLatency value, if HID_SSR_PARAM_INVALID not used*/ + UINT16 ssr_min_tout; /* HIDSSRHostMinTimeout value, if HID_SSR_PARAM_INVALID not used* */ + UINT8 sub_class; /*Device Subclass.*/ + UINT8 ctry_code; /*Country Code.*/ + UINT16 sup_timeout;/* Supervisory Timeout */ + + tHID_DEV_DSCP_INFO dscp_info; /* Descriptor list and Report list to be set in the SDP record. + This parameter is used if HID_DEV_USE_GLB_SDP_REC is set to FALSE.*/ + tSDP_DISC_REC *p_sdp_layer_rec; +} tHID_DEV_SDP_INFO; + +#endif + diff --git a/components/bt/bluedroid/stack/include/hidh_api.h b/components/bt/bluedroid/stack/include/hidh_api.h new file mode 100755 index 0000000000..00b8fde6f5 --- /dev/null +++ b/components/bt/bluedroid/stack/include/hidh_api.h @@ -0,0 +1,236 @@ +/****************************************************************************** + * + * Copyright (C) 2002-2012 Broadcom Corporation + * + * 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. + * + ******************************************************************************/ +#ifndef HIDH_API_H +#define HIDH_API_H + +#include "hiddefs.h" +#include "sdp_api.h" + +/***************************************************************************** +** Constants +*****************************************************************************/ + +enum { + HID_SDP_NO_SERV_UUID = (SDP_ILLEGAL_PARAMETER+1), + HID_SDP_MANDATORY_MISSING +}; + +/* Attributes mask values to be used in HID_HostAddDev API */ +#define HID_VIRTUAL_CABLE 0x0001 +#define HID_NORMALLY_CONNECTABLE 0x0002 +#define HID_RECONN_INIT 0x0004 +#define HID_SDP_DISABLE 0x0008 +#define HID_BATTERY_POWER 0x0010 +#define HID_REMOTE_WAKE 0x0020 +#define HID_SUP_TOUT_AVLBL 0x0040 +#define HID_SSR_MAX_LATENCY 0x0080 +#define HID_SSR_MIN_TOUT 0x0100 + +#define HID_SEC_REQUIRED 0x8000 +#define HID_ATTR_MASK_IGNORE 0 + + +/***************************************************************************** +** Type Definitions +*****************************************************************************/ + +typedef void (tHID_HOST_SDP_CALLBACK) (UINT16 result, UINT16 attr_mask, + tHID_DEV_SDP_INFO *sdp_rec ); + +/* HID-HOST returns the events in the following table to the application via tHID_HOST_DEV_CALLBACK +HID_HDEV_EVT_OPEN Connected to device with Interrupt and Control Channels in OPEN state. + Data = NA +HID_HDEV_EVT_CLOSE Connection with device is closed. Data=reason code. +HID_HDEV_EVT_RETRYING Lost connection is being re-connected. + Data=Retrial number +HID_HDEV_EVT_IN_REPORT Device sent an input report Data=Report Type pdata= pointer to BT_HDR + (GKI buffer having report data.) +HID_HDEV_EVT_HANDSHAKE Device sent SET_REPORT Data=Result-code pdata=NA. +HID_HDEV_EVT_VC_UNPLUG Device sent Virtual Unplug Data=NA. pdata=NA. +*/ + +enum +{ + HID_HDEV_EVT_OPEN, + HID_HDEV_EVT_CLOSE, + HID_HDEV_EVT_RETRYING, + HID_HDEV_EVT_INTR_DATA, + HID_HDEV_EVT_INTR_DATC, + HID_HDEV_EVT_CTRL_DATA, + HID_HDEV_EVT_CTRL_DATC, + HID_HDEV_EVT_HANDSHAKE, + HID_HDEV_EVT_VC_UNPLUG +}; +typedef void (tHID_HOST_DEV_CALLBACK) (UINT8 dev_handle, + BD_ADDR addr, + UINT8 event, /* Event from HID-DEVICE. */ + UINT32 data, /* Integer data corresponding to the event.*/ + BT_HDR *p_buf ); /* Pointer data corresponding to the event. */ + + +/***************************************************************************** +** External Function Declarations +*****************************************************************************/ +#ifdef __cplusplus +extern "C" +{ +#endif + +/******************************************************************************* +** +** Function HID_HostGetSDPRecord +** +** Description This function reads the device SDP record. +** +** Returns tHID_STATUS +** +*******************************************************************************/ +extern tHID_STATUS HID_HostGetSDPRecord (BD_ADDR addr, + tSDP_DISCOVERY_DB *p_db, + UINT32 db_len, + tHID_HOST_SDP_CALLBACK *sdp_cback ); + +/******************************************************************************* +** +** Function HID_HostRegister +** +** Description This function registers HID-Host with lower layers. +** +** Returns tHID_STATUS +** +*******************************************************************************/ +extern tHID_STATUS HID_HostRegister (tHID_HOST_DEV_CALLBACK *dev_cback); + +/******************************************************************************* +** +** Function HID_HostDeregister +** +** Description This function is called when the host is about power down. +** +** Returns tHID_STATUS +** +*******************************************************************************/ +extern tHID_STATUS HID_HostDeregister(void); + +/******************************************************************************* +** +** Function HID_HostAddDev +** +** Description This is called so HID-host may manage this device. +** +** Returns tHID_STATUS +** +*******************************************************************************/ +extern tHID_STATUS HID_HostAddDev (BD_ADDR addr, UINT16 attr_mask, + UINT8 *handle ); + +/******************************************************************************* +** +** Function HID_HostRemoveDev +** +** Description This removes the device from list devices that host has to manage. +** +** Returns tHID_STATUS +** +*******************************************************************************/ +extern tHID_STATUS HID_HostRemoveDev (UINT8 dev_handle ); + +/******************************************************************************* +** +** Function HID_HostOpenDev +** +** Description This function is called when the user wants to initiate a +** connection attempt to a device. +** +** Returns void +** +*******************************************************************************/ +extern tHID_STATUS HID_HostOpenDev (UINT8 dev_handle ); + +/******************************************************************************* +** +** Function HID_HostWriteDev +** +** Description This function is called when the host has a report to send. +** +** Returns void +** +*******************************************************************************/ +extern tHID_STATUS HID_HostWriteDev(UINT8 dev_handle, UINT8 t_type, + UINT8 param, UINT16 data, + UINT8 report_id, BT_HDR *pbuf); + +/******************************************************************************* +** +** Function HID_HostCloseDev +** +** Description This function disconnects the device. +** +** Returns void +** +*******************************************************************************/ +extern tHID_STATUS HID_HostCloseDev(UINT8 dev_handle ); + +/******************************************************************************* +** Function HID_HostInit +** +** Description This function initializes the control block and trace variable +** +** Returns void +*******************************************************************************/ +extern void HID_HostInit(void); + +/******************************************************************************* +** Function HID_HostSetSecurityLevel +** +** Description This function sets the security level for the devices which +** are marked by application as requiring security +** +** Returns tHID_STATUS +*******************************************************************************/ +extern tHID_STATUS HID_HostSetSecurityLevel( char serv_name[], UINT8 sec_lvl ); + +/******************************************************************************* +** +** Function hid_known_hid_device +** +** Description This function checks if this device is of type HID Device +** +** Returns TRUE if device exists else FALSE +** +*******************************************************************************/ +BOOLEAN hid_known_hid_device (BD_ADDR bd_addr); + + +/******************************************************************************* +** +** Function HID_HostSetTraceLevel +** +** Description This function sets the trace level for HID Host. If called with +** a value of 0xFF, it simply reads the current trace level. +** +** Returns the new (current) trace level +** +*******************************************************************************/ +extern UINT8 HID_HostSetTraceLevel (UINT8 new_level); + +#ifdef __cplusplus +} +#endif + +#endif /* HIDH_API_H */ diff --git a/components/bt/bluedroid/stack/include/hidh_int.h b/components/bt/bluedroid/stack/include/hidh_int.h new file mode 100755 index 0000000000..3fedea2b12 --- /dev/null +++ b/components/bt/bluedroid/stack/include/hidh_int.h @@ -0,0 +1,93 @@ +/****************************************************************************** + * + * Copyright (C) 2002-2012 Broadcom Corporation + * + * 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 HID HOST internal definitions + * + ******************************************************************************/ + +#ifndef HIDH_INT_H +#define HIDH_INT_H + +#include "hidh_api.h" +#include "hid_conn.h" +#include "l2c_api.h" + +enum { + HID_DEV_NO_CONN, + HID_DEV_CONNECTED +}; + +typedef struct per_device_ctb +{ + BOOLEAN in_use; + BD_ADDR addr; /* BD-Addr of the host device */ + UINT16 attr_mask; /* 0x01- virtual_cable; 0x02- normally_connectable; 0x03- reconn_initiate; + 0x04- sdp_disable; */ + UINT8 state; /* Device state if in HOST-KNOWN mode */ + UINT8 conn_substate; + UINT8 conn_tries; /* Remembers to the number of connection attempts while CONNECTING */ + + tHID_CONN conn; /* L2CAP channel info */ +} tHID_HOST_DEV_CTB; + +typedef struct host_ctb +{ + tHID_HOST_DEV_CTB devices[HID_HOST_MAX_DEVICES]; + tHID_HOST_DEV_CALLBACK *callback; /* Application callbacks */ + tL2CAP_CFG_INFO l2cap_cfg; + +#define MAX_SERVICE_DB_SIZE 4000 + + BOOLEAN sdp_busy; + tHID_HOST_SDP_CALLBACK *sdp_cback; + tSDP_DISCOVERY_DB *p_sdp_db; + tHID_DEV_SDP_INFO sdp_rec; + BOOLEAN reg_flag; + UINT8 trace_level; +} tHID_HOST_CTB; + +extern tHID_STATUS hidh_conn_snd_data(UINT8 dhandle, UINT8 trans_type, UINT8 param, \ + UINT16 data,UINT8 rpt_id, BT_HDR *buf); +extern tHID_STATUS hidh_conn_reg (void); +extern void hidh_conn_dereg( void ); +extern tHID_STATUS hidh_conn_disconnect (UINT8 dhandle); +extern tHID_STATUS hidh_conn_initiate (UINT8 dhandle); +extern void hidh_proc_repage_timeout (TIMER_LIST_ENT *p_tle); + +#ifdef __cplusplus +extern "C" +{ +#endif + +/****************************************************************************** +** Main Control Block +*******************************************************************************/ +#if HID_DYNAMIC_MEMORY == FALSE +extern tHID_HOST_CTB hh_cb; +#else +extern tHID_HOST_CTB *hidh_cb_ptr; +#define hh_cb (*hidh_cb_ptr) +#endif + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/components/bt/bluedroid/stack/include/l2c_api.h b/components/bt/bluedroid/stack/include/l2c_api.h new file mode 100755 index 0000000000..837dbc8528 --- /dev/null +++ b/components/bt/bluedroid/stack/include/l2c_api.h @@ -0,0 +1,1143 @@ +/****************************************************************************** + * + * Copyright (C) 1999-2012 Broadcom Corporation + * + * 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 L2CAP API definitions + * + ******************************************************************************/ +#ifndef L2C_API_H +#define L2C_API_H + +#include + +#include "bt_target.h" +#include "l2cdefs.h" +#include "hcidefs.h" + +/***************************************************************************** +** Constants +*****************************************************************************/ + +/* Define the minimum offset that L2CAP needs in a buffer. This is made up of +** HCI type(1), len(2), handle(2), L2CAP len(2) and CID(2) => 9 +*/ +#define L2CAP_MIN_OFFSET 13 /* plus control(2), SDU length(2) */ + +/* Minimum offset for broadcast needs another two bytes for the PSM */ +#define L2CAP_BCST_MIN_OFFSET 11 + +/* ping result codes */ +#define L2CAP_PING_RESULT_OK 0 /* Ping reply received OK */ +#define L2CAP_PING_RESULT_NO_LINK 1 /* Link could not be setup */ +#define L2CAP_PING_RESULT_NO_RESP 2 /* Remote L2CAP did not reply */ + +/* result code for L2CA_DataWrite() */ +#define L2CAP_DW_FAILED FALSE +#define L2CAP_DW_SUCCESS TRUE +#define L2CAP_DW_CONGESTED 2 + +/* Values for priority parameter to L2CA_SetAclPriority */ +#define L2CAP_PRIORITY_NORMAL 0 +#define L2CAP_PRIORITY_HIGH 1 + +/* Values for priority parameter to L2CA_SetTxPriority */ +#define L2CAP_CHNL_PRIORITY_HIGH 0 +#define L2CAP_CHNL_PRIORITY_MEDIUM 1 +#define L2CAP_CHNL_PRIORITY_LOW 2 + +typedef UINT8 tL2CAP_CHNL_PRIORITY; + +/* Values for Tx/Rx data rate parameter to L2CA_SetChnlDataRate */ +#define L2CAP_CHNL_DATA_RATE_HIGH 3 +#define L2CAP_CHNL_DATA_RATE_MEDIUM 2 +#define L2CAP_CHNL_DATA_RATE_LOW 1 +#define L2CAP_CHNL_DATA_RATE_NO_TRAFFIC 0 + +typedef UINT8 tL2CAP_CHNL_DATA_RATE; + +/* Data Packet Flags (bits 2-15 are reserved) */ +/* layer specific 14-15 bits are used for FCR SAR */ +#define L2CAP_FLUSHABLE_MASK 0x0003 +#define L2CAP_FLUSHABLE_CH_BASED 0x0000 +#define L2CAP_FLUSHABLE_PKT 0x0001 +#define L2CAP_NON_FLUSHABLE_PKT 0x0002 + + +/* L2CA_FlushChannel num_to_flush definitions */ +#define L2CAP_FLUSH_CHANS_ALL 0xffff +#define L2CAP_FLUSH_CHANS_GET 0x0000 + + +/* special CID for Multi-AV for reporting congestion */ +#define L2CAP_MULTI_AV_CID 0 + +/* length of the HCI header block */ +/* HCI header(4) + SNK count(1) + FCR bits(1) + AV data length(2) */ +#define L2CAP_MULTI_AV_HCI_HDR_LEN 8 + +/* length of padding for 4 bytes align */ +#define L2CAP_MULTI_AV_PADDING_LEN 2 + +/* length of the HCI header block with padding for FCR */ +/* HCI header(4) + SNK count(1) + FCR bits(1) + AV data length(2) + padding(2) */ +#define L2CAP_MULTI_AV_HCI_HDR_LEN_WITH_PADDING 10 + +/* length of the L2CAP header block */ +/* HCI header(4) + L2CAP header(4) + padding(4) or control word(2) + FCS(2) */ +#define L2CAP_MULTI_AV_L2C_HDR_LEN 12 + +/* definition used for L2CA_SetDesireRole */ +#define L2CAP_ROLE_SLAVE HCI_ROLE_SLAVE +#define L2CAP_ROLE_MASTER HCI_ROLE_MASTER +#define L2CAP_ROLE_ALLOW_SWITCH 0x80 /* set this bit to allow switch at create conn */ +#define L2CAP_ROLE_DISALLOW_SWITCH 0x40 /* set this bit to disallow switch at create conn */ +#define L2CAP_ROLE_CHECK_SWITCH 0xC0 + + +/* Values for 'allowed_modes' field passed in structure tL2CAP_ERTM_INFO +*/ +#define L2CAP_FCR_CHAN_OPT_BASIC (1 << L2CAP_FCR_BASIC_MODE) +#define L2CAP_FCR_CHAN_OPT_ERTM (1 << L2CAP_FCR_ERTM_MODE) +#define L2CAP_FCR_CHAN_OPT_STREAM (1 << L2CAP_FCR_STREAM_MODE) + +#define L2CAP_FCR_CHAN_OPT_ALL_MASK (L2CAP_FCR_CHAN_OPT_BASIC | L2CAP_FCR_CHAN_OPT_ERTM | L2CAP_FCR_CHAN_OPT_STREAM) + +/* Validity check for PSM. PSM values must be odd. Also, all PSM values must +** be assigned such that the least significant bit of the most sigificant +** octet equals zero. +*/ +#define L2C_INVALID_PSM(psm) (((psm) & 0x0101) != 0x0001) +#define L2C_IS_VALID_PSM(psm) (((psm) & 0x0101) == 0x0001) + +/***************************************************************************** +** Type Definitions +*****************************************************************************/ + +typedef struct +{ +#define L2CAP_FCR_BASIC_MODE 0x00 +#define L2CAP_FCR_ERTM_MODE 0x03 +#define L2CAP_FCR_STREAM_MODE 0x04 + + UINT8 mode; + + UINT8 tx_win_sz; + UINT8 max_transmit; + UINT16 rtrans_tout; + UINT16 mon_tout; + UINT16 mps; +} tL2CAP_FCR_OPTS; + +/* Define a structure to hold the configuration parameters. Since the +** parameters are optional, for each parameter there is a boolean to +** use to signify its presence or absence. +*/ +typedef struct +{ + UINT16 result; /* Only used in confirm messages */ + BOOLEAN mtu_present; + UINT16 mtu; + BOOLEAN qos_present; + FLOW_SPEC qos; + BOOLEAN flush_to_present; + UINT16 flush_to; + BOOLEAN fcr_present; + tL2CAP_FCR_OPTS fcr; + BOOLEAN fcs_present; /* Optionally bypasses FCS checks */ + UINT8 fcs; /* '0' if desire is to bypass FCS, otherwise '1' */ + BOOLEAN ext_flow_spec_present; + tHCI_EXT_FLOW_SPEC ext_flow_spec; + UINT16 flags; /* bit 0: 0-no continuation, 1-continuation */ +} tL2CAP_CFG_INFO; + +/* L2CAP channel configured field bitmap */ +#define L2CAP_CH_CFG_MASK_MTU 0x0001 +#define L2CAP_CH_CFG_MASK_QOS 0x0002 +#define L2CAP_CH_CFG_MASK_FLUSH_TO 0x0004 +#define L2CAP_CH_CFG_MASK_FCR 0x0008 +#define L2CAP_CH_CFG_MASK_FCS 0x0010 +#define L2CAP_CH_CFG_MASK_EXT_FLOW_SPEC 0x0020 + +typedef UINT16 tL2CAP_CH_CFG_BITS; + +/********************************* +** Callback Functions Prototypes +**********************************/ + +/* Connection indication callback prototype. Parameters are +** BD Address of remote +** Local CID assigned to the connection +** PSM that the remote wants to connect to +** Identifier that the remote sent +*/ +typedef void (tL2CA_CONNECT_IND_CB) (BD_ADDR, UINT16, UINT16, UINT8); + + +/* Connection confirmation callback prototype. Parameters are +** Local CID +** Result - 0 = connected, non-zero means failure reason +*/ +typedef void (tL2CA_CONNECT_CFM_CB) (UINT16, UINT16); + + +/* Connection pending callback prototype. Parameters are +** Local CID +*/ +typedef void (tL2CA_CONNECT_PND_CB) (UINT16); + + +/* Configuration indication callback prototype. Parameters are +** Local CID assigned to the connection +** Pointer to configuration info +*/ +typedef void (tL2CA_CONFIG_IND_CB) (UINT16, tL2CAP_CFG_INFO *); + + +/* Configuration confirm callback prototype. Parameters are +** Local CID assigned to the connection +** Pointer to configuration info +*/ +typedef void (tL2CA_CONFIG_CFM_CB) (UINT16, tL2CAP_CFG_INFO *); + + +/* Disconnect indication callback prototype. Parameters are +** Local CID +** Boolean whether upper layer should ack this +*/ +typedef void (tL2CA_DISCONNECT_IND_CB) (UINT16, BOOLEAN); + + +/* Disconnect confirm callback prototype. Parameters are +** Local CID +** Result +*/ +typedef void (tL2CA_DISCONNECT_CFM_CB) (UINT16, UINT16); + + +/* QOS Violation indication callback prototype. Parameters are +** BD Address of violating device +*/ +typedef void (tL2CA_QOS_VIOLATION_IND_CB) (BD_ADDR); + + +/* Data received indication callback prototype. Parameters are +** Local CID +** Address of buffer +*/ +typedef void (tL2CA_DATA_IND_CB) (UINT16, BT_HDR *); + + +/* Echo response callback prototype. Note that this is not included in the +** registration information, but is passed to L2CAP as part of the API to +** actually send an echo request. Parameters are +** Result +*/ +typedef void (tL2CA_ECHO_RSP_CB) (UINT16); + + +/* Callback function prototype to pass broadcom specific echo response */ +/* to the upper layer */ +typedef void (tL2CA_ECHO_DATA_CB) (BD_ADDR, UINT16, UINT8 *); + + +/* Congestion status callback protype. This callback is optional. If +** an application tries to send data when the transmit queue is full, +** the data will anyways be dropped. The parameter is: +** Local CID +** TRUE if congested, FALSE if uncongested +*/ +typedef void (tL2CA_CONGESTION_STATUS_CB) (UINT16, BOOLEAN); + +/* Callback prototype for number of packets completed events. +** This callback notifies the application when Number of Completed Packets +** event has been received. +** This callback is originally designed for 3DG devices. +** The parameter is: +** peer BD_ADDR +*/ +typedef void (tL2CA_NOCP_CB) (BD_ADDR); + +/* Transmit complete callback protype. This callback is optional. If +** set, L2CAP will call it when packets are sent or flushed. If the +** count is 0xFFFF, it means all packets are sent for that CID (eRTM +** mode only). The parameters are: +** Local CID +** Number of SDUs sent or dropped +*/ +typedef void (tL2CA_TX_COMPLETE_CB) (UINT16, UINT16); + +/* Define the structure that applications use to register with +** L2CAP. This structure includes callback functions. All functions +** MUST be provided, with the exception of the "connect pending" +** callback and "congestion status" callback. +*/ +typedef struct +{ + tL2CA_CONNECT_IND_CB *pL2CA_ConnectInd_Cb; + tL2CA_CONNECT_CFM_CB *pL2CA_ConnectCfm_Cb; + tL2CA_CONNECT_PND_CB *pL2CA_ConnectPnd_Cb; + tL2CA_CONFIG_IND_CB *pL2CA_ConfigInd_Cb; + tL2CA_CONFIG_CFM_CB *pL2CA_ConfigCfm_Cb; + tL2CA_DISCONNECT_IND_CB *pL2CA_DisconnectInd_Cb; + tL2CA_DISCONNECT_CFM_CB *pL2CA_DisconnectCfm_Cb; + tL2CA_QOS_VIOLATION_IND_CB *pL2CA_QoSViolationInd_Cb; + tL2CA_DATA_IND_CB *pL2CA_DataInd_Cb; + tL2CA_CONGESTION_STATUS_CB *pL2CA_CongestionStatus_Cb; + tL2CA_TX_COMPLETE_CB *pL2CA_TxComplete_Cb; + +} tL2CAP_APPL_INFO; + +/* Define the structure that applications use to create or accept +** connections with enhanced retransmission mode. +*/ +typedef struct +{ + UINT8 preferred_mode; + UINT8 allowed_modes; + UINT8 user_rx_pool_id; + UINT8 user_tx_pool_id; + UINT8 fcr_rx_pool_id; + UINT8 fcr_tx_pool_id; + +} tL2CAP_ERTM_INFO; + +#define L2CA_REGISTER(a,b,c) L2CA_Register(a,(tL2CAP_APPL_INFO *)b) +#define L2CA_DEREGISTER(a) L2CA_Deregister(a) +#define L2CA_CONNECT_REQ(a,b,c,d) L2CA_ErtmConnectReq(a,b,c) +#define L2CA_CONNECT_RSP(a,b,c,d,e,f,g) L2CA_ErtmConnectRsp(a,b,c,d,e,f) +#define L2CA_CONFIG_REQ(a,b) L2CA_ConfigReq(a,b) +#define L2CA_CONFIG_RSP(a,b) L2CA_ConfigRsp(a,b) +#define L2CA_DISCONNECT_REQ(a) L2CA_DisconnectReq(a) +#define L2CA_DISCONNECT_RSP(a) L2CA_DisconnectRsp(a) +#define L2CA_DATA_WRITE(a, b) L2CA_DataWrite(a, b) + +/***************************************************************************** +** External Function Declarations +*****************************************************************************/ +#ifdef __cplusplus +extern "C" +{ +#endif + +/******************************************************************************* +** +** Function L2CA_Register +** +** Description Other layers call this function to register for L2CAP +** services. +** +** Returns PSM to use or zero if error. Typically, the PSM returned +** is the same as was passed in, but for an outgoing-only +** connection to a dynamic PSM, a "virtual" PSM is returned +** and should be used in the calls to L2CA_ConnectReq() and +** BTM_SetSecurityLevel(). +** +*******************************************************************************/ +extern UINT16 L2CA_Register (UINT16 psm, tL2CAP_APPL_INFO *p_cb_info); + +/******************************************************************************* +** +** Function L2CA_Deregister +** +** Description Other layers call this function to deregister for L2CAP +** services. +** +** Returns void +** +*******************************************************************************/ +extern void L2CA_Deregister (UINT16 psm); + +/******************************************************************************* +** +** Function L2CA_AllocatePSM +** +** Description Other layers call this function to find an unused PSM for L2CAP +** services. +** +** Returns PSM to use. +** +*******************************************************************************/ +extern UINT16 L2CA_AllocatePSM(void); + +/******************************************************************************* +** +** Function L2CA_ConnectReq +** +** Description Higher layers call this function to create an L2CAP connection. +** Note that the connection is not established at this time, but +** connection establishment gets started. The callback function +** will be invoked when connection establishes or fails. +** +** Returns the CID of the connection, or 0 if it failed to start +** +*******************************************************************************/ +extern UINT16 L2CA_ConnectReq (UINT16 psm, BD_ADDR p_bd_addr); + +/******************************************************************************* +** +** Function L2CA_ConnectRsp +** +** Description Higher layers call this function to accept an incoming +** L2CAP connection, for which they had gotten an connect +** indication callback. +** +** Returns TRUE for success, FALSE for failure +** +*******************************************************************************/ +extern BOOLEAN L2CA_ConnectRsp (BD_ADDR p_bd_addr, UINT8 id, UINT16 lcid, + UINT16 result, UINT16 status); + +/******************************************************************************* +** +** Function L2CA_ErtmConnectReq +** +** Description Higher layers call this function to create an L2CAP connection +** that needs to use Enhanced Retransmission Mode. +** Note that the connection is not established at this time, but +** connection establishment gets started. The callback function +** will be invoked when connection establishes or fails. +** +** Returns the CID of the connection, or 0 if it failed to start +** +*******************************************************************************/ +extern UINT16 L2CA_ErtmConnectReq (UINT16 psm, BD_ADDR p_bd_addr, + tL2CAP_ERTM_INFO *p_ertm_info); + +// This function sets the callback routines for the L2CAP connection referred to by +// |local_cid|. The callback routines can only be modified for outgoing connections +// established by |L2CA_ConnectReq| or accepted incoming connections. |callbacks| +// must not be NULL. This function returns true if the callbacks could be updated, +// false if not (e.g. |local_cid| was not found). +bool L2CA_SetConnectionCallbacks(uint16_t local_cid, const tL2CAP_APPL_INFO *callbacks); + +/******************************************************************************* +** +** Function L2CA_ErtmConnectRsp +** +** Description Higher layers call this function to accept an incoming +** L2CAP connection, for which they had gotten an connect +** indication callback, and for which the higher layer wants +** to use Enhanced Retransmission Mode. +** +** Returns TRUE for success, FALSE for failure +** +*******************************************************************************/ +extern BOOLEAN L2CA_ErtmConnectRsp (BD_ADDR p_bd_addr, UINT8 id, UINT16 lcid, + UINT16 result, UINT16 status, + tL2CAP_ERTM_INFO *p_ertm_info); + +/******************************************************************************* +** +** Function L2CA_ConfigReq +** +** Description Higher layers call this function to send configuration. +** +** Returns TRUE if configuration sent, else FALSE +** +*******************************************************************************/ +extern BOOLEAN L2CA_ConfigReq (UINT16 cid, tL2CAP_CFG_INFO *p_cfg); + +/******************************************************************************* +** +** Function L2CA_ConfigRsp +** +** Description Higher layers call this function to send a configuration +** response. +** +** Returns TRUE if configuration response sent, else FALSE +** +*******************************************************************************/ +extern BOOLEAN L2CA_ConfigRsp (UINT16 cid, tL2CAP_CFG_INFO *p_cfg); + +/******************************************************************************* +** +** Function L2CA_DisconnectReq +** +** Description Higher layers call this function to disconnect a channel. +** +** Returns TRUE if disconnect sent, else FALSE +** +*******************************************************************************/ +extern BOOLEAN L2CA_DisconnectReq (UINT16 cid); + +/******************************************************************************* +** +** Function L2CA_DisconnectRsp +** +** Description Higher layers call this function to acknowledge the +** disconnection of a channel. +** +** Returns void +** +*******************************************************************************/ +extern BOOLEAN L2CA_DisconnectRsp (UINT16 cid); + +/******************************************************************************* +** +** Function L2CA_DataWrite +** +** Description Higher layers call this function to write data. +** +** Returns L2CAP_DW_SUCCESS, if data accepted, else FALSE +** L2CAP_DW_CONGESTED, if data accepted and the channel is congested +** L2CAP_DW_FAILED, if error +** +*******************************************************************************/ +extern UINT8 L2CA_DataWrite (UINT16 cid, BT_HDR *p_data); + +/******************************************************************************* +** +** Function L2CA_Ping +** +** Description Higher layers call this function to send an echo request. +** +** Returns TRUE if echo request sent, else FALSE. +** +*******************************************************************************/ +extern BOOLEAN L2CA_Ping (BD_ADDR p_bd_addr, tL2CA_ECHO_RSP_CB *p_cb); + +/******************************************************************************* +** +** Function L2CA_Echo +** +** Description Higher layers call this function to send an echo request +** with application-specific data. +** +** Returns TRUE if echo request sent, else FALSE. +** +*******************************************************************************/ +extern BOOLEAN L2CA_Echo (BD_ADDR p_bd_addr, BT_HDR *p_data, tL2CA_ECHO_DATA_CB *p_callback); + +// Given a local channel identifier, |lcid|, this function returns the bound remote +// channel identifier, |rcid|, and the ACL link handle, |handle|. If |lcid| is not +// known or is invalid, this function returns false and does not modify the values +// pointed at by |rcid| and |handle|. |rcid| and |handle| may be NULL. +bool L2CA_GetIdentifiers(uint16_t lcid, uint16_t *rcid, uint16_t *handle); + +/******************************************************************************* +** +** Function L2CA_SetIdleTimeout +** +** Description Higher layers call this function to set the idle timeout for +** a connection, or for all future connections. The "idle timeout" +** is the amount of time that a connection can remain up with +** no L2CAP channels on it. A timeout of zero means that the +** connection will be torn down immediately when the last channel +** is removed. A timeout of 0xFFFF means no timeout. Values are +** in seconds. +** +** Returns TRUE if command succeeded, FALSE if failed +** +*******************************************************************************/ +extern BOOLEAN L2CA_SetIdleTimeout (UINT16 cid, UINT16 timeout, + BOOLEAN is_global); + +/******************************************************************************* +** +** Function L2CA_SetIdleTimeoutByBdAddr +** +** Description Higher layers call this function to set the idle timeout for +** a connection. The "idle timeout" is the amount of time that +** a connection can remain up with no L2CAP channels on it. +** A timeout of zero means that the connection will be torn +** down immediately when the last channel is removed. +** A timeout of 0xFFFF means no timeout. Values are in seconds. +** A bd_addr is the remote BD address. If bd_addr = BT_BD_ANY, +** then the idle timeouts for all active l2cap links will be +** changed. +** +** Returns TRUE if command succeeded, FALSE if failed +** +** NOTE This timeout applies to all logical channels active on the +** ACL link. +*******************************************************************************/ +extern BOOLEAN L2CA_SetIdleTimeoutByBdAddr(BD_ADDR bd_addr, UINT16 timeout, + tBT_TRANSPORT transport); + +/******************************************************************************* +** +** Function L2CA_SetTraceLevel +** +** Description This function sets the trace level for L2CAP. If called with +** a value of 0xFF, it simply reads the current trace level. +** +** Returns the new (current) trace level +** +*******************************************************************************/ +extern UINT8 L2CA_SetTraceLevel (UINT8 trace_level); + +/******************************************************************************* +** +** Function L2CA_SetDesireRole +** +** Description This function sets the desire role for L2CAP. +** If the new role is L2CAP_ROLE_ALLOW_SWITCH, allow switch on +** HciCreateConnection. +** If the new role is L2CAP_ROLE_DISALLOW_SWITCH, do not allow switch on +** HciCreateConnection. +** +** If the new role is a valid role (HCI_ROLE_MASTER or HCI_ROLE_SLAVE), +** the desire role is set to the new value. Otherwise, it is not changed. +** +** Returns the new (current) role +** +*******************************************************************************/ +extern UINT8 L2CA_SetDesireRole (UINT8 new_role); + +/******************************************************************************* +** +** Function L2CA_LocalLoopbackReq +** +** Description This function sets up a CID for local loopback +** +** Returns CID of 0 if none. +** +*******************************************************************************/ +extern UINT16 L2CA_LocalLoopbackReq (UINT16 psm, UINT16 handle, BD_ADDR p_bd_addr); + +/******************************************************************************* +** +** Function L2CA_FlushChannel +** +** Description This function flushes none, some or all buffers queued up +** for xmission for a particular CID. If called with +** L2CAP_FLUSH_CHANS_GET (0), it simply returns the number +** of buffers queued for that CID L2CAP_FLUSH_CHANS_ALL (0xffff) +** flushes all buffers. All other values specifies the maximum +** buffers to flush. +** +** Returns Number of buffers left queued for that CID +** +*******************************************************************************/ +extern UINT16 L2CA_FlushChannel (UINT16 lcid, UINT16 num_to_flush); + + +/******************************************************************************* +** +** Function L2CA_SetAclPriority +** +** Description Sets the transmission priority for an ACL channel. +** (For initial implementation only two values are valid. +** L2CAP_PRIORITY_NORMAL and L2CAP_PRIORITY_HIGH). +** +** Returns TRUE if a valid channel, else FALSE +** +*******************************************************************************/ +extern BOOLEAN L2CA_SetAclPriority (BD_ADDR bd_addr, UINT8 priority); + +/******************************************************************************* +** +** Function L2CA_FlowControl +** +** Description Higher layers call this function to flow control a channel. +** +** data_enabled - TRUE data flows, FALSE data is stopped +** +** Returns TRUE if valid channel, else FALSE +** +*******************************************************************************/ +extern BOOLEAN L2CA_FlowControl (UINT16 cid, BOOLEAN data_enabled); + +/******************************************************************************* +** +** Function L2CA_SendTestSFrame +** +** Description Higher layers call this function to send a test S-frame. +** +** Returns TRUE if valid Channel, else FALSE +** +*******************************************************************************/ +extern BOOLEAN L2CA_SendTestSFrame (UINT16 cid, UINT8 sup_type, + UINT8 back_track); + +/******************************************************************************* +** +** Function L2CA_SetTxPriority +** +** Description Sets the transmission priority for a channel. (FCR Mode) +** +** Returns TRUE if a valid channel, else FALSE +** +*******************************************************************************/ +extern BOOLEAN L2CA_SetTxPriority (UINT16 cid, tL2CAP_CHNL_PRIORITY priority); + +/******************************************************************************* +** +** Function L2CA_RegForNoCPEvt +** +** Description Register callback for Number of Completed Packets event. +** +** Input Param p_cb - callback for Number of completed packets event +** p_bda - BT address of remote device +** +** Returns +** +*******************************************************************************/ +extern BOOLEAN L2CA_RegForNoCPEvt(tL2CA_NOCP_CB *p_cb, BD_ADDR p_bda); + +/******************************************************************************* +** +** Function L2CA_SetChnlDataRate +** +** Description Sets the tx/rx data rate for a channel. +** +** Returns TRUE if a valid channel, else FALSE +** +*******************************************************************************/ +extern BOOLEAN L2CA_SetChnlDataRate (UINT16 cid, tL2CAP_CHNL_DATA_RATE tx, tL2CAP_CHNL_DATA_RATE rx); + +typedef void (tL2CA_RESERVE_CMPL_CBACK) (void); + +/******************************************************************************* +** +** Function L2CA_SetFlushTimeout +** +** Description This function set the automatic flush time out in Baseband +** for ACL-U packets. +** BdAddr : the remote BD address of ACL link. If it is BT_DB_ANY +** then the flush time out will be applied to all ACL link. +** FlushTimeout: flush time out in ms +** 0x0000 : No automatic flush +** L2CAP_NO_RETRANSMISSION : No retransmission +** 0x0002 - 0xFFFE : flush time out, if (flush_tout*8)+3/5) +** <= HCI_MAX_AUTO_FLUSH_TOUT (in 625us slot). +** Otherwise, return FALSE. +** L2CAP_NO_AUTOMATIC_FLUSH : No automatic flush +** +** Returns TRUE if command succeeded, FALSE if failed +** +** NOTE This flush timeout applies to all logical channels active on the +** ACL link. +*******************************************************************************/ +extern BOOLEAN L2CA_SetFlushTimeout (BD_ADDR bd_addr, UINT16 flush_tout); + +/******************************************************************************* +** +** Function L2CA_DataWriteEx +** +** Description Higher layers call this function to write data with extended +** flags. +** flags : L2CAP_FLUSHABLE_CH_BASED +** L2CAP_FLUSHABLE_PKT +** L2CAP_NON_FLUSHABLE_PKT +** +** Returns L2CAP_DW_SUCCESS, if data accepted, else FALSE +** L2CAP_DW_CONGESTED, if data accepted and the channel is congested +** L2CAP_DW_FAILED, if error +** +*******************************************************************************/ +extern UINT8 L2CA_DataWriteEx (UINT16 cid, BT_HDR *p_data, UINT16 flags); + +/******************************************************************************* +** +** Function L2CA_SetChnlFlushability +** +** Description Higher layers call this function to set a channels +** flushability flags +** +** Returns TRUE if CID found, else FALSE +** +*******************************************************************************/ +extern BOOLEAN L2CA_SetChnlFlushability (UINT16 cid, BOOLEAN is_flushable); + +/******************************************************************************* +** +** Function L2CA_GetPeerFeatures +** +** Description Get a peers features and fixed channel map +** +** Parameters: BD address of the peer +** Pointers to features and channel mask storage area +** +** Return value: TRUE if peer is connected +** +*******************************************************************************/ +extern BOOLEAN L2CA_GetPeerFeatures (BD_ADDR bd_addr, UINT32 *p_ext_feat, UINT8 *p_chnl_mask); + +/******************************************************************************* +** +** Function L2CA_GetBDAddrbyHandle +** +** Description Get BD address for the given HCI handle +** +** Parameters: HCI handle +** BD address of the peer +** +** Return value: TRUE if found lcb for the given handle, FALSE otherwise +** +*******************************************************************************/ +extern BOOLEAN L2CA_GetBDAddrbyHandle (UINT16 handle, BD_ADDR bd_addr); + +/******************************************************************************* +** +** Function L2CA_GetChnlFcrMode +** +** Description Get the channel FCR mode +** +** Parameters: Local CID +** +** Return value: Channel mode +** +*******************************************************************************/ +extern UINT8 L2CA_GetChnlFcrMode (UINT16 lcid); + + +/******************************************************************************* +** +** UCD callback prototypes +** +*******************************************************************************/ + +/* UCD discovery. Parameters are +** BD Address of remote +** Data Type +** Data +*/ +#define L2CAP_UCD_INFO_TYPE_RECEPTION 0x01 +#define L2CAP_UCD_INFO_TYPE_MTU 0x02 + +typedef void (tL2CA_UCD_DISCOVER_CB) (BD_ADDR, UINT8, UINT32); + +/* UCD data received. Parameters are +** BD Address of remote +** Pointer to buffer with data +*/ +typedef void (tL2CA_UCD_DATA_CB) (BD_ADDR, BT_HDR *); + +/* Congestion status callback protype. This callback is optional. If +** an application tries to send data when the transmit queue is full, +** the data will anyways be dropped. The parameter is: +** remote BD_ADDR +** TRUE if congested, FALSE if uncongested +*/ +typedef void (tL2CA_UCD_CONGESTION_STATUS_CB) (BD_ADDR, BOOLEAN); + +/* UCD registration info (the callback addresses and PSM) +*/ +typedef struct +{ + tL2CA_UCD_DISCOVER_CB *pL2CA_UCD_Discover_Cb; + tL2CA_UCD_DATA_CB *pL2CA_UCD_Data_Cb; + tL2CA_UCD_CONGESTION_STATUS_CB *pL2CA_UCD_Congestion_Status_Cb; +} tL2CAP_UCD_CB_INFO; + +/******************************************************************************* +** +** Function L2CA_UcdRegister +** +** Description Register PSM on UCD. +** +** Parameters: tL2CAP_UCD_CB_INFO +** +** Return value: TRUE if successs +** +*******************************************************************************/ +extern BOOLEAN L2CA_UcdRegister ( UINT16 psm, tL2CAP_UCD_CB_INFO *p_cb_info ); + +/******************************************************************************* +** +** Function L2CA_UcdDeregister +** +** Description Deregister PSM on UCD. +** +** Parameters: PSM +** +** Return value: TRUE if successs +** +*******************************************************************************/ +extern BOOLEAN L2CA_UcdDeregister ( UINT16 psm ); + +/******************************************************************************* +** +** Function L2CA_UcdDiscover +** +** Description Discover UCD of remote device. +** +** Parameters: PSM +** BD_ADDR of remote device +** info_type : L2CAP_UCD_INFO_TYPE_RECEPTION +** L2CAP_UCD_INFO_TYPE_MTU +** +** +** Return value: TRUE if successs +** +*******************************************************************************/ +extern BOOLEAN L2CA_UcdDiscover ( UINT16 psm, BD_ADDR rem_bda, UINT8 info_type ); + +/******************************************************************************* +** +** Function L2CA_UcdDataWrite +** +** Description Send UCD to remote device +** +** Parameters: PSM +** BD Address of remote +** Pointer to buffer of type BT_HDR +** flags : L2CAP_FLUSHABLE_CH_BASED +** L2CAP_FLUSHABLE_PKT +** L2CAP_NON_FLUSHABLE_PKT +** +** Return value L2CAP_DW_SUCCESS, if data accepted +** L2CAP_DW_FAILED, if error +** +*******************************************************************************/ +extern UINT16 L2CA_UcdDataWrite (UINT16 psm, BD_ADDR rem_bda, BT_HDR *p_buf, UINT16 flags); + +/******************************************************************************* +** +** Function L2CA_UcdSetIdleTimeout +** +** Description Set UCD Idle timeout. +** +** Parameters: BD Addr +** Timeout in second +** +** Return value: TRUE if successs +** +*******************************************************************************/ +extern BOOLEAN L2CA_UcdSetIdleTimeout ( BD_ADDR rem_bda, UINT16 timeout ); + +/******************************************************************************* +** +** Function L2CA_UCDSetTxPriority +** +** Description Sets the transmission priority for a connectionless channel. +** +** Returns TRUE if a valid channel, else FALSE +** +*******************************************************************************/ +extern BOOLEAN L2CA_UCDSetTxPriority ( BD_ADDR rem_bda, tL2CAP_CHNL_PRIORITY priority ); + + +/******************************************************************************* +** +** Fixed Channel callback prototypes +** +*******************************************************************************/ + +/* Fixed channel connected and disconnected. Parameters are +** channel +** BD Address of remote +** TRUE if channel is connected, FALSE if disconnected +** Reason for connection failure +** transport : physical transport, BR/EDR or LE +*/ +typedef void (tL2CA_FIXED_CHNL_CB) (UINT16, BD_ADDR, BOOLEAN, UINT16, tBT_TRANSPORT); + +/* Signalling data received. Parameters are +** channel +** BD Address of remote +** Pointer to buffer with data +*/ +typedef void (tL2CA_FIXED_DATA_CB) (UINT16, BD_ADDR, BT_HDR *); + +/* Congestion status callback protype. This callback is optional. If +** an application tries to send data when the transmit queue is full, +** the data will anyways be dropped. The parameter is: +** remote BD_ADDR +** TRUE if congested, FALSE if uncongested +*/ +typedef void (tL2CA_FIXED_CONGESTION_STATUS_CB) (BD_ADDR, BOOLEAN); + +/* Fixed channel registration info (the callback addresses and channel config) +*/ +typedef struct +{ + tL2CA_FIXED_CHNL_CB *pL2CA_FixedConn_Cb; + tL2CA_FIXED_DATA_CB *pL2CA_FixedData_Cb; + tL2CA_FIXED_CONGESTION_STATUS_CB *pL2CA_FixedCong_Cb; + tL2CAP_FCR_OPTS fixed_chnl_opts; + + UINT16 default_idle_tout; + tL2CA_TX_COMPLETE_CB *pL2CA_FixedTxComplete_Cb; /* fixed channel tx complete callback */ +} tL2CAP_FIXED_CHNL_REG; + + +#if (L2CAP_NUM_FIXED_CHNLS > 0) +/******************************************************************************* +** +** Function L2CA_RegisterFixedChannel +** +** Description Register a fixed channel. +** +** Parameters: Fixed Channel # +** Channel Callbacks and config +** +** Return value: TRUE if registered OK +** +*******************************************************************************/ +extern BOOLEAN L2CA_RegisterFixedChannel (UINT16 fixed_cid, tL2CAP_FIXED_CHNL_REG *p_freg); + +/******************************************************************************* +** +** Function L2CA_ConnectFixedChnl +** +** Description Connect an fixed signalling channel to a remote device. +** +** Parameters: Fixed CID +** BD Address of remote +** +** Return value: TRUE if connection started +** +*******************************************************************************/ +extern BOOLEAN L2CA_ConnectFixedChnl (UINT16 fixed_cid, BD_ADDR bd_addr); + +/******************************************************************************* +** +** Function L2CA_SendFixedChnlData +** +** Description Write data on a fixed signalling channel. +** +** Parameters: Fixed CID +** BD Address of remote +** Pointer to buffer of type BT_HDR +** +** Return value L2CAP_DW_SUCCESS, if data accepted +** L2CAP_DW_FAILED, if error +** +*******************************************************************************/ +extern UINT16 L2CA_SendFixedChnlData (UINT16 fixed_cid, BD_ADDR rem_bda, BT_HDR *p_buf); + +/******************************************************************************* +** +** Function L2CA_RemoveFixedChnl +** +** Description Remove a fixed channel to a remote device. +** +** Parameters: Fixed CID +** BD Address of remote +** Idle timeout to use (or 0xFFFF if don't care) +** +** Return value: TRUE if channel removed +** +*******************************************************************************/ +extern BOOLEAN L2CA_RemoveFixedChnl (UINT16 fixed_cid, BD_ADDR rem_bda); + +/******************************************************************************* +** +** Function L2CA_SetFixedChannelTout +** +** Description Higher layers call this function to set the idle timeout for +** a fixed channel. The "idle timeout" is the amount of time that +** a connection can remain up with no L2CAP channels on it. +** A timeout of zero means that the connection will be torn +** down immediately when the last channel is removed. +** A timeout of 0xFFFF means no timeout. Values are in seconds. +** A bd_addr is the remote BD address. If bd_addr = BT_BD_ANY, +** then the idle timeouts for all active l2cap links will be +** changed. +** +** Returns TRUE if command succeeded, FALSE if failed +** +*******************************************************************************/ +extern BOOLEAN L2CA_SetFixedChannelTout (BD_ADDR rem_bda, UINT16 fixed_cid, UINT16 idle_tout); + +#endif /* (L2CAP_NUM_FIXED_CHNLS > 0) */ + +/******************************************************************************* +** +** Function L2CA_GetCurrentConfig +** +** Description This function returns configurations of L2CAP channel +** pp_our_cfg : pointer of our saved configuration options +** p_our_cfg_bits : valid config in bitmap +** pp_peer_cfg: pointer of peer's saved configuration options +** p_peer_cfg_bits : valid config in bitmap +** +** Returns TRUE if successful +** +*******************************************************************************/ +extern BOOLEAN L2CA_GetCurrentConfig (UINT16 lcid, + tL2CAP_CFG_INFO **pp_our_cfg, tL2CAP_CH_CFG_BITS *p_our_cfg_bits, + tL2CAP_CFG_INFO **pp_peer_cfg, tL2CAP_CH_CFG_BITS *p_peer_cfg_bits); + +#if (BLE_INCLUDED == TRUE) +/******************************************************************************* +** +** Function L2CA_CancelBleConnectReq +** +** Description Cancel a pending connection attempt to a BLE device. +** +** Parameters: BD Address of remote +** +** Return value: TRUE if connection was cancelled +** +*******************************************************************************/ +extern BOOLEAN L2CA_CancelBleConnectReq (BD_ADDR rem_bda); + +/******************************************************************************* +** +** Function L2CA_UpdateBleConnParams +** +** Description Update BLE connection parameters. +** +** Parameters: BD Address of remote +** +** Return value: TRUE if update started +** +*******************************************************************************/ +extern BOOLEAN L2CA_UpdateBleConnParams (BD_ADDR rem_bdRa, UINT16 min_int, + UINT16 max_int, UINT16 latency, UINT16 timeout); + +/******************************************************************************* +** +** Function L2CA_EnableUpdateBleConnParams +** +** Description Update BLE connection parameters. +** +** Parameters: BD Address of remote +** enable flag +** +** Return value: TRUE if update started +** +*******************************************************************************/ +extern BOOLEAN L2CA_EnableUpdateBleConnParams (BD_ADDR rem_bda, BOOLEAN enable); + +/******************************************************************************* +** +** Function L2CA_GetBleConnRole +** +** Description This function returns the connection role. +** +** Returns link role. +** +*******************************************************************************/ +extern UINT8 L2CA_GetBleConnRole (BD_ADDR bd_addr); + +/******************************************************************************* +** +** Function L2CA_GetDisconnectReason +** +** Description This function returns the disconnect reason code. +** +** Parameters: BD Address of remote +** Physical transport for the L2CAP connection (BR/EDR or LE) +** +** Returns disconnect reason +** +*******************************************************************************/ +extern UINT16 L2CA_GetDisconnectReason (BD_ADDR remote_bda, tBT_TRANSPORT transport); + +#endif /* (BLE_INCLUDED == TRUE) */ + +#ifdef __cplusplus +} +#endif + +#endif /* L2C_API_H */ diff --git a/components/bt/bluedroid/stack/include/l2c_int.h b/components/bt/bluedroid/stack/include/l2c_int.h new file mode 100755 index 0000000000..cbaca82517 --- /dev/null +++ b/components/bt/bluedroid/stack/include/l2c_int.h @@ -0,0 +1,762 @@ +/****************************************************************************** + * + * Copyright (C) 1999-2012 Broadcom Corporation + * + * 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 L2CAP internal definitions + * + ******************************************************************************/ +#ifndef L2C_INT_H +#define L2C_INT_H + +#include + +#include "btm_api.h" +#include "gki.h" +#include "l2c_api.h" +#include "l2cdefs.h" +#include "list.h" + +#define L2CAP_MIN_MTU 48 /* Minimum acceptable MTU is 48 bytes */ + +/* Timeouts. Since L2CAP works off a 1-second list, all are in seconds. +*/ +#define L2CAP_LINK_ROLE_SWITCH_TOUT 10 /* 10 seconds */ +#define L2CAP_LINK_CONNECT_TOUT 60 /* 30 seconds */ +#define L2CAP_LINK_CONNECT_TOUT_EXT 120 /* 120 seconds */ +#define L2CAP_ECHO_RSP_TOUT 30 /* 30 seconds */ +#define L2CAP_LINK_FLOW_CONTROL_TOUT 2 /* 2 seconds */ +#define L2CAP_LINK_DISCONNECT_TOUT 30 /* 30 seconds */ + +#ifndef L2CAP_CHNL_CONNECT_TOUT /* BTIF needs to override for internal project needs */ +#define L2CAP_CHNL_CONNECT_TOUT 60 /* 60 seconds */ +#endif + +#define L2CAP_CHNL_CONNECT_TOUT_EXT 120 /* 120 seconds */ +#define L2CAP_CHNL_CFG_TIMEOUT 30 /* 30 seconds */ +#define L2CAP_CHNL_DISCONNECT_TOUT 10 /* 10 seconds */ +#define L2CAP_DELAY_CHECK_SM4 2 /* 2 seconds */ +#define L2CAP_WAIT_INFO_RSP_TOUT 3 /* 3 seconds */ +#define L2CAP_WAIT_UNPARK_TOUT 2 /* 2 seconds */ +#define L2CAP_LINK_INFO_RESP_TOUT 2 /* 2 seconds */ +#define L2CAP_BLE_LINK_CONNECT_TOUT 30 /* 30 seconds */ +#define L2CAP_BLE_CONN_PARAM_UPD_TOUT 30 /* 30 seconds */ + +/* quick timer uses millisecond unit */ +#define L2CAP_DEFAULT_RETRANS_TOUT 2000 /* 2000 milliseconds */ +#define L2CAP_DEFAULT_MONITOR_TOUT 12000 /* 12000 milliseconds */ +#define L2CAP_FCR_ACK_TOUT 200 /* 200 milliseconds */ + +/* Define the possible L2CAP channel states. The names of +** the states may seem a bit strange, but they are taken from +** the Bluetooth specification. +*/ +typedef enum +{ + CST_CLOSED, /* Channel is in clodes state */ + CST_ORIG_W4_SEC_COMP, /* Originator waits security clearence */ + CST_TERM_W4_SEC_COMP, /* Acceptor waits security clearence */ + CST_W4_L2CAP_CONNECT_RSP, /* Waiting for peer conenct response */ + CST_W4_L2CA_CONNECT_RSP, /* Waiting for upper layer connect rsp */ + CST_CONFIG, /* Negotiating configuration */ + CST_OPEN, /* Data transfer state */ + CST_W4_L2CAP_DISCONNECT_RSP, /* Waiting for peer disconnect rsp */ + CST_W4_L2CA_DISCONNECT_RSP /* Waiting for upper layer disc rsp */ +} tL2C_CHNL_STATE; + +/* Define the possible L2CAP link states +*/ +typedef enum +{ + LST_DISCONNECTED, + LST_CONNECT_HOLDING, + LST_CONNECTING_WAIT_SWITCH, + LST_CONNECTING, + LST_CONNECTED, + LST_DISCONNECTING +} tL2C_LINK_STATE; + + + +/* Define input events to the L2CAP link and channel state machines. The names +** of the events may seem a bit strange, but they are taken from +** the Bluetooth specification. +*/ +#define L2CEVT_LP_CONNECT_CFM 0 /* Lower layer connect confirm */ +#define L2CEVT_LP_CONNECT_CFM_NEG 1 /* Lower layer connect confirm (failed) */ +#define L2CEVT_LP_CONNECT_IND 2 /* Lower layer connect indication */ +#define L2CEVT_LP_DISCONNECT_IND 3 /* Lower layer disconnect indication */ +#define L2CEVT_LP_QOS_CFM 4 /* Lower layer QOS confirmation */ +#define L2CEVT_LP_QOS_CFM_NEG 5 /* Lower layer QOS confirmation (failed)*/ +#define L2CEVT_LP_QOS_VIOLATION_IND 6 /* Lower layer QOS violation indication */ + +#define L2CEVT_SEC_COMP 7 /* Security cleared successfully */ +#define L2CEVT_SEC_COMP_NEG 8 /* Security procedure failed */ + +#define L2CEVT_L2CAP_CONNECT_REQ 10 /* Peer connection request */ +#define L2CEVT_L2CAP_CONNECT_RSP 11 /* Peer connection response */ +#define L2CEVT_L2CAP_CONNECT_RSP_PND 12 /* Peer connection response pending */ +#define L2CEVT_L2CAP_CONNECT_RSP_NEG 13 /* Peer connection response (failed) */ +#define L2CEVT_L2CAP_CONFIG_REQ 14 /* Peer configuration request */ +#define L2CEVT_L2CAP_CONFIG_RSP 15 /* Peer configuration response */ +#define L2CEVT_L2CAP_CONFIG_RSP_NEG 16 /* Peer configuration response (failed) */ +#define L2CEVT_L2CAP_DISCONNECT_REQ 17 /* Peer disconnect request */ +#define L2CEVT_L2CAP_DISCONNECT_RSP 18 /* Peer disconnect response */ +#define L2CEVT_L2CAP_INFO_RSP 19 /* Peer information response */ +#define L2CEVT_L2CAP_DATA 20 /* Peer data */ + +#define L2CEVT_L2CA_CONNECT_REQ 21 /* Upper layer connect request */ +#define L2CEVT_L2CA_CONNECT_RSP 22 /* Upper layer connect response */ +#define L2CEVT_L2CA_CONNECT_RSP_NEG 23 /* Upper layer connect response (failed)*/ +#define L2CEVT_L2CA_CONFIG_REQ 24 /* Upper layer config request */ +#define L2CEVT_L2CA_CONFIG_RSP 25 /* Upper layer config response */ +#define L2CEVT_L2CA_CONFIG_RSP_NEG 26 /* Upper layer config response (failed) */ +#define L2CEVT_L2CA_DISCONNECT_REQ 27 /* Upper layer disconnect request */ +#define L2CEVT_L2CA_DISCONNECT_RSP 28 /* Upper layer disconnect response */ +#define L2CEVT_L2CA_DATA_READ 29 /* Upper layer data read */ +#define L2CEVT_L2CA_DATA_WRITE 30 /* Upper layer data write */ +#define L2CEVT_L2CA_FLUSH_REQ 31 /* Upper layer flush */ + +#define L2CEVT_TIMEOUT 32 /* Timeout */ +#define L2CEVT_SEC_RE_SEND_CMD 33 /* btm_sec has enough info to proceed */ + +#define L2CEVT_ACK_TIMEOUT 34 /* RR delay timeout */ + + +/* Bitmask to skip over Broadcom feature reserved (ID) to avoid sending two + successive ID values, '0' id only or both */ +#define L2CAP_ADJ_BRCM_ID 0x1 +#define L2CAP_ADJ_ZERO_ID 0x2 +#define L2CAP_ADJ_ID 0x3 + +/* Return values for l2cu_process_peer_cfg_req() */ +#define L2CAP_PEER_CFG_UNACCEPTABLE 0 +#define L2CAP_PEER_CFG_OK 1 +#define L2CAP_PEER_CFG_DISCONNECT 2 + +/* eL2CAP option constants */ +#define L2CAP_MIN_RETRANS_TOUT 2000 /* Min retransmission timeout if no flush timeout or PBF */ +#define L2CAP_MIN_MONITOR_TOUT 12000 /* Min monitor timeout if no flush timeout or PBF */ + +#define L2CAP_MAX_FCR_CFG_TRIES 2 /* Config attempts before disconnecting */ + +typedef uint8_t tL2C_BLE_FIXED_CHNLS_MASK; + +typedef struct +{ + UINT8 next_tx_seq; /* Next sequence number to be Tx'ed */ + UINT8 last_rx_ack; /* Last sequence number ack'ed by the peer */ + UINT8 next_seq_expected; /* Next peer sequence number expected */ + UINT8 last_ack_sent; /* Last peer sequence number ack'ed */ + UINT8 num_tries; /* Number of retries to send a packet */ + UINT8 max_held_acks; /* Max acks we can hold before sending */ + + BOOLEAN remote_busy; /* TRUE if peer has flowed us off */ + BOOLEAN local_busy; /* TRUE if we have flowed off the peer */ + + BOOLEAN rej_sent; /* Reject was sent */ + BOOLEAN srej_sent; /* Selective Reject was sent */ + BOOLEAN wait_ack; /* Transmitter is waiting ack (poll sent) */ + BOOLEAN rej_after_srej; /* Send a REJ when SREJ clears */ + + BOOLEAN send_f_rsp; /* We need to send an F-bit response */ + + UINT16 rx_sdu_len; /* Length of the SDU being received */ + BT_HDR *p_rx_sdu; /* Buffer holding the SDU being received */ + BUFFER_Q waiting_for_ack_q; /* Buffers sent and waiting for peer to ack */ + BUFFER_Q srej_rcv_hold_q; /* Buffers rcvd but held pending SREJ rsp */ + BUFFER_Q retrans_q; /* Buffers being retransmitted */ + + TIMER_LIST_ENT ack_timer; /* Timer delaying RR */ + TIMER_LIST_ENT mon_retrans_timer; /* Timer Monitor or Retransmission */ + +#if (L2CAP_ERTM_STATS == TRUE) + UINT32 connect_tick_count; /* Time channel was established */ + UINT32 ertm_pkt_counts[2]; /* Packets sent and received */ + UINT32 ertm_byte_counts[2]; /* Bytes sent and received */ + UINT32 s_frames_sent[4]; /* S-frames sent (RR, REJ, RNR, SREJ) */ + UINT32 s_frames_rcvd[4]; /* S-frames rcvd (RR, REJ, RNR, SREJ) */ + UINT32 xmit_window_closed; /* # of times the xmit window was closed */ + UINT32 controller_idle; /* # of times less than 2 packets in controller */ + /* when the xmit window was closed */ + UINT32 pkts_retransmitted; /* # of packets that were retransmitted */ + UINT32 retrans_touts; /* # of retransmission timouts */ + UINT32 xmit_ack_touts; /* # of xmit ack timouts */ + +#define L2CAP_ERTM_STATS_NUM_AVG 10 +#define L2CAP_ERTM_STATS_AVG_NUM_SAMPLES 100 + UINT32 ack_delay_avg_count; + UINT32 ack_delay_avg_index; + UINT32 throughput_start; + UINT32 throughput[L2CAP_ERTM_STATS_NUM_AVG]; + UINT32 ack_delay_avg[L2CAP_ERTM_STATS_NUM_AVG]; + UINT32 ack_delay_min[L2CAP_ERTM_STATS_NUM_AVG]; + UINT32 ack_delay_max[L2CAP_ERTM_STATS_NUM_AVG]; + UINT32 ack_q_count_avg[L2CAP_ERTM_STATS_NUM_AVG]; + UINT32 ack_q_count_min[L2CAP_ERTM_STATS_NUM_AVG]; + UINT32 ack_q_count_max[L2CAP_ERTM_STATS_NUM_AVG]; +#endif +} tL2C_FCRB; + + +/* Define a registration control block. Every application (e.g. RFCOMM, SDP, +** TCS etc) that registers with L2CAP is assigned one of these. +*/ +#if (L2CAP_UCD_INCLUDED == TRUE) +#define L2C_UCD_RCB_ID 0x00 +#define L2C_UCD_STATE_UNUSED 0x00 +#define L2C_UCD_STATE_W4_DATA 0x01 +#define L2C_UCD_STATE_W4_RECEPTION 0x02 +#define L2C_UCD_STATE_W4_MTU 0x04 + +typedef struct +{ + UINT8 state; + tL2CAP_UCD_CB_INFO cb_info; +} tL2C_UCD_REG; +#endif + +typedef struct +{ + BOOLEAN in_use; + UINT16 psm; + UINT16 real_psm; /* This may be a dummy RCB for an o/b connection but */ + /* this is the real PSM that we need to connect to */ +#if (L2CAP_UCD_INCLUDED == TRUE) + tL2C_UCD_REG ucd; +#endif + + tL2CAP_APPL_INFO api; +} tL2C_RCB; + + +/* Define a channel control block (CCB). There may be many channel control blocks +** between the same two Bluetooth devices (i.e. on the same link). +** Each CCB has unique local and remote CIDs. All channel control blocks on +** the same physical link and are chained together. +*/ +typedef struct t_l2c_ccb +{ + BOOLEAN in_use; /* TRUE when in use, FALSE when not */ + tL2C_CHNL_STATE chnl_state; /* Channel state */ + + struct t_l2c_ccb *p_next_ccb; /* Next CCB in the chain */ + struct t_l2c_ccb *p_prev_ccb; /* Previous CCB in the chain */ + struct t_l2c_linkcb *p_lcb; /* Link this CCB is assigned to */ + + UINT16 local_cid; /* Local CID */ + UINT16 remote_cid; /* Remote CID */ + + TIMER_LIST_ENT timer_entry; /* CCB Timer List Entry */ + + tL2C_RCB *p_rcb; /* Registration CB for this Channel */ + bool should_free_rcb; /* True if RCB was allocated on the heap */ + +#define IB_CFG_DONE 0x01 +#define OB_CFG_DONE 0x02 +#define RECONFIG_FLAG 0x04 /* True after initial configuration */ +#define CFG_DONE_MASK (IB_CFG_DONE | OB_CFG_DONE) + + UINT8 config_done; /* Configuration flag word */ + UINT8 local_id; /* Transaction ID for local trans */ + UINT8 remote_id; /* Transaction ID for local */ + +#define CCB_FLAG_NO_RETRY 0x01 /* no more retry */ +#define CCB_FLAG_SENT_PENDING 0x02 /* already sent pending response */ + UINT8 flags; + + tL2CAP_CFG_INFO our_cfg; /* Our saved configuration options */ + tL2CAP_CH_CFG_BITS peer_cfg_bits; /* Store what peer wants to configure */ + tL2CAP_CFG_INFO peer_cfg; /* Peer's saved configuration options */ + + BUFFER_Q xmit_hold_q; /* Transmit data hold queue */ + BOOLEAN cong_sent; /* Set when congested status sent */ + UINT16 buff_quota; /* Buffer quota before sending congestion */ + + tL2CAP_CHNL_PRIORITY ccb_priority; /* Channel priority */ + tL2CAP_CHNL_DATA_RATE tx_data_rate; /* Channel Tx data rate */ + tL2CAP_CHNL_DATA_RATE rx_data_rate; /* Channel Rx data rate */ + + /* Fields used for eL2CAP */ + tL2CAP_ERTM_INFO ertm_info; + tL2C_FCRB fcrb; + UINT16 tx_mps; /* TX MPS adjusted based on current controller */ + UINT16 max_rx_mtu; + UINT8 fcr_cfg_tries; /* Max number of negotiation attempts */ + BOOLEAN peer_cfg_already_rejected; /* If mode rejected once, set to TRUE */ + BOOLEAN out_cfg_fcr_present; /* TRUE if cfg response shoulkd include fcr options */ + +#define L2CAP_CFG_FCS_OUR 0x01 /* Our desired config FCS option */ +#define L2CAP_CFG_FCS_PEER 0x02 /* Peer's desired config FCS option */ +#define L2CAP_BYPASS_FCS (L2CAP_CFG_FCS_OUR | L2CAP_CFG_FCS_PEER) + UINT8 bypass_fcs; + +#if (L2CAP_NON_FLUSHABLE_PB_INCLUDED == TRUE) + BOOLEAN is_flushable; /* TRUE if channel is flushable */ +#endif + +#if (L2CAP_NUM_FIXED_CHNLS > 0) || (L2CAP_UCD_INCLUDED == TRUE) + UINT16 fixed_chnl_idle_tout; /* Idle timeout to use for the fixed channel */ +#endif + UINT16 tx_data_len; +} tL2C_CCB; + +/*********************************************************************** +** Define a queue of linked CCBs. +*/ +typedef struct +{ + tL2C_CCB *p_first_ccb; /* The first channel in this queue */ + tL2C_CCB *p_last_ccb; /* The last channel in this queue */ +} tL2C_CCB_Q; + +#if (L2CAP_ROUND_ROBIN_CHANNEL_SERVICE == TRUE) + +/* Round-Robin service for the same priority channels */ +#define L2CAP_NUM_CHNL_PRIORITY 3 /* Total number of priority group (high, medium, low)*/ +#define L2CAP_CHNL_PRIORITY_WEIGHT 5 /* weight per priority for burst transmission quota */ +#define L2CAP_GET_PRIORITY_QUOTA(pri) ((L2CAP_NUM_CHNL_PRIORITY - (pri)) * L2CAP_CHNL_PRIORITY_WEIGHT) + +/* CCBs within the same LCB are served in round robin with priority */ +/* It will make sure that low priority channel (for example, HF signaling on RFCOMM) */ +/* can be sent to headset even if higher priority channel (for example, AV media channel) */ +/* is congested. */ + +typedef struct +{ + tL2C_CCB *p_serve_ccb; /* current serving ccb within priority group */ + tL2C_CCB *p_first_ccb; /* first ccb of priority group */ + UINT8 num_ccb; /* number of channels in priority group */ + UINT8 quota; /* burst transmission quota */ +} tL2C_RR_SERV; + +#endif /* (L2CAP_ROUND_ROBIN_CHANNEL_SERVICE == TRUE) */ + +/* Define a link control block. There is one link control block between +** this device and any other device (i.e. BD ADDR). +*/ +typedef struct t_l2c_linkcb +{ + BOOLEAN in_use; /* TRUE when in use, FALSE when not */ + tL2C_LINK_STATE link_state; + + TIMER_LIST_ENT timer_entry; /* Timer list entry for timeout evt */ + UINT16 handle; /* The handle used with LM */ + + tL2C_CCB_Q ccb_queue; /* Queue of CCBs on this LCB */ + + tL2C_CCB *p_pending_ccb; /* ccb of waiting channel during link disconnect */ + TIMER_LIST_ENT info_timer_entry; /* Timer entry for info resp timeout evt */ + BD_ADDR remote_bd_addr; /* The BD address of the remote */ + + UINT8 link_role; /* Master or slave */ + UINT8 id; + UINT8 cur_echo_id; /* Current id value for echo request */ + tL2CA_ECHO_RSP_CB *p_echo_rsp_cb; /* Echo response callback */ + UINT16 idle_timeout; /* Idle timeout */ + BOOLEAN is_bonding; /* True - link active only for bonding */ + + UINT16 link_flush_tout; /* Flush timeout used */ + + UINT16 link_xmit_quota; /* Num outstanding pkts allowed */ + UINT16 sent_not_acked; /* Num packets sent but not acked */ + + BOOLEAN partial_segment_being_sent; /* Set TRUE when a partial segment */ + /* is being sent. */ + BOOLEAN w4_info_rsp; /* TRUE when info request is active */ + UINT8 info_rx_bits; /* set 1 if received info type */ + UINT32 peer_ext_fea; /* Peer's extended features mask */ + list_t *link_xmit_data_q; /* Link transmit data buffer queue */ + + UINT8 peer_chnl_mask[L2CAP_FIXED_CHNL_ARRAY_SIZE]; +#if (L2CAP_UCD_INCLUDED == TRUE) + UINT16 ucd_mtu; /* peer MTU on UCD */ + BUFFER_Q ucd_out_sec_pending_q; /* Security pending outgoing UCD packet */ + BUFFER_Q ucd_in_sec_pending_q; /* Security pending incoming UCD packet */ +#endif + + BT_HDR *p_hcit_rcv_acl; /* Current HCIT ACL buf being rcvd */ + UINT16 idle_timeout_sv; /* Save current Idle timeout */ + UINT8 acl_priority; /* L2C_PRIORITY_NORMAL or L2C_PRIORITY_HIGH */ + tL2CA_NOCP_CB *p_nocp_cb; /* Num Cmpl pkts callback */ + +#if (L2CAP_NUM_FIXED_CHNLS > 0) + tL2C_CCB *p_fixed_ccbs[L2CAP_NUM_FIXED_CHNLS]; + UINT16 disc_reason; +#endif + + tBT_TRANSPORT transport; +#if (BLE_INCLUDED == TRUE) + tBLE_ADDR_TYPE ble_addr_type; + UINT16 tx_data_len; /* tx data length used in data length extension */ + +#define L2C_BLE_CONN_UPDATE_DISABLE 0x1 /* disable update connection parameters */ +#define L2C_BLE_NEW_CONN_PARAM 0x2 /* new connection parameter to be set */ +#define L2C_BLE_UPDATE_PENDING 0x4 /* waiting for connection update finished */ +#define L2C_BLE_NOT_DEFAULT_PARAM 0x8 /* not using default connection parameters */ + UINT8 conn_update_mask; + + UINT16 min_interval; /* parameters as requested by peripheral */ + UINT16 max_interval; + UINT16 latency; + UINT16 timeout; + +#endif + +#if (L2CAP_ROUND_ROBIN_CHANNEL_SERVICE == TRUE) + /* each priority group is limited burst transmission */ + /* round robin service for the same priority channels */ + tL2C_RR_SERV rr_serv[L2CAP_NUM_CHNL_PRIORITY]; + UINT8 rr_pri; /* current serving priority group */ +#endif + +} tL2C_LCB; + +/* Define the L2CAP control structure +*/ +typedef struct +{ + UINT8 l2cap_trace_level; + UINT16 controller_xmit_window; /* Total ACL window for all links */ + + UINT16 round_robin_quota; /* Round-robin link quota */ + UINT16 round_robin_unacked; /* Round-robin unacked */ + BOOLEAN check_round_robin; /* Do a round robin check */ + + BOOLEAN is_cong_cback_context; + + tL2C_LCB lcb_pool[MAX_L2CAP_LINKS]; /* Link Control Block pool */ + tL2C_CCB ccb_pool[MAX_L2CAP_CHANNELS]; /* Channel Control Block pool */ + tL2C_RCB rcb_pool[MAX_L2CAP_CLIENTS]; /* Registration info pool */ + + tL2C_CCB *p_free_ccb_first; /* Pointer to first free CCB */ + tL2C_CCB *p_free_ccb_last; /* Pointer to last free CCB */ + + UINT8 desire_role; /* desire to be master/slave when accepting a connection */ + BOOLEAN disallow_switch; /* FALSE, to allow switch at create conn */ + UINT16 num_lm_acl_bufs; /* # of ACL buffers on controller */ + UINT16 idle_timeout; /* Idle timeout */ + + list_t *rcv_pending_q; /* Recv pending queue */ + TIMER_LIST_ENT rcv_hold_tle; /* Timer list entry for rcv hold */ + + tL2C_LCB *p_cur_hcit_lcb; /* Current HCI Transport buffer */ + UINT16 num_links_active; /* Number of links active */ + +#if (L2CAP_NON_FLUSHABLE_PB_INCLUDED == TRUE) + UINT16 non_flushable_pbf; /* L2CAP_PKT_START_NON_FLUSHABLE if controller supports */ + /* Otherwise, L2CAP_PKT_START */ + BOOLEAN is_flush_active; /* TRUE if an HCI_Enhanced_Flush has been sent */ +#endif + +#if L2CAP_CONFORMANCE_TESTING == TRUE + UINT32 test_info_resp; /* Conformance testing needs a dynamic response */ +#endif + +#if (L2CAP_NUM_FIXED_CHNLS > 0) + tL2CAP_FIXED_CHNL_REG fixed_reg[L2CAP_NUM_FIXED_CHNLS]; /* Reg info for fixed channels */ +#endif + +#if (BLE_INCLUDED == TRUE) + UINT16 num_ble_links_active; /* Number of LE links active */ + BOOLEAN is_ble_connecting; + BD_ADDR ble_connecting_bda; + UINT16 controller_le_xmit_window; /* Total ACL window for all links */ + tL2C_BLE_FIXED_CHNLS_MASK l2c_ble_fixed_chnls_mask; // LE fixed channels mask + UINT16 num_lm_ble_bufs; /* # of ACL buffers on controller */ + UINT16 ble_round_robin_quota; /* Round-robin link quota */ + UINT16 ble_round_robin_unacked; /* Round-robin unacked */ + BOOLEAN ble_check_round_robin; /* Do a round robin check */ +#endif + + tL2CA_ECHO_DATA_CB *p_echo_data_cb; /* Echo data callback */ + +#if (defined(L2CAP_HIGH_PRI_CHAN_QUOTA_IS_CONFIGURABLE) && (L2CAP_HIGH_PRI_CHAN_QUOTA_IS_CONFIGURABLE == TRUE)) + UINT16 high_pri_min_xmit_quota; /* Minimum number of ACL credit for high priority link */ +#endif /* (L2CAP_HIGH_PRI_CHAN_QUOTA_IS_CONFIGURABLE == TRUE) */ + + UINT16 dyn_psm; +} tL2C_CB; + + + +/* Define a structure that contains the information about a connection. +** This structure is used to pass between functions, and not all the +** fields will always be filled in. +*/ +typedef struct +{ + BD_ADDR bd_addr; /* Remote BD address */ + UINT8 status; /* Connection status */ + UINT16 psm; /* PSM of the connection */ + UINT16 l2cap_result; /* L2CAP result */ + UINT16 l2cap_status; /* L2CAP status */ + UINT16 remote_cid; /* Remote CID */ +} tL2C_CONN_INFO; + + +typedef void (tL2C_FCR_MGMT_EVT_HDLR) (UINT8, tL2C_CCB *); + +/* The offset in a buffer that L2CAP will use when building commands. +*/ +#define L2CAP_SEND_CMD_OFFSET 0 + + +/* Number of ACL buffers to use for high priority channel +*/ +#if (!defined(L2CAP_HIGH_PRI_CHAN_QUOTA_IS_CONFIGURABLE) || (L2CAP_HIGH_PRI_CHAN_QUOTA_IS_CONFIGURABLE == FALSE)) +#define L2CAP_HIGH_PRI_MIN_XMIT_QUOTA_A (L2CAP_HIGH_PRI_MIN_XMIT_QUOTA) +#else +#define L2CAP_HIGH_PRI_MIN_XMIT_QUOTA_A (l2cb.high_pri_min_xmit_quota) +#endif + +#ifdef __cplusplus +extern "C" { +#endif + + +/* L2CAP global data +************************************ +*/ +#if (!defined L2C_DYNAMIC_MEMORY) || (L2C_DYNAMIC_MEMORY == FALSE) +extern tL2C_CB l2cb; +#else +extern tL2C_CB *l2c_cb_ptr; +#define l2cb (*l2c_cb_ptr) +#endif + + +/* Functions provided by l2c_main.c +************************************ +*/ +void l2c_init(void); +void l2c_free(void); + +extern void l2c_process_timeout (TIMER_LIST_ENT *p_tle); +extern UINT8 l2c_data_write (UINT16 cid, BT_HDR *p_data, UINT16 flag); +extern void l2c_rcv_acl_data (BT_HDR *p_msg); +extern void l2c_process_held_packets (BOOLEAN timed_out); + +/* Functions provided by l2c_utils.c +************************************ +*/ +extern tL2C_LCB *l2cu_allocate_lcb (BD_ADDR p_bd_addr, BOOLEAN is_bonding, tBT_TRANSPORT transport); +extern BOOLEAN l2cu_start_post_bond_timer (UINT16 handle); +extern void l2cu_release_lcb (tL2C_LCB *p_lcb); +extern tL2C_LCB *l2cu_find_lcb_by_bd_addr (BD_ADDR p_bd_addr, tBT_TRANSPORT transport); +extern tL2C_LCB *l2cu_find_lcb_by_handle (UINT16 handle); +extern void l2cu_update_lcb_4_bonding (BD_ADDR p_bd_addr, BOOLEAN is_bonding); + +extern UINT8 l2cu_get_conn_role (tL2C_LCB *p_this_lcb); +extern BOOLEAN l2cu_set_acl_priority (BD_ADDR bd_addr, UINT8 priority, BOOLEAN reset_after_rs); + +extern void l2cu_enqueue_ccb (tL2C_CCB *p_ccb); +extern void l2cu_dequeue_ccb (tL2C_CCB *p_ccb); +extern void l2cu_change_pri_ccb (tL2C_CCB *p_ccb, tL2CAP_CHNL_PRIORITY priority); + +extern tL2C_CCB *l2cu_allocate_ccb (tL2C_LCB *p_lcb, UINT16 cid); +extern void l2cu_release_ccb (tL2C_CCB *p_ccb); +extern tL2C_CCB *l2cu_find_ccb_by_cid (tL2C_LCB *p_lcb, UINT16 local_cid); +extern tL2C_CCB *l2cu_find_ccb_by_remote_cid (tL2C_LCB *p_lcb, UINT16 remote_cid); +extern void l2cu_adj_id (tL2C_LCB *p_lcb, UINT8 adj_mask); +extern BOOLEAN l2c_is_cmd_rejected (UINT8 cmd_code, UINT8 id, tL2C_LCB *p_lcb); + +extern void l2cu_send_peer_cmd_reject (tL2C_LCB *p_lcb, UINT16 reason, + UINT8 rem_id,UINT16 p1, UINT16 p2); +extern void l2cu_send_peer_connect_req (tL2C_CCB *p_ccb); +extern void l2cu_send_peer_connect_rsp (tL2C_CCB *p_ccb, UINT16 result, UINT16 status); +extern void l2cu_send_peer_config_req (tL2C_CCB *p_ccb, tL2CAP_CFG_INFO *p_cfg); +extern void l2cu_send_peer_config_rsp (tL2C_CCB *p_ccb, tL2CAP_CFG_INFO *p_cfg); +extern void l2cu_send_peer_config_rej (tL2C_CCB *p_ccb, UINT8 *p_data, UINT16 data_len, UINT16 rej_len); +extern void l2cu_send_peer_disc_req (tL2C_CCB *p_ccb); +extern void l2cu_send_peer_disc_rsp (tL2C_LCB *p_lcb, UINT8 remote_id, UINT16 local_cid, UINT16 remote_cid); +extern void l2cu_send_peer_echo_req (tL2C_LCB *p_lcb, UINT8 *p_data, UINT16 data_len); +extern void l2cu_send_peer_echo_rsp (tL2C_LCB *p_lcb, UINT8 id, UINT8 *p_data, UINT16 data_len); +extern void l2cu_send_peer_info_rsp (tL2C_LCB *p_lcb, UINT8 id, UINT16 info_type); +extern void l2cu_reject_connection (tL2C_LCB *p_lcb, UINT16 remote_cid, UINT8 rem_id, UINT16 result); +extern void l2cu_send_peer_info_req (tL2C_LCB *p_lcb, UINT16 info_type); +extern void l2cu_set_acl_hci_header (BT_HDR *p_buf, tL2C_CCB *p_ccb); +extern void l2cu_check_channel_congestion (tL2C_CCB *p_ccb); +extern void l2cu_disconnect_chnl (tL2C_CCB *p_ccb); + +#if (L2CAP_NON_FLUSHABLE_PB_INCLUDED == TRUE) +extern void l2cu_set_non_flushable_pbf(BOOLEAN); +#endif + +#if (BLE_INCLUDED == TRUE) +extern void l2cu_send_peer_ble_par_req (tL2C_LCB *p_lcb, UINT16 min_int, UINT16 max_int, UINT16 latency, UINT16 timeout); +extern void l2cu_send_peer_ble_par_rsp (tL2C_LCB *p_lcb, UINT16 reason, UINT8 rem_id); +#endif + +extern BOOLEAN l2cu_initialize_fixed_ccb (tL2C_LCB *p_lcb, UINT16 fixed_cid, tL2CAP_FCR_OPTS *p_fcr); +extern void l2cu_no_dynamic_ccbs (tL2C_LCB *p_lcb); +extern void l2cu_process_fixed_chnl_resp (tL2C_LCB *p_lcb); + +/* Functions provided by l2c_ucd.c +************************************ +*/ +#if (L2CAP_UCD_INCLUDED == TRUE) +void l2c_ucd_delete_sec_pending_q(tL2C_LCB *p_lcb); +void l2c_ucd_enqueue_pending_out_sec_q(tL2C_CCB *p_ccb, void *p_data); +BOOLEAN l2c_ucd_check_pending_info_req(tL2C_CCB *p_ccb); +BOOLEAN l2c_ucd_check_pending_out_sec_q(tL2C_CCB *p_ccb); +void l2c_ucd_send_pending_out_sec_q(tL2C_CCB *p_ccb); +void l2c_ucd_discard_pending_out_sec_q(tL2C_CCB *p_ccb); +BOOLEAN l2c_ucd_check_pending_in_sec_q(tL2C_CCB *p_ccb); +void l2c_ucd_send_pending_in_sec_q(tL2C_CCB *p_ccb); +void l2c_ucd_discard_pending_in_sec_q(tL2C_CCB *p_ccb); +BOOLEAN l2c_ucd_check_rx_pkts(tL2C_LCB *p_lcb, BT_HDR *p_msg); +BOOLEAN l2c_ucd_process_event(tL2C_CCB *p_ccb, UINT16 event, void *p_data); +#endif + +#if (BLE_INCLUDED == TRUE) +extern void l2cu_send_peer_ble_par_req (tL2C_LCB *p_lcb, UINT16 min_int, UINT16 max_int, UINT16 latency, UINT16 timeout); +extern void l2cu_send_peer_ble_par_rsp (tL2C_LCB *p_lcb, UINT16 reason, UINT8 rem_id); +#endif + +extern BOOLEAN l2cu_initialize_fixed_ccb (tL2C_LCB *p_lcb, UINT16 fixed_cid, tL2CAP_FCR_OPTS *p_fcr); +extern void l2cu_no_dynamic_ccbs (tL2C_LCB *p_lcb); +extern void l2cu_process_fixed_chnl_resp (tL2C_LCB *p_lcb); + + +/* Functions provided for Broadcom Aware +**************************************** +*/ +extern BOOLEAN l2cu_check_feature_req (tL2C_LCB *p_lcb, UINT8 id, UINT8 *p_data, UINT16 data_len); +extern void l2cu_check_feature_rsp (tL2C_LCB *p_lcb, UINT8 id, UINT8 *p_data, UINT16 data_len); +extern void l2cu_send_feature_req (tL2C_CCB *p_ccb); + +extern tL2C_RCB *l2cu_allocate_rcb (UINT16 psm); +extern tL2C_RCB *l2cu_find_rcb_by_psm (UINT16 psm); +extern void l2cu_release_rcb (tL2C_RCB *p_rcb); + +extern UINT8 l2cu_process_peer_cfg_req (tL2C_CCB *p_ccb, tL2CAP_CFG_INFO *p_cfg); +extern void l2cu_process_peer_cfg_rsp (tL2C_CCB *p_ccb, tL2CAP_CFG_INFO *p_cfg); +extern void l2cu_process_our_cfg_req (tL2C_CCB *p_ccb, tL2CAP_CFG_INFO *p_cfg); +extern void l2cu_process_our_cfg_rsp (tL2C_CCB *p_ccb, tL2CAP_CFG_INFO *p_cfg); + +extern void l2cu_device_reset (void); +extern tL2C_LCB *l2cu_find_lcb_by_state (tL2C_LINK_STATE state); +extern BOOLEAN l2cu_lcb_disconnecting (void); + +extern BOOLEAN l2cu_create_conn (tL2C_LCB *p_lcb, tBT_TRANSPORT transport); +extern BOOLEAN l2cu_create_conn_after_switch (tL2C_LCB *p_lcb); +extern BT_HDR *l2cu_get_next_buffer_to_send (tL2C_LCB *p_lcb); +extern void l2cu_resubmit_pending_sec_req (BD_ADDR p_bda); +extern void l2cu_initialize_amp_ccb (tL2C_LCB *p_lcb); +extern void l2cu_adjust_out_mps (tL2C_CCB *p_ccb); + +/* Functions provided by l2c_link.c +************************************ +*/ +extern BOOLEAN l2c_link_hci_conn_req (BD_ADDR bd_addr); +extern BOOLEAN l2c_link_hci_conn_comp (UINT8 status, UINT16 handle, BD_ADDR p_bda); +extern BOOLEAN l2c_link_hci_disc_comp (UINT16 handle, UINT8 reason); +extern BOOLEAN l2c_link_hci_qos_violation (UINT16 handle); +extern void l2c_link_timeout (tL2C_LCB *p_lcb); +extern void l2c_info_timeout (tL2C_LCB *p_lcb); +extern void l2c_link_check_send_pkts (tL2C_LCB *p_lcb, tL2C_CCB *p_ccb, BT_HDR *p_buf); +extern void l2c_link_adjust_allocation (void); +extern void l2c_link_process_num_completed_pkts (UINT8 *p); +extern void l2c_link_process_num_completed_blocks (UINT8 controller_id, UINT8 *p, UINT16 evt_len); +extern void l2c_link_processs_num_bufs (UINT16 num_lm_acl_bufs); +extern UINT8 l2c_link_pkts_rcvd (UINT16 *num_pkts, UINT16 *handles); +extern void l2c_link_role_changed (BD_ADDR bd_addr, UINT8 new_role, UINT8 hci_status); +extern void l2c_link_sec_comp (BD_ADDR p_bda, tBT_TRANSPORT trasnport, void *p_ref_data, UINT8 status); +extern void l2c_link_segments_xmitted (BT_HDR *p_msg); +extern void l2c_pin_code_request (BD_ADDR bd_addr); +extern void l2c_link_adjust_chnl_allocation (void); + +#if (BLE_INCLUDED == TRUE) +extern void l2c_link_processs_ble_num_bufs (UINT16 num_lm_acl_bufs); +#endif + +#if L2CAP_WAKE_PARKED_LINK == TRUE +extern BOOLEAN l2c_link_check_power_mode ( tL2C_LCB *p_lcb ); +#define L2C_LINK_CHECK_POWER_MODE(x) l2c_link_check_power_mode ((x)) +#else // L2CAP_WAKE_PARKED_LINK +#define L2C_LINK_CHECK_POWER_MODE(x) (FALSE) +#endif // L2CAP_WAKE_PARKED_LINK + +#if L2CAP_CONFORMANCE_TESTING == TRUE +/* Used only for conformance testing */ +extern void l2cu_set_info_rsp_mask (UINT32 mask); +#endif + +/* Functions provided by l2c_csm.c +************************************ +*/ +extern void l2c_csm_execute (tL2C_CCB *p_ccb, UINT16 event, void *p_data); + +extern void l2c_enqueue_peer_data (tL2C_CCB *p_ccb, BT_HDR *p_buf); + + +/* Functions provided by l2c_fcr.c +************************************ +*/ +extern void l2c_fcr_cleanup (tL2C_CCB *p_ccb); +extern void l2c_fcr_proc_pdu (tL2C_CCB *p_ccb, BT_HDR *p_buf); +extern void l2c_fcr_proc_tout (tL2C_CCB *p_ccb); +extern void l2c_fcr_proc_ack_tout (tL2C_CCB *p_ccb); +extern void l2c_fcr_send_S_frame (tL2C_CCB *p_ccb, UINT16 function_code, UINT16 pf_bit); +extern BT_HDR *l2c_fcr_clone_buf (BT_HDR *p_buf, UINT16 new_offset, UINT16 no_of_bytes, UINT8 pool); +extern BOOLEAN l2c_fcr_is_flow_controlled (tL2C_CCB *p_ccb); +extern BT_HDR *l2c_fcr_get_next_xmit_sdu_seg (tL2C_CCB *p_ccb, UINT16 max_packet_length); +extern void l2c_fcr_start_timer (tL2C_CCB *p_ccb); + +/* Configuration negotiation */ +extern UINT8 l2c_fcr_chk_chan_modes (tL2C_CCB *p_ccb); +extern BOOLEAN l2c_fcr_adj_our_req_options (tL2C_CCB *p_ccb, tL2CAP_CFG_INFO *p_cfg); +extern void l2c_fcr_adj_our_rsp_options (tL2C_CCB *p_ccb, tL2CAP_CFG_INFO *p_peer_cfg); +extern BOOLEAN l2c_fcr_renegotiate_chan(tL2C_CCB *p_ccb, tL2CAP_CFG_INFO *p_cfg); +extern UINT8 l2c_fcr_process_peer_cfg_req(tL2C_CCB *p_ccb, tL2CAP_CFG_INFO *p_cfg); +extern void l2c_fcr_adj_monitor_retran_timeout (tL2C_CCB *p_ccb); +extern void l2c_fcr_stop_timer (tL2C_CCB *p_ccb); + +/* Functions provided by l2c_ble.c +************************************ +*/ +#if (BLE_INCLUDED == TRUE) +extern BOOLEAN l2cble_create_conn (tL2C_LCB *p_lcb); +extern void l2cble_process_sig_cmd (tL2C_LCB *p_lcb, UINT8 *p, UINT16 pkt_len); +extern void l2cble_conn_comp (UINT16 handle, UINT8 role, BD_ADDR bda, tBLE_ADDR_TYPE type, + UINT16 conn_interval, UINT16 conn_latency, UINT16 conn_timeout); +extern BOOLEAN l2cble_init_direct_conn (tL2C_LCB *p_lcb); +extern void l2cble_notify_le_connection (BD_ADDR bda); +extern void l2c_ble_link_adjust_allocation (void); +extern void l2cble_process_conn_update_evt (UINT16 handle, UINT8 status); + +#if (defined BLE_LLT_INCLUDED) && (BLE_LLT_INCLUDED == TRUE) +extern void l2cble_process_rc_param_request_evt(UINT16 handle, UINT16 int_min, UINT16 int_max, + UINT16 latency, UINT16 timeout); +#endif + +extern void l2cble_update_data_length(tL2C_LCB *p_lcb); +extern void l2cble_set_fixed_channel_tx_data_length(BD_ADDR remote_bda, UINT16 fix_cid, + UINT16 tx_mtu); +extern void l2cble_process_data_length_change_event(UINT16 handle, UINT16 tx_data_len, + UINT16 rx_data_len); + +#endif +extern void l2cu_process_fixed_disc_cback (tL2C_LCB *p_lcb); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/components/bt/bluedroid/stack/include/l2cap_client.h b/components/bt/bluedroid/stack/include/l2cap_client.h new file mode 100755 index 0000000000..c7da782470 --- /dev/null +++ b/components/bt/bluedroid/stack/include/l2cap_client.h @@ -0,0 +1,77 @@ +/****************************************************************************** + * + * Copyright (C) 2014 Google, Inc. + * + * 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. + * + ******************************************************************************/ + +#ifndef _L2CAP_CLIENT_H_ +#define _L2CAP_CLIENT_H_ + +//#include +#include +#include + +typedef struct buffer_t buffer_t; +typedef struct l2cap_client_t l2cap_client_t; + +typedef struct { + void (*connected)(l2cap_client_t *client, void *context); + void (*disconnected)(l2cap_client_t *client, void *context); + void (*read_ready)(l2cap_client_t *client, buffer_t *packet, void *context); + void (*write_ready)(l2cap_client_t *client, void *context); +} l2cap_client_callbacks_t; + +// Returns a new buffer with enough space for |size| bytes of L2CAP payload. +// |size| must be greater than zero. This function returns NULL if the buffer +// could not be allocated. The returned buffer must be freed with |buffer_free| +// when it is no longer needed. +buffer_t *l2cap_buffer_new(size_t size); + +// Creates and returns a new L2CAP client object. |callbacks| must not be NULL and +// must specify a set of functions that should be called back when events occur +// on the L2CAP connection. |context| may be NULL and will be passed as the argument +// to all callbacks in |l2cap_client_callbacks_t|. The returned object must be freed +// with |l2cap_client_free|. +l2cap_client_t *l2cap_client_new(const l2cap_client_callbacks_t *callbacks, void *context); + +// Frees the L2CAP client object allocated with |l2cap_client_new|. |client| may be NULL. +void l2cap_client_free(l2cap_client_t *client); + +// Attempts to connect the |client| to a peer device specified by |remote_bdaddr| +// using the |psm| protocol specifier. This function returns true if the connect +// operation could be started and will indicate completion with either a 'connected' +// callback (success) or a 'disconnected' callback (failure). +// +// This function must not be called while a connect operation is in progress or +// while |l2cap_client_is_connected|. |client| and |remote_bdaddr| must not be NULL. +// |psm| must be greater than zero. +bool l2cap_client_connect(l2cap_client_t *client, const bt_bdaddr_t *remote_bdaddr, uint16_t psm); + +// Disconnects a connected |client|. This function is asynchronous and idempotent. It +// will indicate completion with a 'disconnected' callback. |client| must not be NULL. +void l2cap_client_disconnect(l2cap_client_t *client); + +// Returns true if |client| is connected and is ready to accept data written to it. +// |client| must not be NULL. +bool l2cap_client_is_connected(const l2cap_client_t *client); + +// Writes data contained in |packet| to a connected |client|. This function returns +// true if the packet was successfully queued for delivery, false if the client cannot +// accept more data at this time. If this function returns false, the caller must wait +// for the 'write_ready' callback to write additional data to the client. Neither +// |client| nor |packet| may be NULL. +bool l2cap_client_write(l2cap_client_t *client, buffer_t *packet); + +#endif /*_L2CAP_CLIENT_H_*/ diff --git a/components/bt/bluedroid/stack/include/l2cdefs.h b/components/bt/bluedroid/stack/include/l2cdefs.h new file mode 100755 index 0000000000..a6e25eb9e7 --- /dev/null +++ b/components/bt/bluedroid/stack/include/l2cdefs.h @@ -0,0 +1,317 @@ +/****************************************************************************** + * + * Copyright (C) 1999-2012 Broadcom Corporation + * + * 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. + * + ******************************************************************************/ + +#ifndef L2CDEFS_H +#define L2CDEFS_H + +/* L2CAP command codes +*/ +#define L2CAP_CMD_REJECT 0x01 +#define L2CAP_CMD_CONN_REQ 0x02 +#define L2CAP_CMD_CONN_RSP 0x03 +#define L2CAP_CMD_CONFIG_REQ 0x04 +#define L2CAP_CMD_CONFIG_RSP 0x05 +#define L2CAP_CMD_DISC_REQ 0x06 +#define L2CAP_CMD_DISC_RSP 0x07 +#define L2CAP_CMD_ECHO_REQ 0x08 +#define L2CAP_CMD_ECHO_RSP 0x09 +#define L2CAP_CMD_INFO_REQ 0x0A +#define L2CAP_CMD_INFO_RSP 0x0B +#define L2CAP_CMD_AMP_CONN_REQ 0x0C +#define L2CAP_CMD_AMP_CONN_RSP 0x0D +#define L2CAP_CMD_AMP_MOVE_REQ 0x0E +#define L2CAP_CMD_AMP_MOVE_RSP 0x0F +#define L2CAP_CMD_AMP_MOVE_CFM 0x10 +#define L2CAP_CMD_AMP_MOVE_CFM_RSP 0x11 +#define L2CAP_CMD_BLE_UPDATE_REQ 0x12 +#define L2CAP_CMD_BLE_UPDATE_RSP 0x13 + + +/* Define some packet and header lengths +*/ +#define L2CAP_PKT_OVERHEAD 4 /* Length and CID */ +#define L2CAP_CMD_OVERHEAD 4 /* Cmd code, Id and length */ +#define L2CAP_CMD_REJECT_LEN 2 /* Reason (data is optional) */ +#define L2CAP_CONN_REQ_LEN 4 /* PSM and source CID */ +#define L2CAP_CONN_RSP_LEN 8 /* Dest CID, source CID, reason, status */ +#define L2CAP_CONFIG_REQ_LEN 4 /* Dest CID, flags (data is optional) */ +#define L2CAP_CONFIG_RSP_LEN 6 /* Dest CID, flags, result,data optional*/ +#define L2CAP_DISC_REQ_LEN 4 /* Dest CID, source CID */ +#define L2CAP_DISC_RSP_LEN 4 /* Dest CID, source CID */ +#define L2CAP_ECHO_REQ_LEN 0 /* Data is optional */ +#define L2CAP_ECHO_RSP_LEN 0 /* Data is optional */ +#define L2CAP_INFO_REQ_LEN 2 /* Info type */ +#define L2CAP_INFO_RSP_LEN 4 /* Info type, result (data is optional) */ +#define L2CAP_BCST_OVERHEAD 2 /* Additional broadcast packet overhead */ +#define L2CAP_UCD_OVERHEAD 2 /* Additional connectionless packet overhead */ + +#define L2CAP_AMP_CONN_REQ_LEN 5 /* PSM, CID, and remote controller ID */ +#define L2CAP_AMP_MOVE_REQ_LEN 3 /* CID and remote controller ID */ +#define L2CAP_AMP_MOVE_RSP_LEN 4 /* CID and result */ +#define L2CAP_AMP_MOVE_CFM_LEN 4 /* CID and result */ +#define L2CAP_AMP_MOVE_CFM_RSP_LEN 2 /* CID */ + +#define L2CAP_CMD_BLE_UPD_REQ_LEN 8 /* Min and max interval, latency, tout */ +#define L2CAP_CMD_BLE_UPD_RSP_LEN 2 /* Result */ + + +/* Define the packet boundary flags +*/ +#if (L2CAP_NON_FLUSHABLE_PB_INCLUDED == TRUE) +#define L2CAP_PKT_START_FLUSHABLE 2 +#define L2CAP_PKT_START_NON_FLUSHABLE 0 +#endif +#define L2CAP_COMPLETE_AMP_PKT 3 /* complete L2CAP packet on AMP HCI */ +#define L2CAP_PKT_START 2 +#define L2CAP_PKT_CONTINUE 1 +#define L2CAP_MASK_FLAG 0x0FFF +#define L2CAP_PKT_TYPE_SHIFT 12 +#define L2CAP_PKT_TYPE_MASK 3 + + +/* Define the L2CAP connection result codes +*/ +#define L2CAP_CONN_OK 0 +#define L2CAP_CONN_PENDING 1 +#define L2CAP_CONN_NO_PSM 2 +#define L2CAP_CONN_SECURITY_BLOCK 3 +#define L2CAP_CONN_NO_RESOURCES 4 +#define L2CAP_CONN_BAD_CTLR_ID 5 /* AMP related */ +#define L2CAP_CONN_TIMEOUT 0xEEEE +#define L2CAP_CONN_AMP_FAILED 254 +#define L2CAP_CONN_NO_LINK 255 /* Add a couple of our own for internal use */ +#define L2CAP_CONN_CANCEL 256 /* L2CAP connection cancelled */ + + +/* Define L2CAP Move Channel Response result codes +*/ +#define L2CAP_MOVE_OK 0 +#define L2CAP_MOVE_PENDING 1 +#define L2CAP_MOVE_CTRL_ID_NOT_SUPPORT 2 +#define L2CAP_MOVE_SAME_CTRLR_ID 3 +#define L2CAP_MOVE_CONFIG_NOT_SUPPORTED 4 +#define L2CAP_MOVE_CHAN_COLLISION 5 +#define L2CAP_MOVE_NOT_ALLOWED 6 + + +/* Define L2CAP Move Channel Confirmation result codes +*/ +#define L2CAP_MOVE_CFM_OK 0 +#define L2CAP_MOVE_CFM_REFUSED 1 + + +/* Define the L2CAP command reject reason codes +*/ +#define L2CAP_CMD_REJ_NOT_UNDERSTOOD 0 +#define L2CAP_CMD_REJ_MTU_EXCEEDED 1 +#define L2CAP_CMD_REJ_INVALID_CID 2 + + +/* L2CAP Predefined CIDs +*/ +#define L2CAP_SIGNALLING_CID 1 +#define L2CAP_CONNECTIONLESS_CID 2 +#define L2CAP_AMP_CID 3 +#define L2CAP_ATT_CID 4 +#define L2CAP_BLE_SIGNALLING_CID 5 +#define L2CAP_SMP_CID 6 +#define L2CAP_SMP_BR_CID 7 +#define L2CAP_AMP_TEST_CID 0x003F +#define L2CAP_BASE_APPL_CID 0x0040 +#define L2CAP_BLE_CONN_MAX_CID 0x007F + +/* Fixed Channels mask bits */ + +/* Signal channel supported (Mandatory) */ +#define L2CAP_FIXED_CHNL_SIG_BIT (1 << L2CAP_SIGNALLING_CID) + +/* Connectionless reception */ +#define L2CAP_FIXED_CHNL_CNCTLESS_BIT (1 << L2CAP_CONNECTIONLESS_CID) + +/* AMP Manager supported */ +#define L2CAP_FIXED_CHNL_AMP_BIT (1 << L2CAP_AMP_CID) + +/* Attribute protocol supported */ +#define L2CAP_FIXED_CHNL_ATT_BIT (1 << L2CAP_ATT_CID) + +/* BLE Signalling supported */ +#define L2CAP_FIXED_CHNL_BLE_SIG_BIT (1 << L2CAP_BLE_SIGNALLING_CID) + +/* BLE Security Mgr supported */ +#define L2CAP_FIXED_CHNL_SMP_BIT (1 << L2CAP_SMP_CID) + +/* Security Mgr over BR supported */ +#define L2CAP_FIXED_CHNL_SMP_BR_BIT (1 << L2CAP_SMP_BR_CID) + + + +/* Define the L2CAP configuration result codes +*/ +#define L2CAP_CFG_OK 0 +#define L2CAP_CFG_UNACCEPTABLE_PARAMS 1 +#define L2CAP_CFG_FAILED_NO_REASON 2 +#define L2CAP_CFG_UNKNOWN_OPTIONS 3 +#define L2CAP_CFG_PENDING 4 +#define L2CAP_CFG_FLOW_SPEC_REJECTED 5 + + +/* Define the L2CAP configuration option types +*/ +#define L2CAP_CFG_TYPE_MTU 0x01 +#define L2CAP_CFG_TYPE_FLUSH_TOUT 0x02 +#define L2CAP_CFG_TYPE_QOS 0x03 +#define L2CAP_CFG_TYPE_FCR 0x04 +#define L2CAP_CFG_TYPE_FCS 0x05 +#define L2CAP_CFG_TYPE_EXT_FLOW 0x06 +#define L2CAP_CFG_TYPE_EXT_WIN_SIZE 0x07 + +#define L2CAP_CFG_MTU_OPTION_LEN 2 /* MTU option length */ +#define L2CAP_CFG_FLUSH_OPTION_LEN 2 /* Flush option len */ +#define L2CAP_CFG_QOS_OPTION_LEN 22 /* QOS option length */ +#define L2CAP_CFG_FCR_OPTION_LEN 9 /* FCR option length */ +#define L2CAP_CFG_FCS_OPTION_LEN 1 /* FCR option length */ +#define L2CAP_CFG_EXT_FLOW_OPTION_LEN 16 /* Extended Flow Spec */ +#define L2CAP_CFG_EXT_WIN_SIZE_LEN 2 /* Ext window size length */ +#define L2CAP_CFG_OPTION_OVERHEAD 2 /* Type and length */ + +/* Configuration Cmd/Rsp Flags mask +*/ +#define L2CAP_CFG_FLAGS_MASK_CONT 0x0001 /* Flags mask: Continuation */ + +/* FCS Check Option values +*/ +#define L2CAP_CFG_FCS_BYPASS 0 /* Bypass the FCS in streaming or ERTM modes */ +#define L2CAP_CFG_FCS_USE 1 /* Use the FCS in streaming or ERTM modes [default] */ + +/* Default values for configuration +*/ +#define L2CAP_NO_AUTOMATIC_FLUSH 0xFFFF +#define L2CAP_NO_RETRANSMISSION 0x0001 + +#define L2CAP_DEFAULT_MTU (672) +#define L2CAP_DEFAULT_FLUSH_TO L2CAP_NO_AUTOMATIC_FLUSH +#define L2CAP_DEFAULT_SERV_TYPE 1 +#define L2CAP_DEFAULT_TOKEN_RATE 0 +#define L2CAP_DEFAULT_BUCKET_SIZE 0 +#define L2CAP_DEFAULT_PEAK_BANDWIDTH 0 +#define L2CAP_DEFAULT_LATENCY 0xFFFFFFFF +#define L2CAP_DEFAULT_DELAY 0xFFFFFFFF +#define L2CAP_DEFAULT_FCS L2CAP_CFG_FCS_USE + + +/* Define the L2CAP disconnect result codes +*/ +#define L2CAP_DISC_OK 0 +#define L2CAP_DISC_TIMEOUT 0xEEEE + +/* Define the L2CAP info resp result codes +*/ +#define L2CAP_INFO_RESP_RESULT_SUCCESS 0 +#define L2CAP_INFO_RESP_RESULT_NOT_SUPPORTED 1 + +/* Define the info-type fields of information request & response +*/ +#define L2CAP_CONNLESS_MTU_INFO_TYPE 0x0001 +#define L2CAP_EXTENDED_FEATURES_INFO_TYPE 0x0002 /* Used in Information Req/Response */ +#define L2CAP_FIXED_CHANNELS_INFO_TYPE 0x0003 /* Used in AMP */ + +#define L2CAP_CONNLESS_MTU_INFO_SIZE 2 /* Connectionless MTU size */ +#define L2CAP_EXTENDED_FEATURES_ARRAY_SIZE 4 /* Extended features array size */ +#define L2CAP_FIXED_CHNL_ARRAY_SIZE 8 /* Fixed channel array size */ + +/* Extended features mask bits +*/ +#define L2CAP_EXTFEA_RTRANS 0x00000001 /* Retransmission Mode (Not Supported) */ +#define L2CAP_EXTFEA_FC 0x00000002 /* Flow Control Mode (Not Supported) */ +#define L2CAP_EXTFEA_QOS 0x00000004 +#define L2CAP_EXTFEA_ENH_RETRANS 0x00000008 /* Enhanced retransmission mode */ +#define L2CAP_EXTFEA_STREAM_MODE 0x00000010 /* Streaming Mode */ +#define L2CAP_EXTFEA_NO_CRC 0x00000020 /* Optional FCS (if set No FCS desired) */ +#define L2CAP_EXTFEA_EXT_FLOW_SPEC 0x00000040 /* Extended flow spec */ +#define L2CAP_EXTFEA_FIXED_CHNLS 0x00000080 /* Fixed channels */ +#define L2CAP_EXTFEA_EXT_WINDOW 0x00000100 /* Extended Window Size */ +#define L2CAP_EXTFEA_UCD_RECEPTION 0x00000200 /* Unicast Connectionless Data Reception */ + +/* Mask for locally supported features used in Information Response (default to none) */ +#ifndef L2CAP_EXTFEA_SUPPORTED_MASK +#define L2CAP_EXTFEA_SUPPORTED_MASK 0 +#endif + +/* Mask for LE supported features used in Information Response (default to none) */ +#ifndef L2CAP_BLE_EXTFEA_MASK +#define L2CAP_BLE_EXTFEA_MASK 0 +#endif + +/* Define a value that tells L2CAP to use the default HCI ACL buffer pool */ +#define L2CAP_DEFAULT_ERM_POOL_ID 0xFF +/* Define a value that tells L2CAP to use the default MPS */ +#define L2CAP_DEFAULT_ERM_MPS 0x0000 + +#define L2CAP_FCR_OVERHEAD 2 /* Control word */ +#define L2CAP_FCS_LEN 2 /* FCS takes 2 bytes */ +#define L2CAP_SDU_LEN_OVERHEAD 2 /* SDU length field is 2 bytes */ +#define L2CAP_SDU_LEN_OFFSET 2 /* SDU length offset is 2 bytes */ +#define L2CAP_EXT_CONTROL_OVERHEAD 4 /* Extended Control Field */ +#define L2CAP_MAX_HEADER_FCS (L2CAP_PKT_OVERHEAD + L2CAP_EXT_CONTROL_OVERHEAD + L2CAP_SDU_LEN_OVERHEAD + L2CAP_FCS_LEN) + /* length(2), channel(2), control(4), SDU length(2) FCS(2) */ +/* To optimize this, it must be a multiplum of the L2CAP PDU length AND match the 3DH5 air + * including the l2cap headers in each packet - to match the latter - the -5 is added + */ +#define L2CAP_MAX_SDU_LENGTH (GKI_BUF4_SIZE - (L2CAP_MIN_OFFSET + L2CAP_MAX_HEADER_FCS) -5) + +/* Part of L2CAP_MIN_OFFSET that is not part of L2CAP +*/ +#define L2CAP_OFFSET_WO_L2HDR (L2CAP_MIN_OFFSET-(L2CAP_PKT_OVERHEAD+L2CAP_FCR_OVERHEAD)) + +/* SAR bits in the control word +*/ +#define L2CAP_FCR_UNSEG_SDU 0x0000 /* Control word to begin with for unsegmented PDU*/ +#define L2CAP_FCR_START_SDU 0x4000 /* ...for Starting PDU of a semented SDU */ +#define L2CAP_FCR_END_SDU 0x8000 /* ...for ending PDU of a segmented SDU */ +#define L2CAP_FCR_CONT_SDU 0xc000 /* ...for continuation PDU of a segmented SDU */ + +/* Supervisory frame types +*/ +#define L2CAP_FCR_SUP_RR 0x0000 /* Supervisory frame - RR */ +#define L2CAP_FCR_SUP_REJ 0x0001 /* Supervisory frame - REJ */ +#define L2CAP_FCR_SUP_RNR 0x0002 /* Supervisory frame - RNR */ +#define L2CAP_FCR_SUP_SREJ 0x0003 /* Supervisory frame - SREJ */ + +#define L2CAP_FCR_SAR_BITS 0xC000 /* Mask to get the SAR bits from control word */ +#define L2CAP_FCR_SAR_BITS_SHIFT 14 /* Bits to shift right to get the SAR bits from ctrl-word */ + +#define L2CAP_FCR_S_FRAME_BIT 0x0001 /* Mask to check if a PDU is S-frame */ +#define L2CAP_FCR_REQ_SEQ_BITS 0x3F00 /* Mask to get the req-seq from control word */ +#define L2CAP_FCR_REQ_SEQ_BITS_SHIFT 8 /* Bits to shift right to get the req-seq from ctrl-word */ +#define L2CAP_FCR_TX_SEQ_BITS 0x007E /* Mask on get the tx-seq from control word */ +#define L2CAP_FCR_TX_SEQ_BITS_SHIFT 1 /* Bits to shift right to get the tx-seq from ctrl-word */ + +#define L2CAP_FCR_F_BIT 0x0080 /* F-bit in the control word (Sup and I frames) */ +#define L2CAP_FCR_P_BIT 0x0010 /* P-bit in the control word (Sup frames only) */ + +#define L2CAP_FCR_F_BIT_SHIFT 7 +#define L2CAP_FCR_P_BIT_SHIFT 4 + +#define L2CAP_FCR_SEG_BITS 0xC000 /* Mask to get the segmentation bits from ctrl-word */ +#define L2CAP_FCR_SUP_SHIFT 2 /* Bits to shift right to get the S-bits from ctrl-word */ +#define L2CAP_FCR_SUP_BITS 0x000C /* Mask to get the supervisory bits from ctrl-word */ + +#define L2CAP_FCR_INIT_CRC 0 /* Initial state of the CRC register */ +#define L2CAP_FCR_SEQ_MODULO 0x3F /* Mask for sequence numbers (range 0 - 63) */ + +#endif diff --git a/components/bt/bluedroid/stack/include/p_256_ecc_pp.h b/components/bt/bluedroid/stack/include/p_256_ecc_pp.h new file mode 100755 index 0000000000..fd3dc64fe3 --- /dev/null +++ b/components/bt/bluedroid/stack/include/p_256_ecc_pp.h @@ -0,0 +1,65 @@ +/****************************************************************************** + * + * Copyright (C) 2006-2015 Broadcom Corporation + * + * 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 simple pairing algorithms using Elliptic Curve Cryptography for private public key + * + ******************************************************************************/ + +#pragma once + +#include "p_256_multprecision.h" + +typedef unsigned long DWORD; + +typedef struct { + DWORD x[KEY_LENGTH_DWORDS_P256]; + DWORD y[KEY_LENGTH_DWORDS_P256]; + DWORD z[KEY_LENGTH_DWORDS_P256]; +} Point; + +typedef struct { + // curve's coefficients + DWORD a[KEY_LENGTH_DWORDS_P256]; + DWORD b[KEY_LENGTH_DWORDS_P256]; + + //whether a is -3 + int a_minus3; + + // prime modulus + DWORD p[KEY_LENGTH_DWORDS_P256]; + + // Omega, p = 2^m -omega + DWORD omega[KEY_LENGTH_DWORDS_P256]; + + // base point, a point on E of order r + Point G; + +} elliptic_curve_t; + +extern elliptic_curve_t curve; +extern elliptic_curve_t curve_p256; + +void ECC_PointMult_Bin_NAF(Point *q, Point *p, DWORD *n, uint32_t keyLength); + +#define ECC_PointMult(q, p, n, keyLength) ECC_PointMult_Bin_NAF(q, p, n, keyLength) + +void p_256_init_curve(UINT32 keyLength); + + diff --git a/components/bt/bluedroid/stack/include/p_256_multprecision.h b/components/bt/bluedroid/stack/include/p_256_multprecision.h new file mode 100755 index 0000000000..0d1a964c38 --- /dev/null +++ b/components/bt/bluedroid/stack/include/p_256_multprecision.h @@ -0,0 +1,62 @@ +/****************************************************************************** + * + * Copyright (C) 2006-2015 Broadcom Corporation + * + * 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 simple pairing algorithms + * + ******************************************************************************/ +#pragma once + +#include "bt_types.h" + +/* Type definitions */ +typedef unsigned long DWORD; + +#define DWORD_BITS 32 +#define DWORD_BYTES 4 +#define DWORD_BITS_SHIFT 5 + +#define KEY_LENGTH_DWORDS_P192 6 +#define KEY_LENGTH_DWORDS_P256 8 +/* Arithmetic Operations */ + +int multiprecision_compare(DWORD *a, DWORD *b, uint32_t keyLength); +int multiprecision_iszero(DWORD *a, uint32_t keyLength); +void multiprecision_init(DWORD *c, uint32_t keyLength); +void multiprecision_copy(DWORD *c, DWORD *a, uint32_t keyLength); +UINT32 multiprecision_dword_bits (DWORD a); +UINT32 multiprecision_most_signdwords(DWORD *a, uint32_t keyLength); +UINT32 multiprecision_most_signbits(DWORD *a, uint32_t keyLength); +void multiprecision_inv_mod(DWORD *aminus, DWORD *a, uint32_t keyLength); +DWORD multiprecision_add(DWORD *c, DWORD *a, DWORD *b, uint32_t keyLength); // c=a+b +void multiprecision_add_mod(DWORD *c, DWORD *a, DWORD *b, uint32_t keyLength); +DWORD multiprecision_sub(DWORD *c, DWORD *a, DWORD *b, uint32_t keyLength); // c=a-b +void multiprecision_sub_mod(DWORD *c, DWORD *a, DWORD *b, uint32_t keyLength); +void multiprecision_rshift(DWORD * c, DWORD * a, uint32_t keyLength); // c=a>>1, return carrier +void multiprecision_lshift_mod(DWORD * c, DWORD * a, uint32_t keyLength); // c=a<> RFCOMM_SHIFT_CR; \ + dlci = *p_data++ >> RFCOMM_SHIFT_DLCI; \ + if (!ea) dlci += *p_data++ << RFCOMM_SHIFT_DLCI2; \ +} + +#define RFCOMM_FORMAT_CTRL_FIELD(p_data, ea, cr, dlci) \ + *p_data++ = ea | cr | (dlci << RFCOMM_SHIFT_DLCI) + +#define RFCOMM_PARSE_TYPE_FIELD(type, pf, p_data) \ +{ \ + type = *p_data & ~RFCOMM_PF_MASK; \ + pf = (*p_data++ & RFCOMM_PF_MASK) >> RFCOMM_PF_OFFSET;\ +} + +#define RFCOMM_FORMAT_TYPE_FIELD(p_data, type, pf) \ + *p_data++ = (type | (pf << RFCOMM_PF_OFFSET)) \ +{ \ + type = *p_data & ~RFCOMM_PF_MASK; \ + pf = (*p_data++ & RFCOMM_PF_MASK) >> RFCOMM_PF_OFFSET;\ +} + +#define RFCOMM_PARSE_LEN_FIELD(ea, length, p_data) \ +{ \ + ea = (*p_data & RFCOMM_EA); \ + length = (*p_data++ >> RFCOMM_SHIFT_LENGTH1); \ + if (!ea) length += (*p_data++ << RFCOMM_SHIFT_LENGTH2); \ +} + +#define RFCOMM_FRAME_IS_CMD(initiator, cr) \ + (( (initiator) && !(cr)) || (!(initiator) && (cr))) + +#define RFCOMM_FRAME_IS_RSP(initiator, cr) \ + (( (initiator) && (cr)) || (!(initiator) && !(cr))) + +#define RFCOMM_CR(initiator, is_command) \ + (( ( (initiator) && (is_command)) \ + || (!(initiator) && !(is_command))) << 1) + +#define RFCOMM_I_CR(is_command) ((is_command) ? 0x02 : 0x00) + +#define RFCOMM_MAX_DLCI 61 + +#define RFCOMM_VALID_DLCI(dlci) \ + (((dlci) == 0) || (((dlci) >= 2) && ((dlci) <= RFCOMM_MAX_DLCI))) + + +/* Port Negotiation (PN) */ +#define RFCOMM_PN_DLCI_MASK 0x3F + +#define RFCOMM_PN_FRAM_TYPE_UIH 0x00 +#define RFCOMM_PN_FRAME_TYPE_MASK 0x0F + +#define RFCOMM_PN_CONV_LAYER_MASK 0xF0 +#define RFCOMM_PN_CONV_LAYER_TYPE_1 0 +#define RFCOMM_PN_CONV_LAYER_CBFC_I 0xF0 +#define RFCOMM_PN_CONV_LAYER_CBFC_R 0xE0 + +#define RFCOMM_PN_PRIORITY_MASK 0x3F +#define RFCOMM_PN_PRIORITY_0 0 + +#define RFCOMM_PN_K_MASK 0x07 + +#define RFCOMM_T1_DSEC 0 /* None negotiable in RFCOMM */ +#define RFCOMM_N2 0 /* Number of retransmissions */ +#define RFCOMM_K 0 /* Window size */ +#define RFCOMM_K_MAX 7 /* Max value of K for credit based flow control */ + +#define RFCOMM_MSC_FC 0x02 /* Flow control*/ +#define RFCOMM_MSC_RTC 0x04 /* Ready to communicate*/ +#define RFCOMM_MSC_RTR 0x08 /* Ready to receive*/ +#define RFCOMM_MSC_IC 0x40 /* Incomming call indicator*/ +#define RFCOMM_MSC_DV 0x80 /* Data Valid*/ + +#define RFCOMM_MSC_SHIFT_BREAK 4 +#define RFCOMM_MSC_BREAK_MASK 0xF0 +#define RFCOMM_MSC_BREAK_PRESENT_MASK 0x02 + +#define RFCOMM_BAUD_RATE_2400 0x00 +#define RFCOMM_BAUD_RATE_4800 0x01 +#define RFCOMM_BAUD_RATE_7200 0x02 +#define RFCOMM_BAUD_RATE_9600 0x03 +#define RFCOMM_BAUD_RATE_19200 0x04 +#define RFCOMM_BAUD_RATE_38400 0x05 +#define RFCOMM_BAUD_RATE_57600 0x06 +#define RFCOMM_BAUD_RATE_115200 0x07 +#define RFCOMM_BAUD_RATE_230400 0x08 + +#define RFCOMM_5_BITS 0x00 +#define RFCOMM_6_BITS 0x01 +#define RFCOMM_7_BITS 0x02 +#define RFCOMM_8_BITS 0x03 + +#define RFCOMM_RPN_BITS_MASK 0x03 +#define RFCOMM_RPN_BITS_SHIFT 0 + +#define RFCOMM_ONESTOPBIT 0x00 +#define RFCOMM_ONE5STOPBITS 0x01 + +#define RFCOMM_RPN_STOP_BITS_MASK 0x01 +#define RFCOMM_RPN_STOP_BITS_SHIFT 2 + +#define RFCOMM_PARITY_NO 0x00 +#define RFCOMM_PARITY_YES 0x01 +#define RFCOMM_RPN_PARITY_MASK 0x01 +#define RFCOMM_RPN_PARITY_SHIFT 3 + +#define RFCOMM_ODD_PARITY 0x00 +#define RFCOMM_EVEN_PARITY 0x01 +#define RFCOMM_MARK_PARITY 0x02 +#define RFCOMM_SPACE_PARITY 0x03 + +#define RFCOMM_RPN_PARITY_TYPE_MASK 0x03 +#define RFCOMM_RPN_PARITY_TYPE_SHIFT 4 + +#define RFCOMM_FC_OFF 0x00 +#define RFCOMM_FC_XONXOFF_ON_INPUT 0x01 +#define RFCOMM_FC_XONXOFF_ON_OUTPUT 0x02 +#define RFCOMM_FC_RTR_ON_INPUT 0x04 +#define RFCOMM_FC_RTR_ON_OUTPUT 0x08 +#define RFCOMM_FC_RTC_ON_INPUT 0x10 +#define RFCOMM_FC_RTC_ON_OUTPUT 0x20 +#define RFCOMM_FC_MASK 0x3F + +#define RFCOMM_RPN_PM_BIT_RATE 0x0001 +#define RFCOMM_RPN_PM_DATA_BITS 0x0002 +#define RFCOMM_RPN_PM_STOP_BITS 0x0004 +#define RFCOMM_RPN_PM_PARITY 0x0008 +#define RFCOMM_RPN_PM_PARITY_TYPE 0x0010 +#define RFCOMM_RPN_PM_XON_CHAR 0x0020 +#define RFCOMM_RPN_PM_XOFF_CHAR 0x0040 +#define RFCOMM_RPN_PM_XONXOFF_ON_INPUT 0x0100 +#define RFCOMM_RPN_PM_XONXOFF_ON_OUTPUT 0x0200 +#define RFCOMM_RPN_PM_RTR_ON_INPUT 0x0400 +#define RFCOMM_RPN_PM_RTR_ON_OUTPUT 0x0800 +#define RFCOMM_RPN_PM_RTC_ON_INPUT 0x1000 +#define RFCOMM_RPN_PM_RTC_ON_OUTPUT 0x2000 +#define RFCOMM_RPN_PM_MASK 0x3F7F + +#define RFCOMM_RLS_ERROR 0x01 +#define RFCOMM_RLS_OVERRUN 0x02 +#define RFCOMM_RLS_PARITY 0x04 +#define RFCOMM_RLS_FRAMING 0x08 + +/* Multiplexor channel uses DLCI 0 */ +#define RFCOMM_MX_DLCI 0 + +/* +** Define RFCOMM Multiplexer message types +*/ +#define RFCOMM_MX_PN 0x80 +#define RFCOMM_MX_PN_LEN 8 + +#define RFCOMM_MX_CLD 0xC0 +#define RFCOMM_MX_CLD_LEN 0 + +#define RFCOMM_MX_TEST 0x20 + +#define RFCOMM_MX_FCON 0xA0 +#define RFCOMM_MX_FCON_LEN 0 + +#define RFCOMM_MX_FCOFF 0x60 +#define RFCOMM_MX_FCOFF_LEN 0 + +#define RFCOMM_MX_MSC 0xE0 +#define RFCOMM_MX_MSC_LEN_NO_BREAK 2 +#define RFCOMM_MX_MSC_LEN_WITH_BREAK 3 + +#define RFCOMM_MX_NSC 0x10 +#define RFCOMM_MX_NSC_LEN 1 + +#define RFCOMM_MX_RPN 0x90 +#define RFCOMM_MX_RPN_REQ_LEN 1 +#define RFCOMM_MX_RPN_LEN 8 + +#define RFCOMM_MX_RLS 0x50 +#define RFCOMM_MX_RLS_LEN 2 +#endif diff --git a/components/bt/bluedroid/stack/include/sdp_api.h b/components/bt/bluedroid/stack/include/sdp_api.h new file mode 100755 index 0000000000..ff44bf5f6b --- /dev/null +++ b/components/bt/bluedroid/stack/include/sdp_api.h @@ -0,0 +1,736 @@ +/****************************************************************************** + * + * Copyright (C) 1999-2012 Broadcom Corporation + * + * 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. + * + ******************************************************************************/ +#ifndef SDP_API_H +#define SDP_API_H + +#include "bt_target.h" +#include "sdpdefs.h" + +/***************************************************************************** +** Constants +*****************************************************************************/ + +/* Success code and error codes */ +#define SDP_SUCCESS 0x0000 +#define SDP_INVALID_VERSION 0x0001 +#define SDP_INVALID_SERV_REC_HDL 0x0002 +#define SDP_INVALID_REQ_SYNTAX 0x0003 +#define SDP_INVALID_PDU_SIZE 0x0004 +#define SDP_INVALID_CONT_STATE 0x0005 +#define SDP_NO_RESOURCES 0x0006 +#define SDP_DI_REG_FAILED 0x0007 +#define SDP_DI_DISC_FAILED 0x0008 +#define SDP_NO_DI_RECORD_FOUND 0x0009 +#define SDP_ERR_ATTR_NOT_PRESENT 0x000A +#define SDP_ILLEGAL_PARAMETER 0x000B + +#define SDP_NO_RECS_MATCH 0xFFF0 +#define SDP_CONN_FAILED 0xFFF1 +#define SDP_CFG_FAILED 0xFFF2 +#define SDP_GENERIC_ERROR 0xFFF3 +#define SDP_DB_FULL 0xFFF4 +#define SDP_INVALID_PDU 0xFFF5 +#define SDP_SECURITY_ERR 0xFFF6 +#define SDP_CONN_REJECTED 0xFFF7 +#define SDP_CANCEL 0xFFF8 + +/* Define the PSM that SDP uses */ +#define SDP_PSM 0x0001 + +/* Legacy #define to avoid code changes - SDP UUID is same as BT UUID */ +#define tSDP_UUID tBT_UUID + +/* Masks for attr_value field of tSDP_DISC_ATTR */ +#define SDP_DISC_ATTR_LEN_MASK 0x0FFF +#define SDP_DISC_ATTR_TYPE(len_type) (len_type >> 12) +#define SDP_DISC_ATTR_LEN(len_type) (len_type & SDP_DISC_ATTR_LEN_MASK) + +/* Maximum number of protocol list items (list_elem in tSDP_PROTOCOL_ELEM) */ +#define SDP_MAX_LIST_ELEMS 3 + + +/***************************************************************************** +** Type Definitions +*****************************************************************************/ + +/* Define a callback function for when discovery is complete. */ +typedef void (tSDP_DISC_CMPL_CB) (UINT16 result); +typedef void (tSDP_DISC_CMPL_CB2) (UINT16 result, void* user_data); + +typedef struct +{ + BD_ADDR peer_addr; + UINT16 peer_mtu; +} tSDP_DR_OPEN; + +typedef struct +{ + UINT8 *p_data; + UINT16 data_len; +} tSDP_DR_DATA; + +typedef union +{ + tSDP_DR_OPEN open; + tSDP_DR_DATA data; +} tSDP_DATA; + +/* Define a callback function for when discovery result is received. */ +typedef void (tSDP_DISC_RES_CB) (UINT16 event, tSDP_DATA *p_data); + +/* Define a structure to hold the discovered service information. */ +typedef struct +{ + union + { + UINT8 u8; /* 8-bit integer */ + UINT16 u16; /* 16-bit integer */ + UINT32 u32; /* 32-bit integer */ + UINT8 array[4]; /* Variable length field */ + struct t_sdp_disc_attr *p_sub_attr; /* Addr of first sub-attr (list)*/ + } v; + +} tSDP_DISC_ATVAL; + +typedef struct t_sdp_disc_attr +{ + struct t_sdp_disc_attr *p_next_attr; /* Addr of next linked attr */ + UINT16 attr_id; /* Attribute ID */ + UINT16 attr_len_type; /* Length and type fields */ + tSDP_DISC_ATVAL attr_value; /* Variable length entry data */ +} tSDP_DISC_ATTR; + +typedef struct t_sdp_disc_rec +{ + tSDP_DISC_ATTR *p_first_attr; /* First attribute of record */ + struct t_sdp_disc_rec *p_next_rec; /* Addr of next linked record */ + UINT32 time_read; /* The time the record was read */ + BD_ADDR remote_bd_addr; /* Remote BD address */ +} tSDP_DISC_REC; + +typedef struct +{ + UINT32 mem_size; /* Memory size of the DB */ + UINT32 mem_free; /* Memory still available */ + tSDP_DISC_REC *p_first_rec; /* Addr of first record in DB */ + UINT16 num_uuid_filters; /* Number of UUIds to filter */ + tSDP_UUID uuid_filters[SDP_MAX_UUID_FILTERS]; /* UUIDs to filter */ + UINT16 num_attr_filters; /* Number of attribute filters */ + UINT16 attr_filters[SDP_MAX_ATTR_FILTERS]; /* Attributes to filter */ + UINT8 *p_free_mem; /* Pointer to free memory */ +#if (SDP_RAW_DATA_INCLUDED == TRUE) + UINT8 *raw_data; /* Received record from server. allocated/released by client */ + UINT32 raw_size; /* size of raw_data */ + UINT32 raw_used; /* length of raw_data used */ +#endif +}tSDP_DISCOVERY_DB; + +/* This structure is used to add protocol lists and find protocol elements */ +typedef struct +{ + UINT16 protocol_uuid; + UINT16 num_params; + UINT16 params[SDP_MAX_PROTOCOL_PARAMS]; +} tSDP_PROTOCOL_ELEM; + +typedef struct +{ + UINT16 num_elems; + tSDP_PROTOCOL_ELEM list_elem[SDP_MAX_LIST_ELEMS]; +} tSDP_PROTO_LIST_ELEM; + +/* Device Identification (DI) data structure +*/ +/* Used to set the DI record */ +typedef struct t_sdp_di_record +{ + UINT16 vendor; + UINT16 vendor_id_source; + UINT16 product; + UINT16 version; + BOOLEAN primary_record; + char client_executable_url[SDP_MAX_ATTR_LEN]; /* optional */ + char service_description[SDP_MAX_ATTR_LEN]; /* optional */ + char documentation_url[SDP_MAX_ATTR_LEN]; /* optional */ +}tSDP_DI_RECORD; + +/* Used to get the DI record */ +typedef struct t_sdp_di_get_record +{ + UINT16 spec_id; + tSDP_DI_RECORD rec; +}tSDP_DI_GET_RECORD; + + +/***************************************************************************** +** External Function Declarations +*****************************************************************************/ +#ifdef __cplusplus +extern "C" +{ +#endif + +/* API into the SDP layer for service discovery. */ + +/******************************************************************************* +** +** Function SDP_InitDiscoveryDb +** +** Description This function is called to initialize a discovery database. +** +** Returns TRUE if successful, FALSE if one or more parameters are bad +** +*******************************************************************************/ +extern BOOLEAN SDP_InitDiscoveryDb (tSDP_DISCOVERY_DB *p_db, UINT32 len, + UINT16 num_uuid, + tSDP_UUID *p_uuid_list, + UINT16 num_attr, + UINT16 *p_attr_list); + +/******************************************************************************* +** +** Function SDP_CancelServiceSearch +** +** Description This function cancels an active query to an SDP server. +** +** Returns TRUE if discovery cancelled, FALSE if a matching activity is not found. +** +*******************************************************************************/ +extern BOOLEAN SDP_CancelServiceSearch (tSDP_DISCOVERY_DB *p_db); + +/******************************************************************************* +** +** Function SDP_ServiceSearchRequest +** +** Description This function queries an SDP server for information. +** +** Returns TRUE if discovery started, FALSE if failed. +** +*******************************************************************************/ +extern BOOLEAN SDP_ServiceSearchRequest (UINT8 *p_bd_addr, + tSDP_DISCOVERY_DB *p_db, + tSDP_DISC_CMPL_CB *p_cb); + + +/******************************************************************************* +** +** Function SDP_ServiceSearchAttributeRequest +** +** Description This function queries an SDP server for information. +** +** The difference between this API function and the function +** SDP_ServiceSearchRequest is that this one does a +** combined ServiceSearchAttributeRequest SDP function. +** +** Returns TRUE if discovery started, FALSE if failed. +** +*******************************************************************************/ +extern BOOLEAN SDP_ServiceSearchAttributeRequest (UINT8 *p_bd_addr, + tSDP_DISCOVERY_DB *p_db, + tSDP_DISC_CMPL_CB *p_cb); + +/******************************************************************************* +** +** Function SDP_ServiceSearchAttributeRequest2 +** +** Description This function queries an SDP server for information. +** +** The difference between this API function and the function +** SDP_ServiceSearchRequest is that this one does a +** combined ServiceSearchAttributeRequest SDP function with the +** user data piggyback +** +** Returns TRUE if discovery started, FALSE if failed. +** +*******************************************************************************/ +extern BOOLEAN SDP_ServiceSearchAttributeRequest2 (UINT8 *p_bd_addr, + tSDP_DISCOVERY_DB *p_db, + tSDP_DISC_CMPL_CB2 *p_cb, void * user_data); + +/* API of utilities to find data in the local discovery database */ + +/******************************************************************************* +** +** Function SDP_FindAttributeInDb +** +** Description This function queries an SDP database for a specific attribute. +** If the p_start_rec pointer is NULL, it looks from the beginning +** of the database, else it continues from the next record after +** p_start_rec. +** +** Returns Pointer to matching record, or NULL +** +*******************************************************************************/ +extern tSDP_DISC_REC *SDP_FindAttributeInDb (tSDP_DISCOVERY_DB *p_db, + UINT16 attr_id, + tSDP_DISC_REC *p_start_rec); + + +/******************************************************************************* +** +** Function SDP_FindAttributeInRec +** +** Description This function searches an SDP discovery record for a +** specific attribute. +** +** Returns Pointer to matching attribute entry, or NULL +** +*******************************************************************************/ +extern tSDP_DISC_ATTR *SDP_FindAttributeInRec (tSDP_DISC_REC *p_rec, + UINT16 attr_id); + + +/******************************************************************************* +** +** Function SDP_FindServiceInDb +** +** Description This function queries an SDP database for a specific service. +** If the p_start_rec pointer is NULL, it looks from the beginning +** of the database, else it continues from the next record after +** p_start_rec. +** +** Returns Pointer to record containing service class, or NULL +** +*******************************************************************************/ +extern tSDP_DISC_REC *SDP_FindServiceInDb (tSDP_DISCOVERY_DB *p_db, + UINT16 service_uuid, + tSDP_DISC_REC *p_start_rec); + + +/******************************************************************************* +** +** Function SDP_FindServiceUUIDInDb +** +** Description This function queries an SDP database for a specific service. +** If the p_start_rec pointer is NULL, it looks from the beginning +** of the database, else it continues from the next record after +** p_start_rec. +** +** NOTE the only difference between this function and the previous +** function "SDP_FindServiceInDb()" is that this function takes +** a tBT_UUID input. +** +** Returns Pointer to record containing service class, or NULL +** +*******************************************************************************/ +extern tSDP_DISC_REC *SDP_FindServiceUUIDInDb (tSDP_DISCOVERY_DB *p_db, + tBT_UUID *p_uuid, + tSDP_DISC_REC *p_start_rec); + +/******************************************************************************* +** +** Function SDP_FindServiceUUIDInRec_128bit +** +** Description This function is called to read the 128-bit service UUID within a record +** if there is any. +** +** Parameters: p_rec - pointer to a SDP record. +** p_uuid - output parameter to save the UUID found. +** +** Returns TRUE if found, otherwise FALSE. +** +*******************************************************************************/ +extern BOOLEAN SDP_FindServiceUUIDInRec_128bit(tSDP_DISC_REC *p_rec, tBT_UUID * p_uuid); + +/******************************************************************************* +** +** Function SDP_FindServiceInDb_128bit +** +** Description This function queries an SDP database for a specific service. +** If the p_start_rec pointer is NULL, it looks from the beginning +** of the database, else it continues from the next record after +** p_start_rec. +** +** Returns Pointer to record containing service class, or NULL +** +*******************************************************************************/ +extern tSDP_DISC_REC *SDP_FindServiceInDb_128bit(tSDP_DISCOVERY_DB *p_db, + tSDP_DISC_REC *p_start_rec); + +/******************************************************************************* +** +** Function SDP_FindProtocolListElemInRec +** +** Description This function looks at a specific discovery record for a +** protocol list element. +** +** Returns TRUE if found, FALSE if not +** If found, the passed protocol list element is filled in. +** +*******************************************************************************/ +extern BOOLEAN SDP_FindProtocolListElemInRec (tSDP_DISC_REC *p_rec, + UINT16 layer_uuid, + tSDP_PROTOCOL_ELEM *p_elem); + + +/******************************************************************************* +** +** Function SDP_FindAddProtoListsElemInRec +** +** Description This function looks at a specific discovery record for a +** protocol list element. +** +** Returns TRUE if found, FALSE if not +** If found, the passed protocol list element is filled in. +** +*******************************************************************************/ +extern BOOLEAN SDP_FindAddProtoListsElemInRec (tSDP_DISC_REC *p_rec, + UINT16 layer_uuid, + tSDP_PROTOCOL_ELEM *p_elem); + + +/******************************************************************************* +** +** Function SDP_FindProfileVersionInRec +** +** Description This function looks at a specific discovery record for the +** Profile list descriptor, and pulls out the version number. +** The version number consists of an 8-bit major version and +** an 8-bit minor version. +** +** Returns TRUE if found, FALSE if not +** If found, the major and minor version numbers that were passed +** in are filled in. +** +*******************************************************************************/ +extern BOOLEAN SDP_FindProfileVersionInRec (tSDP_DISC_REC *p_rec, + UINT16 profile_uuid, + UINT16 *p_version); + + +/* API into SDP for local service database updates */ + +/******************************************************************************* +** +** Function SDP_CreateRecord +** +** Description This function is called to create a record in the database. +** This would be through the SDP database maintenance API. The +** record is created empty, teh application should then call +** "add_attribute" to add the record's attributes. +** +** Returns Record handle if OK, else 0. +** +*******************************************************************************/ +extern UINT32 SDP_CreateRecord (void); + + +/******************************************************************************* +** +** Function SDP_DeleteRecord +** +** Description This function is called to add a record (or all records) +** from the database. This would be through the SDP database +** maintenance API. +** +** If a record handle of 0 is passed, all records are deleted. +** +** Returns TRUE if succeeded, else FALSE +** +*******************************************************************************/ +extern BOOLEAN SDP_DeleteRecord (UINT32 handle); + + +/******************************************************************************* +** +** Function SDP_ReadRecord +** +** Description This function is called to get the raw data of the record +** with the given handle from the database. +** +** Returns -1, if the record is not found. +** Otherwise, the offset (0 or 1) to start of data in p_data. +** +** The size of data copied into p_data is in *p_data_len. +** +*******************************************************************************/ +extern INT32 SDP_ReadRecord(UINT32 handle, UINT8 *p_data, INT32 *p_data_len); + +/******************************************************************************* +** +** Function SDP_AddAttribute +** +** Description This function is called to add an attribute to a record. +** This would be through the SDP database maintenance API. +** If the attribute already exists in the record, it is replaced +** with the new value. +** +** NOTE Attribute values must be passed as a Big Endian stream. +** +** Returns TRUE if added OK, else FALSE +** +*******************************************************************************/ +extern BOOLEAN SDP_AddAttribute (UINT32 handle, UINT16 attr_id, + UINT8 attr_type, UINT32 attr_len, + UINT8 *p_val); + + +/******************************************************************************* +** +** Function SDP_AddSequence +** +** Description This function is called to add a sequence to a record. +** This would be through the SDP database maintenance API. +** If the sequence already exists in the record, it is replaced +** with the new sequence. +** +** NOTE Element values must be passed as a Big Endian stream. +** +** Returns TRUE if added OK, else FALSE +** +*******************************************************************************/ +extern BOOLEAN SDP_AddSequence (UINT32 handle, UINT16 attr_id, + UINT16 num_elem, UINT8 type[], + UINT8 len[], UINT8 *p_val[]); + + +/******************************************************************************* +** +** Function SDP_AddUuidSequence +** +** Description This function is called to add a UUID sequence to a record. +** This would be through the SDP database maintenance API. +** If the sequence already exists in the record, it is replaced +** with the new sequence. +** +** Returns TRUE if added OK, else FALSE +** +*******************************************************************************/ +extern BOOLEAN SDP_AddUuidSequence (UINT32 handle, UINT16 attr_id, + UINT16 num_uuids, UINT16 *p_uuids); + + +/******************************************************************************* +** +** Function SDP_AddProtocolList +** +** Description This function is called to add a protocol descriptor list to +** a record. This would be through the SDP database maintenance API. +** If the protocol list already exists in the record, it is replaced +** with the new list. +** +** Returns TRUE if added OK, else FALSE +** +*******************************************************************************/ +extern BOOLEAN SDP_AddProtocolList (UINT32 handle, UINT16 num_elem, + tSDP_PROTOCOL_ELEM *p_elem_list); + + +/******************************************************************************* +** +** Function SDP_AddAdditionProtoLists +** +** Description This function is called to add a protocol descriptor list to +** a record. This would be through the SDP database maintenance API. +** If the protocol list already exists in the record, it is replaced +** with the new list. +** +** Returns TRUE if added OK, else FALSE +** +*******************************************************************************/ +extern BOOLEAN SDP_AddAdditionProtoLists (UINT32 handle, UINT16 num_elem, + tSDP_PROTO_LIST_ELEM *p_proto_list); + + +/******************************************************************************* +** +** Function SDP_AddProfileDescriptorList +** +** Description This function is called to add a profile descriptor list to +** a record. This would be through the SDP database maintenance API. +** If the version already exists in the record, it is replaced +** with the new one. +** +** Returns TRUE if added OK, else FALSE +** +*******************************************************************************/ +extern BOOLEAN SDP_AddProfileDescriptorList (UINT32 handle, + UINT16 profile_uuid, + UINT16 version); + + +/******************************************************************************* +** +** Function SDP_AddLanguageBaseAttrIDList +** +** Description This function is called to add a language base attr list to +** a record. This would be through the SDP database maintenance API. +** If the version already exists in the record, it is replaced +** with the new one. +** +** Returns TRUE if added OK, else FALSE +** +*******************************************************************************/ +extern BOOLEAN SDP_AddLanguageBaseAttrIDList (UINT32 handle, + UINT16 lang, UINT16 char_enc, + UINT16 base_id); + + +/******************************************************************************* +** +** Function SDP_AddServiceClassIdList +** +** Description This function is called to add a service list to a record. +** This would be through the SDP database maintenance API. +** If the service list already exists in the record, it is replaced +** with the new list. +** +** Returns TRUE if added OK, else FALSE +** +*******************************************************************************/ +extern BOOLEAN SDP_AddServiceClassIdList (UINT32 handle, + UINT16 num_services, + UINT16 *p_service_uuids); + + +/******************************************************************************* +** +** Function SDP_DeleteAttribute +** +** Description This function is called to delete an attribute from a record. +** This would be through the SDP database maintenance API. +** +** Returns TRUE if deleted OK, else FALSE if not found +** +*******************************************************************************/ +extern BOOLEAN SDP_DeleteAttribute (UINT32 handle, UINT16 attr_id); + + +/* Device Identification APIs */ + +/******************************************************************************* +** +** Function SDP_SetLocalDiRecord +** +** Description This function adds a DI record to the local SDP database. +** +** Returns Returns SDP_SUCCESS if record added successfully, else error +** +*******************************************************************************/ +extern UINT16 SDP_SetLocalDiRecord (tSDP_DI_RECORD *device_info, + UINT32 *p_handle); + +/******************************************************************************* +** +** Function SDP_DiDiscover +** +** Description This function queries a remote device for DI information. +** +** Returns SDP_SUCCESS if query started successfully, else error +** +*******************************************************************************/ +extern UINT16 SDP_DiDiscover (BD_ADDR remote_device, + tSDP_DISCOVERY_DB *p_db, UINT32 len, + tSDP_DISC_CMPL_CB *p_cb); + + +/******************************************************************************* +** +** Function SDP_GetNumDiRecords +** +** Description Searches specified database for DI records +** +** Returns number of DI records found +** +*******************************************************************************/ +extern UINT8 SDP_GetNumDiRecords (tSDP_DISCOVERY_DB *p_db); + + +/******************************************************************************* +** +** Function SDP_GetDiRecord +** +** Description This function retrieves a remote device's DI record from +** the specified database. +** +** Returns SDP_SUCCESS if record retrieved, else error +** +*******************************************************************************/ +extern UINT16 SDP_GetDiRecord (UINT8 getRecordIndex, + tSDP_DI_GET_RECORD *device_info, + tSDP_DISCOVERY_DB *p_db); + + +/******************************************************************************* +** +** Function SDP_SetTraceLevel +** +** Description This function sets the trace level for SDP. If called with +** a value of 0xFF, it simply reads the current trace level. +** +** Returns the new (current) trace level +** +*******************************************************************************/ +extern UINT8 SDP_SetTraceLevel (UINT8 new_level); + +/******************************************************************************* +** +** Function SDP_ConnOpen +** +** Description This function creates a connection to the SDP server on the +** given device. +** +** Returns 0, if failed to initiate connection. Otherwise, the handle. +** +*******************************************************************************/ +UINT32 SDP_ConnOpen (UINT8 *p_bd_addr, tSDP_DISC_RES_CB *p_rcb, + tSDP_DISC_CMPL_CB *p_cb); + +/******************************************************************************* +** +** Function SDP_WriteData +** +** Description This function sends data to the connected SDP server. +** +** Returns TRUE if data is sent, FALSE if failed. +** +*******************************************************************************/ +BOOLEAN SDP_WriteData (UINT32 handle, BT_HDR *p_msg); + +/******************************************************************************* +** +** Function SDP_ConnClose +** +** Description This function is called to close a SDP connection. +** +** Parameters: handle - Handle of the connection returned by SDP_ConnOpen +** +** Returns TRUE if connection is closed, FALSE if failed to find the handle. +** +*******************************************************************************/ +BOOLEAN SDP_ConnClose (UINT32 handle); + +/******************************************************************************* +** +** Function SDP_FindServiceUUIDInRec +** +** Description This function is called to read the service UUID within a record +** if there is any. +** +** Parameters: p_rec - pointer to a SDP record. +** +** Returns TRUE if found, otherwise FALSE. +** +*******************************************************************************/ +BOOLEAN SDP_FindServiceUUIDInRec(tSDP_DISC_REC *p_rec, tBT_UUID *p_uuid); + +#ifdef __cplusplus +} +#endif + +#endif /* SDP_API_H */ diff --git a/components/bt/bluedroid/stack/include/sdpdefs.h b/components/bt/bluedroid/stack/include/sdpdefs.h new file mode 100755 index 0000000000..44d87e74bc --- /dev/null +++ b/components/bt/bluedroid/stack/include/sdpdefs.h @@ -0,0 +1,327 @@ +/****************************************************************************** + * + * Copyright (C) 1999-2012 Broadcom Corporation + * + * 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 definitions for the SDP API + * + ******************************************************************************/ + +#ifndef SDP_DEFS_H +#define SDP_DEFS_H + +/* Define the service attribute IDs. +*/ +#define ATTR_ID_SERVICE_RECORD_HDL 0x0000 +#define ATTR_ID_SERVICE_CLASS_ID_LIST 0x0001 +#define ATTR_ID_SERVICE_RECORD_STATE 0x0002 +#define ATTR_ID_SERVICE_ID 0x0003 +#define ATTR_ID_PROTOCOL_DESC_LIST 0x0004 +#define ATTR_ID_BROWSE_GROUP_LIST 0x0005 +#define ATTR_ID_LANGUAGE_BASE_ATTR_ID_LIST 0x0006 +#define ATTR_ID_SERVICE_INFO_TIME_TO_LIVE 0x0007 +#define ATTR_ID_SERVICE_AVAILABILITY 0x0008 +#define ATTR_ID_BT_PROFILE_DESC_LIST 0x0009 +#define ATTR_ID_DOCUMENTATION_URL 0x000A +#define ATTR_ID_CLIENT_EXE_URL 0x000B +#define ATTR_ID_ICON_URL 0x000C +#define ATTR_ID_ADDITION_PROTO_DESC_LISTS 0x000D + +#define LANGUAGE_BASE_ID 0x0100 +#define ATTR_ID_SERVICE_NAME LANGUAGE_BASE_ID + 0x0000 +#define ATTR_ID_SERVICE_DESCRIPTION LANGUAGE_BASE_ID + 0x0001 +#define ATTR_ID_PROVIDER_NAME LANGUAGE_BASE_ID + 0x0002 + +/* Device Identification (DI) +*/ +#define ATTR_ID_SPECIFICATION_ID 0x0200 +#define ATTR_ID_VENDOR_ID 0x0201 +#define ATTR_ID_PRODUCT_ID 0x0202 +#define ATTR_ID_PRODUCT_VERSION 0x0203 +#define ATTR_ID_PRIMARY_RECORD 0x0204 +#define ATTR_ID_VENDOR_ID_SOURCE 0x0205 + +#define BLUETOOTH_DI_SPECIFICATION 0x0103 /* 1.3 */ +#define DI_VENDOR_ID_DEFAULT 0xFFFF +#define DI_VENDOR_ID_SOURCE_BTSIG 0x0001 +#define DI_VENDOR_ID_SOURCE_USBIF 0x0002 + + +#define ATTR_ID_IP_SUBNET 0x0200 /* PAN Profile (***) */ +#define ATTR_ID_VERSION_NUMBER_LIST 0x0200 +#define ATTR_ID_GOEP_L2CAP_PSM 0x0200 +#define ATTR_ID_GROUP_ID 0x0200 +#define ATTR_ID_SERVICE_DATABASE_STATE 0x0201 +#define ATTR_ID_SERVICE_VERSION 0x0300 +#define ATTR_ID_HCRP_1284ID 0x0300 + +#define ATTR_ID_SUPPORTED_DATA_STORES 0x0301 +#define ATTR_ID_NETWORK 0x0301 +#define ATTR_ID_EXTERNAL_NETWORK 0x0301 +#define ATTR_ID_FAX_CLASS_1_SUPPORT 0x0302 +#define ATTR_ID_REMOTE_AUDIO_VOLUME_CONTROL 0x0302 +#define ATTR_ID_DEVICE_NAME 0x0302 +#define ATTR_ID_SUPPORTED_FORMATS_LIST 0x0303 +#define ATTR_ID_FAX_CLASS_2_0_SUPPORT 0x0303 +#define ATTR_ID_FAX_CLASS_2_SUPPORT 0x0304 +#define ATTR_ID_FRIENDLY_NAME 0x0304 +#define ATTR_ID_AUDIO_FEEDBACK_SUPPORT 0x0305 +#define ATTR_ID_NETWORK_ADDRESS 0x0306 +#define ATTR_ID_DEVICE_LOCATION 0x0306 +#define ATTR_ID_WAP_GATEWAY 0x0307 +#define ATTR_ID_HOME_PAGE_URL 0x0308 +#define ATTR_ID_WAP_STACK_TYPE 0x0309 +#define ATTR_ID_IMG_SUPPORTED_CAPABILITIES 0x0310 /* Imaging Profile */ +#define ATTR_ID_SUPPORTED_FEATURES 0x0311 /* HFP, BIP */ +#define ATTR_ID_IMG_SUPPORTED_FUNCTIONS 0x0312 /* Imaging Profile */ +#define ATTR_ID_IMG_TOT_DATA_CAPABILITY 0x0313 /* Imaging Profile */ +#define ATTR_ID_SUPPORTED_REPOSITORIES 0x0314 /* Phone book access Profile */ +#define ATTR_ID_MAS_INSTANCE_ID 0x0315 /* MAP profile */ +#define ATTR_ID_SUPPORTED_MSG_TYPE 0x0316 /* MAP profile */ +#define ATTR_ID_MAP_SUPPORTED_FEATURES 0x0317 /* MAP profile */ +#define ATTR_ID_PBAP_SUPPORTED_FEATURES 0x0317 /* PBAP profile */ + + +/* These values are for the BPP profile */ +#define ATTR_ID_DOCUMENT_FORMATS_SUPPORTED 0x0350 +#define ATTR_ID_CHARACTER_REPERTOIRES_SUPPORTED 0x0352 +#define ATTR_ID_XHTML_IMAGE_FORMATS_SUPPORTED 0x0354 +#define ATTR_ID_COLOR_SUPPORTED 0x0356 +#define ATTR_ID_1284ID 0x0358 +#define ATTR_ID_PRINTER_NAME 0x035A +#define ATTR_ID_PRINTER_LOCATION 0x035C +#define ATTR_ID_DUPLEX_SUPPORTED 0x035E +#define ATTR_ID_MEDIA_TYPES_SUPPORTED 0x0360 +#define ATTR_ID_MAX_MEDIA_WIDTH 0x0362 +#define ATTR_ID_MAX_MEDIA_LENGTH 0x0364 +#define ATTR_ID_ENHANCED_LAYOUT_SUPPORTED 0x0366 +#define ATTR_ID_RUI_FORMATS_SUPPORTED 0x0368 +#define ATTR_ID_RUI_REF_PRINTING_SUPPORTED 0x0370 /* Boolean */ +#define ATTR_ID_RUI_DIRECT_PRINTING_SUPPORTED 0x0372 /* Boolean */ +#define ATTR_ID_REF_PRINTING_TOP_URL 0x0374 +#define ATTR_ID_DIRECT_PRINTING_TOP_URL 0x0376 +#define ATTR_ID_PRINTER_ADMIN_RUI_TOP_URL 0x0378 +#define ATTR_ID_BPP_DEVICE_NAME 0x037A + +/* These values are for the PAN profile */ +#define ATTR_ID_SECURITY_DESCRIPTION 0x030A +#define ATTR_ID_NET_ACCESS_TYPE 0x030B +#define ATTR_ID_MAX_NET_ACCESS_RATE 0x030C +#define ATTR_ID_IPV4_SUBNET 0x030D +#define ATTR_ID_IPV6_SUBNET 0x030E +#define ATTR_ID_PAN_SECURITY 0x0400 + +/* These values are for HID profile */ +#define ATTR_ID_HID_DEVICE_RELNUM 0x0200 +#define ATTR_ID_HID_PARSER_VERSION 0x0201 +#define ATTR_ID_HID_DEVICE_SUBCLASS 0x0202 +#define ATTR_ID_HID_COUNTRY_CODE 0x0203 +#define ATTR_ID_HID_VIRTUAL_CABLE 0x0204 +#define ATTR_ID_HID_RECONNECT_INITIATE 0x0205 +#define ATTR_ID_HID_DESCRIPTOR_LIST 0x0206 +#define ATTR_ID_HID_LANGUAGE_ID_BASE 0x0207 +#define ATTR_ID_HID_SDP_DISABLE 0x0208 +#define ATTR_ID_HID_BATTERY_POWER 0x0209 +#define ATTR_ID_HID_REMOTE_WAKE 0x020A +#define ATTR_ID_HID_PROFILE_VERSION 0x020B +#define ATTR_ID_HID_LINK_SUPERVISION_TO 0x020C +#define ATTR_ID_HID_NORMALLY_CONNECTABLE 0x020D +#define ATTR_ID_HID_BOOT_DEVICE 0x020E +#define ATTR_ID_HID_SSR_HOST_MAX_LAT 0x020F +#define ATTR_ID_HID_SSR_HOST_MIN_TOUT 0x0210 + +/* These values are for the HDP profile */ +#define ATTR_ID_HDP_SUP_FEAT_LIST 0x0200 /* Supported features list */ +#define ATTR_ID_HDP_DATA_EXCH_SPEC 0x0301 /* Data exchange specification */ +#define ATTR_ID_HDP_MCAP_SUP_PROC 0x0302 /* MCAP supported procedures */ + +/* Define common 16-bit protocol UUIDs +*/ +#define UUID_PROTOCOL_SDP 0x0001 +#define UUID_PROTOCOL_UDP 0x0002 +#define UUID_PROTOCOL_RFCOMM 0x0003 +#define UUID_PROTOCOL_TCP 0x0004 +#define UUID_PROTOCOL_TCS_BIN 0x0005 +#define UUID_PROTOCOL_TCS_AT 0x0006 +#define UUID_PROTOCOL_OBEX 0x0008 +#define UUID_PROTOCOL_IP 0x0009 +#define UUID_PROTOCOL_FTP 0x000A +#define UUID_PROTOCOL_HTTP 0x000C +#define UUID_PROTOCOL_WSP 0x000E +#define UUID_PROTOCOL_BNEP 0x000F +#define UUID_PROTOCOL_UPNP 0x0010 +#define UUID_PROTOCOL_HIDP 0x0011 +#define UUID_PROTOCOL_HCRP_CTRL 0x0012 +#define UUID_PROTOCOL_HCRP_DATA 0x0014 +#define UUID_PROTOCOL_HCRP_NOTIF 0x0016 +#define UUID_PROTOCOL_AVCTP 0x0017 +#define UUID_PROTOCOL_AVDTP 0x0019 +#define UUID_PROTOCOL_CMTP 0x001B +#define UUID_PROTOCOL_UDI 0x001D +#define UUID_PROTOCOL_MCAP_CTRL 0x001E +#define UUID_PROTOCOL_MCAP_DATA 0x001F +#define UUID_PROTOCOL_L2CAP 0x0100 +#define UUID_PROTOCOL_ATT 0x0007 + +/* Define common 16-bit service class UUIDs +*/ +#define UUID_SERVCLASS_SERVICE_DISCOVERY_SERVER 0X1000 +#define UUID_SERVCLASS_BROWSE_GROUP_DESCRIPTOR 0X1001 +#define UUID_SERVCLASS_PUBLIC_BROWSE_GROUP 0X1002 +#define UUID_SERVCLASS_SERIAL_PORT 0X1101 +#define UUID_SERVCLASS_LAN_ACCESS_USING_PPP 0X1102 +#define UUID_SERVCLASS_DIALUP_NETWORKING 0X1103 +#define UUID_SERVCLASS_IRMC_SYNC 0X1104 +#define UUID_SERVCLASS_OBEX_OBJECT_PUSH 0X1105 +#define UUID_SERVCLASS_OBEX_FILE_TRANSFER 0X1106 +#define UUID_SERVCLASS_IRMC_SYNC_COMMAND 0X1107 +#define UUID_SERVCLASS_HEADSET 0X1108 +#define UUID_SERVCLASS_CORDLESS_TELEPHONY 0X1109 +#define UUID_SERVCLASS_AUDIO_SOURCE 0X110A +#define UUID_SERVCLASS_AUDIO_SINK 0X110B +#define UUID_SERVCLASS_AV_REM_CTRL_TARGET 0X110C /* Audio/Video Control profile */ +#define UUID_SERVCLASS_ADV_AUDIO_DISTRIBUTION 0X110D /* Advanced Audio Distribution profile */ +#define UUID_SERVCLASS_AV_REMOTE_CONTROL 0X110E /* Audio/Video Control profile */ +#define UUID_SERVCLASS_AV_REM_CTRL_CONTROL 0X110F /* Audio/Video Control profile */ +#define UUID_SERVCLASS_INTERCOM 0X1110 +#define UUID_SERVCLASS_FAX 0X1111 +#define UUID_SERVCLASS_HEADSET_AUDIO_GATEWAY 0X1112 +#define UUID_SERVCLASS_WAP 0X1113 +#define UUID_SERVCLASS_WAP_CLIENT 0X1114 +#define UUID_SERVCLASS_PANU 0X1115 /* PAN profile */ +#define UUID_SERVCLASS_NAP 0X1116 /* PAN profile */ +#define UUID_SERVCLASS_GN 0X1117 /* PAN profile */ +#define UUID_SERVCLASS_DIRECT_PRINTING 0X1118 /* BPP profile */ +#define UUID_SERVCLASS_REFERENCE_PRINTING 0X1119 /* BPP profile */ +#define UUID_SERVCLASS_IMAGING 0X111A /* Imaging profile */ +#define UUID_SERVCLASS_IMAGING_RESPONDER 0X111B /* Imaging profile */ +#define UUID_SERVCLASS_IMAGING_AUTO_ARCHIVE 0X111C /* Imaging profile */ +#define UUID_SERVCLASS_IMAGING_REF_OBJECTS 0X111D /* Imaging profile */ +#define UUID_SERVCLASS_HF_HANDSFREE 0X111E /* Handsfree profile */ +#define UUID_SERVCLASS_AG_HANDSFREE 0X111F /* Handsfree profile */ +#define UUID_SERVCLASS_DIR_PRT_REF_OBJ_SERVICE 0X1120 /* BPP profile */ +#define UUID_SERVCLASS_REFLECTED_UI 0X1121 /* BPP profile */ +#define UUID_SERVCLASS_BASIC_PRINTING 0X1122 /* BPP profile */ +#define UUID_SERVCLASS_PRINTING_STATUS 0X1123 /* BPP profile */ +#define UUID_SERVCLASS_HUMAN_INTERFACE 0X1124 /* HID profile */ +#define UUID_SERVCLASS_CABLE_REPLACEMENT 0X1125 /* HCRP profile */ +#define UUID_SERVCLASS_HCRP_PRINT 0X1126 /* HCRP profile */ +#define UUID_SERVCLASS_HCRP_SCAN 0X1127 /* HCRP profile */ +#define UUID_SERVCLASS_COMMON_ISDN_ACCESS 0X1128 /* CAPI Message Transport Protocol*/ +#define UUID_SERVCLASS_VIDEO_CONFERENCING_GW 0X1129 /* Video Conferencing profile */ +#define UUID_SERVCLASS_UDI_MT 0X112A /* Unrestricted Digital Information profile */ +#define UUID_SERVCLASS_UDI_TA 0X112B /* Unrestricted Digital Information profile */ +#define UUID_SERVCLASS_VCP 0X112C /* Video Conferencing profile */ +#define UUID_SERVCLASS_SAP 0X112D /* SIM Access profile */ +#define UUID_SERVCLASS_PBAP_PCE 0X112E /* Phonebook Access - PCE */ +#define UUID_SERVCLASS_PBAP_PSE 0X112F /* Phonebook Access - PSE */ +#define UUID_SERVCLASS_PHONE_ACCESS 0x1130 +#define UUID_SERVCLASS_HEADSET_HS 0x1131 /* Headset - HS, from HSP v1.2 */ +#define UUID_SERVCLASS_PNP_INFORMATION 0X1200 /* Device Identification */ +#define UUID_SERVCLASS_GENERIC_NETWORKING 0X1201 +#define UUID_SERVCLASS_GENERIC_FILETRANSFER 0X1202 +#define UUID_SERVCLASS_GENERIC_AUDIO 0X1203 +#define UUID_SERVCLASS_GENERIC_TELEPHONY 0X1204 +#define UUID_SERVCLASS_UPNP_SERVICE 0X1205 /* UPNP_Service [ESDP] */ +#define UUID_SERVCLASS_UPNP_IP_SERVICE 0X1206 /* UPNP_IP_Service [ESDP] */ +#define UUID_SERVCLASS_ESDP_UPNP_IP_PAN 0X1300 /* UPNP_IP_PAN [ESDP] */ +#define UUID_SERVCLASS_ESDP_UPNP_IP_LAP 0X1301 /* UPNP_IP_LAP [ESDP] */ +#define UUID_SERVCLASS_ESDP_UPNP_IP_L2CAP 0X1302 /* UPNP_L2CAP [ESDP] */ +#define UUID_SERVCLASS_VIDEO_SOURCE 0X1303 /* Video Distribution Profile (VDP) */ +#define UUID_SERVCLASS_VIDEO_SINK 0X1304 /* Video Distribution Profile (VDP) */ +#define UUID_SERVCLASS_VIDEO_DISTRIBUTION 0X1305 /* Video Distribution Profile (VDP) */ +#define UUID_SERVCLASS_HDP_PROFILE 0X1400 /* Health Device profile (HDP) */ +#define UUID_SERVCLASS_HDP_SOURCE 0X1401 /* Health Device profile (HDP) */ +#define UUID_SERVCLASS_HDP_SINK 0X1402 /* Health Device profile (HDP) */ +#define UUID_SERVCLASS_MAP_PROFILE 0X1134 /* MAP profile UUID */ +#define UUID_SERVCLASS_MESSAGE_ACCESS 0X1132 /* Message Access Service UUID */ +#define UUID_SERVCLASS_MESSAGE_NOTIFICATION 0X1133 /* Message Notification Service UUID */ + +#define UUID_SERVCLASS_GAP_SERVER 0x1800 +#define UUID_SERVCLASS_GATT_SERVER 0x1801 +#define UUID_SERVCLASS_IMMEDIATE_ALERT 0x1802 /* immediate alert */ +#define UUID_SERVCLASS_LINKLOSS 0x1803 /* Link Loss Alert */ +#define UUID_SERVCLASS_TX_POWER 0x1804 /* TX power */ +#define UUID_SERVCLASS_CURRENT_TIME 0x1805 /* Link Loss Alert */ +#define UUID_SERVCLASS_DST_CHG 0x1806 /* DST Time change */ +#define UUID_SERVCLASS_REF_TIME_UPD 0x1807 /* reference time update */ +#define UUID_SERVCLASS_THERMOMETER 0x1809 /* Thermometer UUID */ +#define UUID_SERVCLASS_DEVICE_INFO 0x180A /* device info service */ +#define UUID_SERVCLASS_NWA 0x180B /* Network availability */ +#define UUID_SERVCLASS_HEART_RATE 0x180D /* Heart Rate service */ +#define UUID_SERVCLASS_PHALERT 0x180E /* phone alert service */ +#define UUID_SERVCLASS_BATTERY 0x180F /* battery service */ +#define UUID_SERVCLASS_BPM 0x1810 /* blood pressure service */ +#define UUID_SERVCLASS_ALERT_NOTIFICATION 0x1811 /* alert notification service */ +#define UUID_SERVCLASS_LE_HID 0x1812 /* HID over LE */ +#define UUID_SERVCLASS_SCAN_PARAM 0x1813 /* Scan Parameter service */ +#define UUID_SERVCLASS_GLUCOSE 0x1808 /* Glucose Meter Service */ +#define UUID_SERVCLASS_RSC 0x1814 /* RUNNERS SPEED AND CADENCE SERVICE */ +#define UUID_SERVCLASS_CSC 0x1816 /* Cycling SPEED AND CADENCE SERVICE */ + +#define UUID_SERVCLASS_TEST_SERVER 0x9000 /* Test Group UUID */ + +#if (BTM_WBS_INCLUDED == TRUE ) +#define UUID_CODEC_CVSD 0x0001 /* CVSD */ +#define UUID_CODEC_MSBC 0x0002 /* mSBC */ +#endif + +/* Define all the 'Descriptor Type' values. +*/ +#define NULL_DESC_TYPE 0 +#define UINT_DESC_TYPE 1 +#define TWO_COMP_INT_DESC_TYPE 2 +#define UUID_DESC_TYPE 3 +#define TEXT_STR_DESC_TYPE 4 +#define BOOLEAN_DESC_TYPE 5 +#define DATA_ELE_SEQ_DESC_TYPE 6 +#define DATA_ELE_ALT_DESC_TYPE 7 +#define URL_DESC_TYPE 8 + +/* Define all the "Descriptor Size" values. +*/ +#define SIZE_ONE_BYTE 0 +#define SIZE_TWO_BYTES 1 +#define SIZE_FOUR_BYTES 2 +#define SIZE_EIGHT_BYTES 3 +#define SIZE_SIXTEEN_BYTES 4 +#define SIZE_IN_NEXT_BYTE 5 +#define SIZE_IN_NEXT_WORD 6 +#define SIZE_IN_NEXT_LONG 7 + +/* Language Encoding Constants */ +#define LANG_ID_CODE_ENGLISH ((UINT16) 0x656e) /* "en" */ +#define LANG_ID_CHAR_ENCODE_UTF8 ((UINT16) 0x006a) /* UTF-8 */ + +/* Constants used for display purposes only. These define ovelapping attribute values */ +#define ATTR_ID_VERS_OR_GRP_OR_DRELNUM_OR_IPSUB_OR_SPECID 0x0200 +#define ATTR_ID_VEND_ID_OR_SERVICE_DB_STATE_OR_PARSE_VER 0x0201 +#define ATTR_ID_PROD_ID_OR_HID_DEV_SUBCLASS 0x0202 +#define ATTR_ID_PROD_VER_OR_HID_COUNTRY_CODE 0x0203 +#define ATTR_ID_PRIMARY_REC_OR_HID_VIRTUAL_CABLE 0x0204 +#define ATTR_ID_DI_VENDOR_ID_SOURCE_OR_HID_INIT_RECONNECT 0x0205 +#define ATTR_ID_SERV_VERS_OR_1284ID 0x0300 +#define ATTR_ID_DATA_STORES_OR_NETWORK 0x0301 +#define ATTR_ID_FAX_1_OR_AUD_VOL_OR_DEV_NAME 0x0302 +#define ATTR_ID_FORMATS_OR_FAX_2_0 0x0303 +#define ATTR_ID_FAX_CLASS_2_OR_FRIENDLY_NAME 0x0304 +#define ATTR_ID_NETADDRESS_OR_DEVLOCATION 0x0306 + +#endif + + diff --git a/components/bt/bluedroid/stack/include/sdpint.h b/components/bt/bluedroid/stack/include/sdpint.h new file mode 100755 index 0000000000..834266edc1 --- /dev/null +++ b/components/bt/bluedroid/stack/include/sdpint.h @@ -0,0 +1,325 @@ +/****************************************************************************** + * + * Copyright (C) 1999-2012 Broadcom Corporation + * + * 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 internally used SDP definitions + * + ******************************************************************************/ + +#ifndef SDP_INT_H +#define SDP_INT_H + +#include "bt_target.h" +#include "sdp_api.h" +#include "l2c_api.h" + + +/* Continuation length - we use a 2-byte offset */ +#define SDP_CONTINUATION_LEN 2 +#define SDP_MAX_CONTINUATION_LEN 16 /* As per the spec */ + +/* Timeout definitions. */ +#define SDP_INACT_TIMEOUT 30 /* Inactivity timeout */ + + +/* Define the Out-Flow default values. */ +#define SDP_OFLOW_QOS_FLAG 0 +#define SDP_OFLOW_SERV_TYPE 0 +#define SDP_OFLOW_TOKEN_RATE 0 +#define SDP_OFLOW_TOKEN_BUCKET_SIZE 0 +#define SDP_OFLOW_PEAK_BANDWIDTH 0 +#define SDP_OFLOW_LATENCY 0 +#define SDP_OFLOW_DELAY_VARIATION 0 + +/* Define the In-Flow default values. */ +#define SDP_IFLOW_QOS_FLAG 0 +#define SDP_IFLOW_SERV_TYPE 0 +#define SDP_IFLOW_TOKEN_RATE 0 +#define SDP_IFLOW_TOKEN_BUCKET_SIZE 0 +#define SDP_IFLOW_PEAK_BANDWIDTH 0 +#define SDP_IFLOW_LATENCY 0 +#define SDP_IFLOW_DELAY_VARIATION 0 + +#define SDP_LINK_TO 0 + +/* Define the type of device notification. */ +/* (Inquiry Scan and Page Scan) */ +#define SDP_DEVICE_NOTI_LEN sizeof (BT_HDR) + \ + HCIC_PREAMBLE_SIZE + \ + HCIC_PARAM_SIZE_WRITE_PARAM1 + +#define SDP_DEVICE_NOTI_FLAG 0x03 + +/* Define the Protocol Data Unit (PDU) types. +*/ +#define SDP_PDU_ERROR_RESPONSE 0x01 +#define SDP_PDU_SERVICE_SEARCH_REQ 0x02 +#define SDP_PDU_SERVICE_SEARCH_RSP 0x03 +#define SDP_PDU_SERVICE_ATTR_REQ 0x04 +#define SDP_PDU_SERVICE_ATTR_RSP 0x05 +#define SDP_PDU_SERVICE_SEARCH_ATTR_REQ 0x06 +#define SDP_PDU_SERVICE_SEARCH_ATTR_RSP 0x07 + +/* Max UUIDs and attributes we support per sequence */ +#define MAX_UUIDS_PER_SEQ 8 +#define MAX_ATTR_PER_SEQ 8 + +/* Max length we support for any attribute */ +// btla-specific ++ +#ifdef SDP_MAX_ATTR_LEN +#define MAX_ATTR_LEN SDP_MAX_ATTR_LEN +#else +#define MAX_ATTR_LEN 256 +#endif +// btla-specific -- + +/* Internal UUID sequence representation */ +typedef struct +{ + UINT16 len; + UINT8 value[MAX_UUID_SIZE]; +} tUID_ENT; + +typedef struct +{ + UINT16 num_uids; + tUID_ENT uuid_entry[MAX_UUIDS_PER_SEQ]; +} tSDP_UUID_SEQ; + + +/* Internal attribute sequence definitions */ +typedef struct +{ + UINT16 start; + UINT16 end; +} tATT_ENT; + +typedef struct +{ + UINT16 num_attr; + tATT_ENT attr_entry[MAX_ATTR_PER_SEQ]; +} tSDP_ATTR_SEQ; + + +/* Define the attribute element of the SDP database record */ +typedef struct +{ + UINT32 len; /* Number of bytes in the entry */ + UINT8 *value_ptr; /* Points to attr_pad */ + UINT16 id; + UINT8 type; +} tSDP_ATTRIBUTE; + +/* An SDP record consists of a handle, and 1 or more attributes */ +typedef struct +{ + UINT32 record_handle; + UINT32 free_pad_ptr; + UINT16 num_attributes; + tSDP_ATTRIBUTE attribute[SDP_MAX_REC_ATTR]; + UINT8 attr_pad[SDP_MAX_PAD_LEN]; +} tSDP_RECORD; + + +/* Define the SDP database */ +typedef struct +{ + UINT32 di_primary_handle; /* Device ID Primary record or NULL if nonexistent */ + UINT16 num_records; + tSDP_RECORD record[SDP_MAX_RECORDS]; +} tSDP_DB; + +enum +{ + SDP_IS_SEARCH, + SDP_IS_ATTR_SEARCH, +}; + +#if SDP_SERVER_ENABLED == TRUE +/* Continuation information for the SDP server response */ +typedef struct +{ + UINT16 next_attr_index; /* attr index for next continuation response */ + UINT16 next_attr_start_id; /* attr id to start with for the attr index in next cont. response */ + tSDP_RECORD *prev_sdp_rec; /* last sdp record that was completely sent in the response */ + BOOLEAN last_attr_seq_desc_sent; /* whether attr seq length has been sent previously */ + UINT16 attr_offset; /* offset within the attr to keep trak of partial attributes in the responses */ +} tSDP_CONT_INFO; +#endif /* SDP_SERVER_ENABLED == TRUE */ + +/* Define the SDP Connection Control Block */ +typedef struct +{ +#define SDP_STATE_IDLE 0 +#define SDP_STATE_CONN_SETUP 1 +#define SDP_STATE_CFG_SETUP 2 +#define SDP_STATE_CONNECTED 3 + UINT8 con_state; + +#define SDP_FLAGS_IS_ORIG 0x01 +#define SDP_FLAGS_HIS_CFG_DONE 0x02 +#define SDP_FLAGS_MY_CFG_DONE 0x04 + UINT8 con_flags; + + BD_ADDR device_address; + TIMER_LIST_ENT timer_entry; + UINT16 rem_mtu_size; + UINT16 connection_id; + UINT16 list_len; /* length of the response in the GKI buffer */ + UINT8 *rsp_list; /* pointer to GKI buffer holding response */ + +#if SDP_CLIENT_ENABLED == TRUE + tSDP_DISCOVERY_DB *p_db; /* Database to save info into */ + tSDP_DISC_CMPL_CB *p_cb; /* Callback for discovery done */ + tSDP_DISC_CMPL_CB2 *p_cb2; /* Callback for discovery done piggy back with the user data */ + void *user_data; /* piggy back user data */ + UINT32 handles[SDP_MAX_DISC_SERVER_RECS]; /* Discovered server record handles */ + UINT16 num_handles; /* Number of server handles */ + UINT16 cur_handle; /* Current handle being processed */ + UINT16 transaction_id; + UINT16 disconnect_reason; /* Disconnect reason */ +#if (defined(SDP_BROWSE_PLUS) && SDP_BROWSE_PLUS == TRUE) + UINT16 cur_uuid_idx; +#endif + +#define SDP_DISC_WAIT_CONN 0 +#define SDP_DISC_WAIT_HANDLES 1 +#define SDP_DISC_WAIT_ATTR 2 +#define SDP_DISC_WAIT_SEARCH_ATTR 3 +#define SDP_DISC_WAIT_CANCEL 5 + + UINT8 disc_state; + UINT8 is_attr_search; +#endif /* SDP_CLIENT_ENABLED == TRUE */ + +#if SDP_SERVER_ENABLED == TRUE + UINT16 cont_offset; /* Continuation state data in the server response */ + tSDP_CONT_INFO cont_info; /* structure to hold continuation information for the server response */ +#endif /* SDP_SERVER_ENABLED == TRUE */ + +} tCONN_CB; + + +/* The main SDP control block */ +typedef struct +{ + tL2CAP_CFG_INFO l2cap_my_cfg; /* My L2CAP config */ + tCONN_CB ccb[SDP_MAX_CONNECTIONS]; +#if SDP_SERVER_ENABLED == TRUE + tSDP_DB server_db; +#endif + tL2CAP_APPL_INFO reg_info; /* L2CAP Registration info */ + UINT16 max_attr_list_size; /* Max attribute list size to use */ + UINT16 max_recs_per_search; /* Max records we want per seaarch */ + UINT8 trace_level; +} tSDP_CB; + +#ifdef __cplusplus +extern "C" { +#endif +/* Global SDP data */ +#if SDP_DYNAMIC_MEMORY == FALSE +extern tSDP_CB sdp_cb; +#else +extern tSDP_CB *sdp_cb_ptr; +#define sdp_cb (*sdp_cb_ptr) +#endif + +#ifdef __cplusplus +} +#endif + +/* Functions provided by sdp_main.c */ +extern void sdp_init (void); +extern void sdp_disconnect (tCONN_CB*p_ccb, UINT16 reason); + +#if (defined(SDP_DEBUG) && SDP_DEBUG == TRUE) +extern UINT16 sdp_set_max_attr_list_size (UINT16 max_size); +#endif + +/* Functions provided by sdp_conn.c +*/ +extern void sdp_conn_rcv_l2e_conn_ind (BT_HDR *p_msg); +extern void sdp_conn_rcv_l2e_conn_cfm (BT_HDR *p_msg); +extern void sdp_conn_rcv_l2e_disc (BT_HDR *p_msg); +extern void sdp_conn_rcv_l2e_config_ind (BT_HDR *p_msg); +extern void sdp_conn_rcv_l2e_config_cfm (BT_HDR *p_msg); +extern void sdp_conn_rcv_l2e_conn_failed (BT_HDR *p_msg); +extern void sdp_conn_rcv_l2e_connected (BT_HDR *p_msg); +extern void sdp_conn_rcv_l2e_conn_failed (BT_HDR *p_msg); +extern void sdp_conn_rcv_l2e_data (BT_HDR *p_msg); +extern void sdp_conn_timeout (tCONN_CB *p_ccb); + +extern tCONN_CB *sdp_conn_originate (UINT8 *p_bd_addr); + +/* Functions provided by sdp_utils.c +*/ +extern tCONN_CB *sdpu_find_ccb_by_cid (UINT16 cid); +extern tCONN_CB *sdpu_find_ccb_by_db (tSDP_DISCOVERY_DB *p_db); +extern tCONN_CB *sdpu_allocate_ccb (void); +extern void sdpu_release_ccb (tCONN_CB *p_ccb); + +extern UINT8 *sdpu_build_attrib_seq (UINT8 *p_out, UINT16 *p_attr, UINT16 num_attrs); +extern UINT8 *sdpu_build_attrib_entry (UINT8 *p_out, tSDP_ATTRIBUTE *p_attr); +extern void sdpu_build_n_send_error (tCONN_CB *p_ccb, UINT16 trans_num, UINT16 error_code, char *p_error_text); + +extern UINT8 *sdpu_extract_attr_seq (UINT8 *p, UINT16 param_len, tSDP_ATTR_SEQ *p_seq); +extern UINT8 *sdpu_extract_uid_seq (UINT8 *p, UINT16 param_len, tSDP_UUID_SEQ *p_seq); + +extern UINT8 *sdpu_get_len_from_type (UINT8 *p, UINT8 type, UINT32 *p_len); +extern BOOLEAN sdpu_is_base_uuid (UINT8 *p_uuid); +extern BOOLEAN sdpu_compare_uuid_arrays (UINT8 *p_uuid1, UINT32 len1, UINT8 *p_uuid2, UINT16 len2); +extern BOOLEAN sdpu_compare_bt_uuids (tBT_UUID *p_uuid1, tBT_UUID *p_uuid2); +extern BOOLEAN sdpu_compare_uuid_with_attr (tBT_UUID *p_btuuid, tSDP_DISC_ATTR *p_attr); + +extern void sdpu_sort_attr_list( UINT16 num_attr, tSDP_DISCOVERY_DB *p_db ); +extern UINT16 sdpu_get_list_len( tSDP_UUID_SEQ *uid_seq, tSDP_ATTR_SEQ *attr_seq ); +extern UINT16 sdpu_get_attrib_seq_len(tSDP_RECORD *p_rec, tSDP_ATTR_SEQ *attr_seq); +extern UINT16 sdpu_get_attrib_entry_len(tSDP_ATTRIBUTE *p_attr); +extern UINT8 *sdpu_build_partial_attrib_entry (UINT8 *p_out, tSDP_ATTRIBUTE *p_attr, UINT16 len, UINT16 *offset); +extern void sdpu_uuid16_to_uuid128(UINT16 uuid16, UINT8* p_uuid128); + +/* Functions provided by sdp_db.c +*/ +extern tSDP_RECORD *sdp_db_service_search (tSDP_RECORD *p_rec, tSDP_UUID_SEQ *p_seq); +extern tSDP_RECORD *sdp_db_find_record (UINT32 handle); +extern tSDP_ATTRIBUTE *sdp_db_find_attr_in_rec (tSDP_RECORD *p_rec, UINT16 start_attr, UINT16 end_attr); + + +/* Functions provided by sdp_server.c +*/ +#if SDP_SERVER_ENABLED == TRUE +extern void sdp_server_handle_client_req (tCONN_CB *p_ccb, BT_HDR *p_msg); +#else +#define sdp_server_handle_client_req(p_ccb, p_msg) +#endif + +/* Functions provided by sdp_discovery.c +*/ +#if SDP_CLIENT_ENABLED == TRUE +extern void sdp_disc_connected (tCONN_CB *p_ccb); +extern void sdp_disc_server_rsp (tCONN_CB *p_ccb, BT_HDR *p_msg); +#else +#define sdp_disc_connected(p_ccb) +#define sdp_disc_server_rsp(p_ccb, p_msg) +#endif + + + +#endif diff --git a/components/bt/bluedroid/stack/include/smp_api.h b/components/bt/bluedroid/stack/include/smp_api.h new file mode 100755 index 0000000000..62ef1db24f --- /dev/null +++ b/components/bt/bluedroid/stack/include/smp_api.h @@ -0,0 +1,494 @@ +/****************************************************************************** + * + * Copyright (C) 1999-2012 Broadcom Corporation + * + * 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 SMP API function external definitions. + * + ******************************************************************************/ +#ifndef SMP_API_H +#define SMP_API_H + +#include "bt_target.h" + +#define SMP_PIN_CODE_LEN_MAX PIN_CODE_LEN +#define SMP_PIN_CODE_LEN_MIN 6 + +#if BLE_INCLUDED == TRUE && SMP_INCLUDED == TRUE +/* SMP command code */ +#define SMP_OPCODE_PAIRING_REQ 0x01 +#define SMP_OPCODE_PAIRING_RSP 0x02 +#define SMP_OPCODE_CONFIRM 0x03 +#define SMP_OPCODE_RAND 0x04 +#define SMP_OPCODE_PAIRING_FAILED 0x05 +#define SMP_OPCODE_ENCRYPT_INFO 0x06 +#define SMP_OPCODE_MASTER_ID 0x07 +#define SMP_OPCODE_IDENTITY_INFO 0x08 +#define SMP_OPCODE_ID_ADDR 0x09 +#define SMP_OPCODE_SIGN_INFO 0x0A +#define SMP_OPCODE_SEC_REQ 0x0B +#define SMP_OPCODE_PAIR_PUBLIC_KEY 0x0C +#define SMP_OPCODE_PAIR_DHKEY_CHECK 0x0D +#define SMP_OPCODE_PAIR_KEYPR_NOTIF 0x0E +#define SMP_OPCODE_MAX SMP_OPCODE_PAIR_KEYPR_NOTIF +#define SMP_OPCODE_MIN SMP_OPCODE_PAIRING_REQ +#define SMP_OPCODE_PAIR_COMMITM 0x0F +#endif + +/* SMP event type */ +#define SMP_IO_CAP_REQ_EVT 1 /* IO capability request event */ +#define SMP_SEC_REQUEST_EVT 2 /* SMP pairing request */ +#define SMP_PASSKEY_NOTIF_EVT 3 /* passkey notification event */ +#define SMP_PASSKEY_REQ_EVT 4 /* passkey request event */ +#define SMP_OOB_REQ_EVT 5 /* OOB request event */ +#define SMP_NC_REQ_EVT 6 /* Numeric Comparison request event */ +#define SMP_COMPLT_EVT 7 /* SMP complete event */ +#define SMP_PEER_KEYPR_NOT_EVT 8 /* Peer keypress notification received event */ +#define SMP_SC_OOB_REQ_EVT 9 /* SC OOB request event (both local and peer OOB data */ + /* can be expected in response) */ +#define SMP_SC_LOC_OOB_DATA_UP_EVT 10 /* SC OOB local data set is created */ + /* (as result of SMP_CrLocScOobData(...)) */ +#define SMP_BR_KEYS_REQ_EVT 12 /* SMP over BR keys request event */ +typedef UINT8 tSMP_EVT; + + +/* pairing failure reason code */ +#define SMP_PASSKEY_ENTRY_FAIL 0x01 +#define SMP_OOB_FAIL 0x02 +#define SMP_PAIR_AUTH_FAIL 0x03 +#define SMP_CONFIRM_VALUE_ERR 0x04 +#define SMP_PAIR_NOT_SUPPORT 0x05 +#define SMP_ENC_KEY_SIZE 0x06 +#define SMP_INVALID_CMD 0x07 +#define SMP_PAIR_FAIL_UNKNOWN 0x08 +#define SMP_REPEATED_ATTEMPTS 0x09 +#define SMP_INVALID_PARAMETERS 0x0A +#define SMP_DHKEY_CHK_FAIL 0x0B +#define SMP_NUMERIC_COMPAR_FAIL 0x0C +#define SMP_BR_PARING_IN_PROGR 0x0D +#define SMP_XTRANS_DERIVE_NOT_ALLOW 0x0E +#define SMP_MAX_FAIL_RSN_PER_SPEC SMP_XTRANS_DERIVE_NOT_ALLOW + +/* self defined error code */ +#define SMP_PAIR_INTERNAL_ERR (SMP_MAX_FAIL_RSN_PER_SPEC + 0x01) /* 0x0E */ + +/* 0x0F unknown IO capability, unable to decide association model */ +#define SMP_UNKNOWN_IO_CAP (SMP_MAX_FAIL_RSN_PER_SPEC + 0x02) /* 0x0F */ + +#define SMP_INIT_FAIL (SMP_MAX_FAIL_RSN_PER_SPEC + 0x03) /* 0x10 */ +#define SMP_CONFIRM_FAIL (SMP_MAX_FAIL_RSN_PER_SPEC + 0x04) /* 0x11 */ +#define SMP_BUSY (SMP_MAX_FAIL_RSN_PER_SPEC + 0x05) /* 0x12 */ +#define SMP_ENC_FAIL (SMP_MAX_FAIL_RSN_PER_SPEC + 0x06) /* 0x13 */ +#define SMP_STARTED (SMP_MAX_FAIL_RSN_PER_SPEC + 0x07) /* 0x14 */ +#define SMP_RSP_TIMEOUT (SMP_MAX_FAIL_RSN_PER_SPEC + 0x08) /* 0x15 */ +#define SMP_DIV_NOT_AVAIL (SMP_MAX_FAIL_RSN_PER_SPEC + 0x09) /* 0x16 */ + +/* 0x17 unspecified failed reason */ +#define SMP_FAIL (SMP_MAX_FAIL_RSN_PER_SPEC + 0x0A) /* 0x17 */ + +#define SMP_CONN_TOUT (SMP_MAX_FAIL_RSN_PER_SPEC + 0x0B) +#define SMP_SUCCESS 0 + +typedef UINT8 tSMP_STATUS; + + +/* Device IO capability */ +#define SMP_IO_CAP_OUT BTM_IO_CAP_OUT /* DisplayOnly */ +#define SMP_IO_CAP_IO BTM_IO_CAP_IO /* DisplayYesNo */ +#define SMP_IO_CAP_IN BTM_IO_CAP_IN /* KeyboardOnly */ +#define SMP_IO_CAP_NONE BTM_IO_CAP_NONE /* NoInputNoOutput */ +#define SMP_IO_CAP_KBDISP BTM_IO_CAP_KBDISP /* Keyboard Display */ +#define SMP_IO_CAP_MAX BTM_IO_CAP_MAX +typedef UINT8 tSMP_IO_CAP; + +#ifndef SMP_DEFAULT_IO_CAPS + #define SMP_DEFAULT_IO_CAPS SMP_IO_CAP_KBDISP +#endif + +/* OOB data present or not */ +enum +{ + SMP_OOB_NONE, + SMP_OOB_PRESENT, + SMP_OOB_UNKNOWN +}; +typedef UINT8 tSMP_OOB_FLAG; + +/* type of OOB data required from application */ +enum +{ + SMP_OOB_INVALID_TYPE, + SMP_OOB_PEER, + SMP_OOB_LOCAL, + SMP_OOB_BOTH +}; +typedef UINT8 tSMP_OOB_DATA_TYPE; + +#define SMP_AUTH_NO_BOND 0x00 +#define SMP_AUTH_GEN_BOND 0x01 //todo sdh change GEN_BOND to BOND + +/* SMP Authentication requirement */ +#define SMP_AUTH_YN_BIT (1 << 2) +#define SMP_SC_SUPPORT_BIT (1 << 3) +#define SMP_KP_SUPPORT_BIT (1 << 4) + +#define SMP_AUTH_MASK (SMP_AUTH_GEN_BOND|SMP_AUTH_YN_BIT|SMP_SC_SUPPORT_BIT|SMP_KP_SUPPORT_BIT) + +#define SMP_AUTH_BOND SMP_AUTH_GEN_BOND + +/* no MITM, No Bonding, encryption only */ +#define SMP_AUTH_NB_ENC_ONLY 0x00 //(SMP_AUTH_MASK | BTM_AUTH_SP_NO) + +/* MITM, No Bonding, Use IO Capability to determine authentication procedure */ +#define SMP_AUTH_NB_IOCAP (SMP_AUTH_NO_BOND | SMP_AUTH_YN_BIT) + +/* No MITM, General Bonding, Encryption only */ +#define SMP_AUTH_GB_ENC_ONLY (SMP_AUTH_GEN_BOND ) + +/* MITM, General Bonding, Use IO Capability to determine authentication procedure */ +#define SMP_AUTH_GB_IOCAP (SMP_AUTH_GEN_BOND | SMP_AUTH_YN_BIT) + +/* Secure Connections, no MITM, no Bonding */ +#define SMP_AUTH_SC_ENC_ONLY (SMP_SC_SUPPORT_BIT) + +/* Secure Connections, no MITM, Bonding */ +#define SMP_AUTH_SC_GB (SMP_SC_SUPPORT_BIT | SMP_AUTH_GEN_BOND) + +/* Secure Connections, MITM, no Bonding */ +#define SMP_AUTH_SC_MITM_NB (SMP_SC_SUPPORT_BIT | SMP_AUTH_YN_BIT | SMP_AUTH_NO_BOND) + +/* Secure Connections, MITM, Bonding */ +#define SMP_AUTH_SC_MITM_GB (SMP_SC_SUPPORT_BIT | SMP_AUTH_YN_BIT | SMP_AUTH_GEN_BOND) + + /* All AuthReq RFU bits are set to 1 - NOTE: reserved bit in Bonding_Flags is not set */ +#define SMP_AUTH_ALL_RFU_SET 0xF8 + +typedef UINT8 tSMP_AUTH_REQ; + +#define SMP_SEC_NONE 0 +#define SMP_SEC_UNAUTHENTICATE (1 << 0) +#define SMP_SEC_AUTHENTICATED (1 << 2) +typedef UINT8 tSMP_SEC_LEVEL; + +/* Maximum Encryption Key Size range */ +#define SMP_ENCR_KEY_SIZE_MIN 7 +#define SMP_ENCR_KEY_SIZE_MAX 16 + +/* SMP key types */ +#define SMP_SEC_KEY_TYPE_ENC (1 << 0) /* encryption key */ +#define SMP_SEC_KEY_TYPE_ID (1 << 1) /* identity key */ +#define SMP_SEC_KEY_TYPE_CSRK (1 << 2) /* slave CSRK */ +#define SMP_SEC_KEY_TYPE_LK (1 << 3) /* BR/EDR link key */ +typedef UINT8 tSMP_KEYS; + +#define SMP_BR_SEC_DEFAULT_KEY (SMP_SEC_KEY_TYPE_ENC | SMP_SEC_KEY_TYPE_ID | \ + SMP_SEC_KEY_TYPE_CSRK) + +/* default security key distribution value */ +#define SMP_SEC_DEFAULT_KEY (SMP_SEC_KEY_TYPE_ENC | SMP_SEC_KEY_TYPE_ID | \ + SMP_SEC_KEY_TYPE_CSRK | SMP_SEC_KEY_TYPE_LK) + +#define SMP_SC_KEY_STARTED 0 /* passkey entry started */ +#define SMP_SC_KEY_ENTERED 1 /* passkey digit entered */ +#define SMP_SC_KEY_ERASED 2 /* passkey digit erased */ +#define SMP_SC_KEY_CLEARED 3 /* passkey cleared */ +#define SMP_SC_KEY_COMPLT 4 /* passkey entry completed */ +#define SMP_SC_KEY_OUT_OF_RANGE 5 /* out of range */ +typedef UINT8 tSMP_SC_KEY_TYPE; + +/* data type for BTM_SP_IO_REQ_EVT */ +typedef struct +{ + tSMP_IO_CAP io_cap; /* local IO capabilities */ + tSMP_OOB_FLAG oob_data; /* OOB data present (locally) for the peer device */ + tSMP_AUTH_REQ auth_req; /* Authentication required (for local device) */ + UINT8 max_key_size; /* max encryption key size */ + tSMP_KEYS init_keys; /* initiator keys to be distributed */ + tSMP_KEYS resp_keys; /* responder keys */ +} tSMP_IO_REQ; + +typedef struct +{ + tSMP_STATUS reason; + tSMP_SEC_LEVEL sec_level; + BOOLEAN is_pair_cancel; + BOOLEAN smp_over_br; +} tSMP_CMPL; + +typedef struct +{ + BT_OCTET32 x; + BT_OCTET32 y; +} tSMP_PUBLIC_KEY; + +/* the data associated with the info sent to the peer via OOB interface */ +typedef struct +{ + BOOLEAN present; + BT_OCTET16 randomizer; + BT_OCTET16 commitment; + + tBLE_BD_ADDR addr_sent_to; + BT_OCTET32 private_key_used; /* is used to calculate: */ + /* publ_key_used = P-256(private_key_used, curve_p256.G) - send it to the */ + /* other side */ + /* dhkey = P-256(private_key_used, publ key rcvd from the other side) */ + tSMP_PUBLIC_KEY publ_key_used; /* P-256(private_key_used, curve_p256.G) */ +} tSMP_LOC_OOB_DATA; + +/* the data associated with the info received from the peer via OOB interface */ +typedef struct +{ + BOOLEAN present; + BT_OCTET16 randomizer; + BT_OCTET16 commitment; + tBLE_BD_ADDR addr_rcvd_from; +} tSMP_PEER_OOB_DATA; + +typedef struct +{ + tSMP_LOC_OOB_DATA loc_oob_data; + tSMP_PEER_OOB_DATA peer_oob_data; +} tSMP_SC_OOB_DATA; + + +typedef union +{ + UINT32 passkey; + tSMP_IO_REQ io_req; /* IO request */ + tSMP_CMPL cmplt; + tSMP_OOB_DATA_TYPE req_oob_type; + tSMP_LOC_OOB_DATA loc_oob_data; +}tSMP_EVT_DATA; + + +/* AES Encryption output */ +typedef struct +{ + UINT8 status; + UINT8 param_len; + UINT16 opcode; + UINT8 param_buf[BT_OCTET16_LEN]; +} tSMP_ENC; + +/* Security Manager events - Called by the stack when Security Manager related events occur.*/ +typedef UINT8 (tSMP_CALLBACK) (tSMP_EVT event, BD_ADDR bd_addr, tSMP_EVT_DATA *p_data); + +/* callback function for CMAC algorithm +*/ +typedef void (tCMAC_CMPL_CBACK)(UINT8 *p_mac, UINT16 tlen, UINT32 sign_counter); + +/***************************************************************************** +** External Function Declarations +*****************************************************************************/ +#ifdef __cplusplus +extern "C" +{ +#endif +/* API of SMP */ + +/******************************************************************************* +** +** Function SMP_Init +** +** Description This function initializes the SMP unit. +** +** Returns void +** +*******************************************************************************/ +extern void SMP_Init(void); + +/******************************************************************************* +** +** Function SMP_SetTraceLevel +** +** Description This function sets the trace level for SMP. If called with +** a value of 0xFF, it simply returns the current trace level. +** +** Returns The new or current trace level +** +*******************************************************************************/ +extern UINT8 SMP_SetTraceLevel (UINT8 new_level); + +/******************************************************************************* +** +** Function SMP_Register +** +** Description This function register for the SMP service callback. +** +** Returns void +** +*******************************************************************************/ +extern BOOLEAN SMP_Register (tSMP_CALLBACK *p_cback); + +/******************************************************************************* +** +** Function SMP_Pair +** +** Description This function is called to start a SMP pairing. +** +** Returns SMP_STARTED if bond started, else otherwise exception. +** +*******************************************************************************/ +extern tSMP_STATUS SMP_Pair (BD_ADDR bd_addr); + +/******************************************************************************* +** +** Function SMP_BR_PairWith +** +** Description This function is called to start a SMP pairing over BR/EDR. +** +** Returns SMP_STARTED if pairing started, otherwise reason for failure. +** +*******************************************************************************/ +extern tSMP_STATUS SMP_BR_PairWith (BD_ADDR bd_addr); + +/******************************************************************************* +** +** Function SMP_PairCancel +** +** Description This function is called to cancel a SMP pairing. +** +** Returns TRUE - pairing cancelled +** +*******************************************************************************/ +extern BOOLEAN SMP_PairCancel (BD_ADDR bd_addr); + +/******************************************************************************* +** +** Function SMP_SecurityGrant +** +** Description This function is called to grant security process. +** +** Parameters bd_addr - peer device bd address. +** res - result of the operation SMP_SUCCESS if success. +** Otherwise, SMP_REPEATED_ATTEMPTS is too many attempts. +** +** Returns None +** +*******************************************************************************/ +extern void SMP_SecurityGrant(BD_ADDR bd_addr, UINT8 res); + +/******************************************************************************* +** +** Function SMP_PasskeyReply +** +** Description This function is called after Security Manager submitted +** Passkey request to the application. +** +** Parameters: bd_addr - Address of the device for which PIN was requested +** res - result of the operation SMP_SUCCESS if success +** passkey - numeric value in the range of +** BTM_MIN_PASSKEY_VAL(0) - BTM_MAX_PASSKEY_VAL(999999(0xF423F)). +** +*******************************************************************************/ +extern void SMP_PasskeyReply (BD_ADDR bd_addr, UINT8 res, UINT32 passkey); + +/******************************************************************************* +** +** Function SMP_ConfirmReply +** +** Description This function is called after Security Manager submitted +** numeric comparison request to the application. +** +** Parameters: bd_addr - Address of the device with which numeric +** comparison was requested +** res - comparison result SMP_SUCCESS if success +** +*******************************************************************************/ +extern void SMP_ConfirmReply (BD_ADDR bd_addr, UINT8 res); + +/******************************************************************************* +** +** Function SMP_OobDataReply +** +** Description This function is called to provide the OOB data for +** SMP in response to SMP_OOB_REQ_EVT +** +** Parameters: bd_addr - Address of the peer device +** res - result of the operation SMP_SUCCESS if success +** p_data - SM Randomizer C. +** +*******************************************************************************/ +extern void SMP_OobDataReply(BD_ADDR bd_addr, tSMP_STATUS res, UINT8 len, + UINT8 *p_data); + +/******************************************************************************* +** +** Function SMP_SecureConnectionOobDataReply +** +** Description This function is called to provide the SC OOB data for +** SMP in response to SMP_SC_OOB_REQ_EVT +** +** Parameters: p_data - pointer to the data +** +*******************************************************************************/ +extern void SMP_SecureConnectionOobDataReply(UINT8 *p_data); + +/******************************************************************************* +** +** Function SMP_Encrypt +** +** Description This function is called to encrypt the data with the specified +** key +** +** Parameters: key - Pointer to key key[0] conatins the MSB +** key_len - key length +** plain_text - Pointer to data to be encrypted +** plain_text[0] conatins the MSB +** pt_len - plain text length +** p_out - pointer to the encrypted outputs +** +** Returns Boolean - TRUE: encryption is successful +*******************************************************************************/ +extern BOOLEAN SMP_Encrypt (UINT8 *key, UINT8 key_len, + UINT8 *plain_text, UINT8 pt_len, + tSMP_ENC *p_out); + +/******************************************************************************* +** +** Function SMP_KeypressNotification +** +** Description This function is called to notify SM about Keypress Notification. +** +** Parameters: bd_addr - Address of the device to send keypress +** notification to +** value - keypress notification parameter value +** +*******************************************************************************/ +extern void SMP_KeypressNotification (BD_ADDR bd_addr, UINT8 value); + +/******************************************************************************* +** +** Function SMP_CreateLocalSecureConnectionsOobData +** +** Description This function is called to start creation of local SC OOB +** data set (tSMP_LOC_OOB_DATA). +** +** Parameters: bd_addr - Address of the device to send OOB data block +** to. +** +** Returns Boolean - TRUE: creation of local SC OOB data set started. +*******************************************************************************/ +extern BOOLEAN SMP_CreateLocalSecureConnectionsOobData ( + tBLE_BD_ADDR *addr_to_send_to); + +#ifdef __cplusplus +} +#endif +#endif /* SMP_API_H */ diff --git a/components/bt/bluedroid/stack/include/smp_int.h b/components/bt/bluedroid/stack/include/smp_int.h new file mode 100755 index 0000000000..a058bab538 --- /dev/null +++ b/components/bt/bluedroid/stack/include/smp_int.h @@ -0,0 +1,543 @@ +/****************************************************************************** + * + * Copyright (C) 1999-2012 Broadcom Corporation + * + * 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 internally used SMP definitions + * + ******************************************************************************/ +#ifndef SMP_INT_H +#define SMP_INT_H + +#if BLE_INCLUDED == TRUE + +#include "btu.h" +#include "btm_ble_api.h" +#include "btm_api.h" +#include "smp_api.h" + +#define SMP_MODEL_ENCRYPTION_ONLY 0 /* Legacy mode, Just Works model */ +#define SMP_MODEL_PASSKEY 1 /* Legacy mode, Passkey Entry model, this side inputs the key */ +#define SMP_MODEL_OOB 2 /* Legacy mode, OOB model */ +#define SMP_MODEL_KEY_NOTIF 3 /* Legacy mode, Passkey Entry model, this side displays the key */ +#define SMP_MODEL_SEC_CONN_JUSTWORKS 4 /* Secure Connections mode, Just Works model */ +#define SMP_MODEL_SEC_CONN_NUM_COMP 5 /* Secure Connections mode, Numeric Comparison model */ +#define SMP_MODEL_SEC_CONN_PASSKEY_ENT 6 /* Secure Connections mode, Passkey Entry model, */ + /* this side inputs the key */ +#define SMP_MODEL_SEC_CONN_PASSKEY_DISP 7 /* Secure Connections mode, Passkey Entry model, */ + /* this side displays the key */ +#define SMP_MODEL_SEC_CONN_OOB 8 /* Secure Connections mode, OOB model */ +#define SMP_MODEL_OUT_OF_RANGE 9 +typedef UINT8 tSMP_ASSO_MODEL; + + +#ifndef SMP_MAX_CONN + #define SMP_MAX_CONN 2 +#endif + +#define SMP_WAIT_FOR_RSP_TOUT 30 + +#define SMP_OPCODE_INIT 0x04 + +/* SMP events */ +#define SMP_PAIRING_REQ_EVT SMP_OPCODE_PAIRING_REQ +#define SMP_PAIRING_RSP_EVT SMP_OPCODE_PAIRING_RSP +#define SMP_CONFIRM_EVT SMP_OPCODE_CONFIRM +#define SMP_RAND_EVT SMP_OPCODE_RAND +#define SMP_PAIRING_FAILED_EVT SMP_OPCODE_PAIRING_FAILED +#define SMP_ENCRPTION_INFO_EVT SMP_OPCODE_ENCRYPT_INFO +#define SMP_MASTER_ID_EVT SMP_OPCODE_MASTER_ID +#define SMP_ID_INFO_EVT SMP_OPCODE_IDENTITY_INFO +#define SMP_ID_ADDR_EVT SMP_OPCODE_ID_ADDR +#define SMP_SIGN_INFO_EVT SMP_OPCODE_SIGN_INFO +#define SMP_SECURITY_REQ_EVT SMP_OPCODE_SEC_REQ + +#define SMP_PAIR_PUBLIC_KEY_EVT SMP_OPCODE_PAIR_PUBLIC_KEY +#define SMP_PAIR_KEYPRESS_NOTIFICATION_EVT SMP_OPCODE_PAIR_KEYPR_NOTIF + +#define SMP_PAIR_COMMITM_EVT SMP_OPCODE_PAIR_COMMITM + +#define SMP_SELF_DEF_EVT (SMP_PAIR_COMMITM_EVT + 1) +#define SMP_KEY_READY_EVT (SMP_SELF_DEF_EVT) +#define SMP_ENCRYPTED_EVT (SMP_SELF_DEF_EVT + 1) +#define SMP_L2CAP_CONN_EVT (SMP_SELF_DEF_EVT + 2) +#define SMP_L2CAP_DISCONN_EVT (SMP_SELF_DEF_EVT + 3) +#define SMP_IO_RSP_EVT (SMP_SELF_DEF_EVT + 4) +#define SMP_API_SEC_GRANT_EVT (SMP_SELF_DEF_EVT + 5) +#define SMP_TK_REQ_EVT (SMP_SELF_DEF_EVT + 6) +#define SMP_AUTH_CMPL_EVT (SMP_SELF_DEF_EVT + 7) +#define SMP_ENC_REQ_EVT (SMP_SELF_DEF_EVT + 8) +#define SMP_BOND_REQ_EVT (SMP_SELF_DEF_EVT + 9) +#define SMP_DISCARD_SEC_REQ_EVT (SMP_SELF_DEF_EVT + 10) + +#define SMP_PAIR_DHKEY_CHCK_EVT SMP_OPCODE_PAIR_DHKEY_CHECK + +#define SMP_PUBL_KEY_EXCH_REQ_EVT (SMP_SELF_DEF_EVT + 11) /* request to start public */ + /* key exchange */ + +#define SMP_LOC_PUBL_KEY_CRTD_EVT (SMP_SELF_DEF_EVT + 12) /* local public key created */ + +#define SMP_BOTH_PUBL_KEYS_RCVD_EVT (SMP_SELF_DEF_EVT + 13) /* both local and peer public */ + /* keys are saved in cb */ + +#define SMP_SC_DHKEY_CMPLT_EVT (SMP_SELF_DEF_EVT + 14) /* DHKey computation is completed,*/ + /* time to start SC phase1 */ + +#define SMP_HAVE_LOC_NONCE_EVT (SMP_SELF_DEF_EVT + 15) /* new local nonce is generated */ + /*and saved in p_cb->rand */ + +#define SMP_SC_PHASE1_CMPLT_EVT (SMP_SELF_DEF_EVT + 16) /* time to start SC phase2 */ + +#define SMP_SC_CALC_NC_EVT (SMP_SELF_DEF_EVT + 17) /* request to calculate number */ + /* for user check. Used only in the */ + /* numeric compare protocol */ + +/* Request to display the number for user check to the user.*/ +/* Used only in the numeric compare protocol */ +#define SMP_SC_DSPL_NC_EVT (SMP_SELF_DEF_EVT + 18) + +#define SMP_SC_NC_OK_EVT (SMP_SELF_DEF_EVT + 19) /* user confirms 'OK' numeric */ + /*comparison request */ + +/* both local and peer DHKey Checks are already present - it is used on slave to prevent race condition */ +#define SMP_SC_2_DHCK_CHKS_PRES_EVT (SMP_SELF_DEF_EVT + 20) + +/* same meaning as SMP_KEY_READY_EVT to separate between SC and legacy actions */ +#define SMP_SC_KEY_READY_EVT (SMP_SELF_DEF_EVT + 21) +#define SMP_KEYPRESS_NOTIFICATION_EVENT (SMP_SELF_DEF_EVT + 22) + +#define SMP_SC_OOB_DATA_EVT (SMP_SELF_DEF_EVT + 23) /* SC OOB data from some */ + /* repository is provided */ + +#define SMP_CR_LOC_SC_OOB_DATA_EVT (SMP_SELF_DEF_EVT + 24) +#define SMP_MAX_EVT SMP_CR_LOC_SC_OOB_DATA_EVT + +typedef UINT8 tSMP_EVENT; + +/* Assumption it's only using the low 8 bits, if bigger than that, need to expand it to 16 bits */ +#define SMP_SEC_KEY_MASK 0x00ff + +/* SMP pairing state */ +enum +{ + SMP_STATE_IDLE, + SMP_STATE_WAIT_APP_RSP, + SMP_STATE_SEC_REQ_PENDING, + SMP_STATE_PAIR_REQ_RSP, + SMP_STATE_WAIT_CONFIRM, + SMP_STATE_CONFIRM, + SMP_STATE_RAND, + SMP_STATE_PUBLIC_KEY_EXCH, + SMP_STATE_SEC_CONN_PHS1_START, + SMP_STATE_WAIT_COMMITMENT, + SMP_STATE_WAIT_NONCE, + SMP_STATE_SEC_CONN_PHS2_START, + SMP_STATE_WAIT_DHK_CHECK, + SMP_STATE_DHK_CHECK, + SMP_STATE_ENCRYPTION_PENDING, + SMP_STATE_BOND_PENDING, + SMP_STATE_CREATE_LOCAL_SEC_CONN_OOB_DATA, + SMP_STATE_MAX +}; +typedef UINT8 tSMP_STATE; + +/* SMP over BR/EDR events */ +#define SMP_BR_PAIRING_REQ_EVT SMP_OPCODE_PAIRING_REQ +#define SMP_BR_PAIRING_RSP_EVT SMP_OPCODE_PAIRING_RSP +#define SMP_BR_CONFIRM_EVT SMP_OPCODE_CONFIRM /* not expected over BR/EDR */ +#define SMP_BR_RAND_EVT SMP_OPCODE_RAND /* not expected over BR/EDR */ +#define SMP_BR_PAIRING_FAILED_EVT SMP_OPCODE_PAIRING_FAILED +#define SMP_BR_ENCRPTION_INFO_EVT SMP_OPCODE_ENCRYPT_INFO /* not expected over BR/EDR */ +#define SMP_BR_MASTER_ID_EVT SMP_OPCODE_MASTER_ID /* not expected over BR/EDR */ +#define SMP_BR_ID_INFO_EVT SMP_OPCODE_IDENTITY_INFO +#define SMP_BR_ID_ADDR_EVT SMP_OPCODE_ID_ADDR +#define SMP_BR_SIGN_INFO_EVT SMP_OPCODE_SIGN_INFO +#define SMP_BR_SECURITY_REQ_EVT SMP_OPCODE_SEC_REQ /* not expected over BR/EDR */ +#define SMP_BR_PAIR_PUBLIC_KEY_EVT SMP_OPCODE_PAIR_PUBLIC_KEY /* not expected over BR/EDR */ +#define SMP_BR_PAIR_DHKEY_CHCK_EVT SMP_OPCODE_PAIR_DHKEY_CHECK /* not expected over BR/EDR */ +#define SMP_BR_PAIR_KEYPR_NOTIF_EVT SMP_OPCODE_PAIR_KEYPR_NOTIF /* not expected over BR/EDR */ +#define SMP_BR_SELF_DEF_EVT SMP_BR_PAIR_KEYPR_NOTIF_EVT +#define SMP_BR_KEY_READY_EVT (SMP_BR_SELF_DEF_EVT + 1) +#define SMP_BR_ENCRYPTED_EVT (SMP_BR_SELF_DEF_EVT + 2) +#define SMP_BR_L2CAP_CONN_EVT (SMP_BR_SELF_DEF_EVT + 3) +#define SMP_BR_L2CAP_DISCONN_EVT (SMP_BR_SELF_DEF_EVT + 4) +#define SMP_BR_KEYS_RSP_EVT (SMP_BR_SELF_DEF_EVT + 5) +#define SMP_BR_API_SEC_GRANT_EVT (SMP_BR_SELF_DEF_EVT + 6) +#define SMP_BR_TK_REQ_EVT (SMP_BR_SELF_DEF_EVT + 7) +#define SMP_BR_AUTH_CMPL_EVT (SMP_BR_SELF_DEF_EVT + 8) +#define SMP_BR_ENC_REQ_EVT (SMP_BR_SELF_DEF_EVT + 9) +#define SMP_BR_BOND_REQ_EVT (SMP_BR_SELF_DEF_EVT + 10) +#define SMP_BR_DISCARD_SEC_REQ_EVT (SMP_BR_SELF_DEF_EVT + 11) +#define SMP_BR_MAX_EVT (SMP_BR_SELF_DEF_EVT + 12) +typedef UINT8 tSMP_BR_EVENT; + +/* SMP over BR/EDR pairing states */ +enum +{ + SMP_BR_STATE_IDLE = SMP_STATE_IDLE, + SMP_BR_STATE_WAIT_APP_RSP, + SMP_BR_STATE_PAIR_REQ_RSP, + SMP_BR_STATE_BOND_PENDING, + SMP_BR_STATE_MAX +}; +typedef UINT8 tSMP_BR_STATE; + +/* random and encrption activity state */ +enum +{ + SMP_GEN_COMPARE = 1, + SMP_GEN_CONFIRM, + + SMP_GEN_DIV_LTK, + SMP_GEN_DIV_CSRK, + SMP_GEN_RAND_V, + SMP_GEN_TK, + SMP_GEN_SRAND_MRAND, + SMP_GEN_SRAND_MRAND_CONT, + SMP_GENERATE_PRIVATE_KEY_0_7, + SMP_GENERATE_PRIVATE_KEY_8_15, + SMP_GENERATE_PRIVATE_KEY_16_23, + SMP_GENERATE_PRIVATE_KEY_24_31, + SMP_GEN_NONCE_0_7, + SMP_GEN_NONCE_8_15 +}; + +enum +{ + SMP_KEY_TYPE_TK, + SMP_KEY_TYPE_CFM, + SMP_KEY_TYPE_CMP, + SMP_KEY_TYPE_PEER_DHK_CHCK, + SMP_KEY_TYPE_STK, + SMP_KEY_TYPE_LTK +}; +typedef struct +{ + UINT8 key_type; + UINT8* p_data; +}tSMP_KEY; + +typedef union +{ + UINT8 *p_data; /* UINT8 type data pointer */ + tSMP_KEY key; + UINT16 reason; + UINT32 passkey; + tSMP_OOB_DATA_TYPE req_oob_type; +}tSMP_INT_DATA; + +/* internal status mask */ +#define SMP_PAIR_FLAGS_WE_STARTED_DD (1) +#define SMP_PAIR_FLAGS_PEER_STARTED_DD (1 << 1) +#define SMP_PAIR_FLAGS_CMD_CONFIRM (1 << SMP_OPCODE_CONFIRM) /* 1 << 3 */ +#define SMP_PAIR_FLAG_ENC_AFTER_PAIR (1 << 4) +#define SMP_PAIR_FLAG_HAVE_PEER_DHK_CHK (1 << 5) /* used on slave to resolve race condition */ +#define SMP_PAIR_FLAG_HAVE_PEER_PUBL_KEY (1 << 6) /* used on slave to resolve race condition */ +#define SMP_PAIR_FLAG_HAVE_PEER_COMM (1 << 7) /* used to resolve race condition */ +#define SMP_PAIR_FLAG_HAVE_LOCAL_PUBL_KEY (1 << 8) /* used on slave to resolve race condition */ + +/* check if authentication requirement need MITM protection */ +#define SMP_NO_MITM_REQUIRED(x) (((x) & SMP_AUTH_YN_BIT) == 0) + +#define SMP_ENCRYT_KEY_SIZE 16 +#define SMP_ENCRYT_DATA_SIZE 16 +#define SMP_ECNCRPYT_STATUS HCI_SUCCESS + +typedef struct +{ + BD_ADDR bd_addr; + BT_HDR* p_copy; +} tSMP_REQ_Q_ENTRY; + +/* SMP control block */ +typedef struct +{ + tSMP_CALLBACK *p_callback; + TIMER_LIST_ENT rsp_timer_ent; + UINT8 trace_level; + BD_ADDR pairing_bda; + tSMP_STATE state; + BOOLEAN derive_lk; + BOOLEAN id_addr_rcvd; + tBLE_ADDR_TYPE id_addr_type; + BD_ADDR id_addr; + BOOLEAN smp_over_br; + tSMP_BR_STATE br_state; /* if SMP over BR/ERD has priority over SMP */ + UINT8 failure; + UINT8 status; + UINT8 role; + UINT16 flags; + UINT8 cb_evt; + tSMP_SEC_LEVEL sec_level; + BOOLEAN connect_initialized; + BT_OCTET16 confirm; + BT_OCTET16 rconfirm; + BT_OCTET16 rrand; /* for SC this is peer nonce */ + BT_OCTET16 rand; /* for SC this is local nonce */ + BT_OCTET32 private_key; + BT_OCTET32 dhkey; + BT_OCTET16 commitment; + BT_OCTET16 remote_commitment; + BT_OCTET16 local_random; /* local randomizer - passkey or OOB randomizer */ + BT_OCTET16 peer_random; /* peer randomizer - passkey or OOB randomizer */ + BT_OCTET16 dhkey_check; + BT_OCTET16 remote_dhkey_check; + tSMP_PUBLIC_KEY loc_publ_key; + tSMP_PUBLIC_KEY peer_publ_key; + tSMP_OOB_DATA_TYPE req_oob_type; + tSMP_SC_OOB_DATA sc_oob_data; + tSMP_IO_CAP peer_io_caps; + tSMP_IO_CAP local_io_capability; + tSMP_OOB_FLAG peer_oob_flag; + tSMP_OOB_FLAG loc_oob_flag; + tSMP_AUTH_REQ peer_auth_req; + tSMP_AUTH_REQ loc_auth_req; + BOOLEAN secure_connections_only_mode_required;/* TRUE if locally SM is required to operate */ + /* either in Secure Connections mode or not at all */ + tSMP_ASSO_MODEL selected_association_model; + BOOLEAN le_secure_connections_mode_is_used; + BOOLEAN le_sc_kp_notif_is_used; + tSMP_SC_KEY_TYPE local_keypress_notification; + tSMP_SC_KEY_TYPE peer_keypress_notification; + UINT8 round; /* authentication stage 1 round for passkey association model */ + UINT32 number_to_display; + BT_OCTET16 mac_key; + UINT8 peer_enc_size; + UINT8 loc_enc_size; + UINT8 peer_i_key; + UINT8 peer_r_key; + UINT8 local_i_key; + UINT8 local_r_key; + + BT_OCTET16 tk; + BT_OCTET16 ltk; + UINT16 div; + BT_OCTET16 csrk; /* storage for local CSRK */ + UINT16 ediv; + BT_OCTET8 enc_rand; + UINT8 rand_enc_proc_state; + UINT8 addr_type; + BD_ADDR local_bda; + BOOLEAN is_pair_cancel; + BOOLEAN discard_sec_req; + UINT8 rcvd_cmd_code; + UINT8 rcvd_cmd_len; + UINT16 total_tx_unacked; + BOOLEAN wait_for_authorization_complete; +}tSMP_CB; + +/* Server Action functions are of this type */ +typedef void (*tSMP_ACT)(tSMP_CB *p_cb, tSMP_INT_DATA *p_data); + + +#ifdef __cplusplus +extern "C" +{ +#endif + +#if SMP_DYNAMIC_MEMORY == FALSE +extern tSMP_CB smp_cb; +#else +extern tSMP_CB *smp_cb_ptr; +#define smp_cb (*smp_cb_ptr) +#endif + +#ifdef __cplusplus +} +#endif + +/* Functions provided by att_main.c */ +extern void smp_init (void); + +/* smp main */ +extern void smp_sm_event(tSMP_CB *p_cb, tSMP_EVENT event, void *p_data); + +extern void smp_proc_sec_request(tSMP_CB *p_cb, tSMP_INT_DATA *p_data); +extern void smp_set_fail_nc (BOOLEAN enable); +extern void smp_set_fail_conf (BOOLEAN enable); +extern void smp_set_passk_entry_fail(BOOLEAN enable); +extern void smp_set_oob_fail(BOOLEAN enable); +extern void smp_set_peer_sc_notif(BOOLEAN enable); +extern void smp_aes_cmac_rfc4493_chk (UINT8 *key, UINT8 *msg, UINT8 msg_len, + UINT8 mac_len, UINT8 *mac); +extern void smp_f4_calc_chk (UINT8 *U, UINT8 *V, UINT8 *X, UINT8 *Z, UINT8 *mac); +extern void smp_g2_calc_chk (UINT8 *U, UINT8 *V, UINT8 *X, UINT8 *Y); +extern void smp_h6_calc_chk (UINT8 *key, UINT8 *key_id, UINT8 *mac); +extern void smp_f5_key_calc_chk (UINT8 *w, UINT8 *mac); +extern void smp_f5_mackey_or_ltk_calc_chk(UINT8 *t, UINT8 *counter, + UINT8 *key_id, UINT8 *n1, + UINT8 *n2, UINT8 *a1, UINT8 *a2, + UINT8 *length, UINT8 *mac); +extern void smp_f5_calc_chk (UINT8 *w, UINT8 *n1, UINT8 *n2, UINT8 *a1, UINT8 *a2, + UINT8 *mac_key, UINT8 *ltk); +extern void smp_f6_calc_chk (UINT8 *w, UINT8 *n1, UINT8 *n2, UINT8 *r, + UINT8 *iocap, UINT8 *a1, UINT8 *a2, UINT8 *mac); +/* smp_main */ +extern void smp_sm_event(tSMP_CB *p_cb, tSMP_EVENT event, void *p_data); +extern tSMP_STATE smp_get_state(void); +extern void smp_set_state(tSMP_STATE state); + +/* smp_br_main */ +extern void smp_br_state_machine_event(tSMP_CB *p_cb, tSMP_BR_EVENT event, void *p_data); +extern tSMP_BR_STATE smp_get_br_state(void); +extern void smp_set_br_state(tSMP_BR_STATE state); + + +/* smp_act.c */ +extern void smp_send_pair_req(tSMP_CB *p_cb, tSMP_INT_DATA *p_data); +extern void smp_send_confirm(tSMP_CB *p_cb, tSMP_INT_DATA *p_data); +extern void smp_send_pair_fail(tSMP_CB *p_cb, tSMP_INT_DATA *p_data); +extern void smp_send_rand(tSMP_CB *p_cb, tSMP_INT_DATA *p_data); +extern void smp_send_pair_public_key(tSMP_CB *p_cb, tSMP_INT_DATA *p_data); +extern void smp_send_commitment(tSMP_CB *p_cb, tSMP_INT_DATA *p_data); +extern void smp_send_dhkey_check(tSMP_CB *p_cb, tSMP_INT_DATA *p_data); +extern void smp_send_keypress_notification(tSMP_CB *p_cb, tSMP_INT_DATA *p_data); +extern void smp_proc_pair_fail(tSMP_CB *p_cb, tSMP_INT_DATA *p_data); +extern void smp_proc_confirm(tSMP_CB *p_cb, tSMP_INT_DATA *p_data); +extern void smp_proc_rand(tSMP_CB *p_cb, tSMP_INT_DATA *p_data); +extern void smp_process_pairing_public_key(tSMP_CB *p_cb, tSMP_INT_DATA *p_data); +extern void smp_proc_enc_info(tSMP_CB *p_cb, tSMP_INT_DATA *p_data); +extern void smp_proc_master_id(tSMP_CB *p_cb, tSMP_INT_DATA *p_data); +extern void smp_proc_id_info(tSMP_CB *p_cb, tSMP_INT_DATA *p_data); +extern void smp_proc_id_addr(tSMP_CB *p_cb, tSMP_INT_DATA *p_data); +extern void smp_proc_sec_grant(tSMP_CB *p_cb, tSMP_INT_DATA *p_data); +extern void smp_proc_sec_req(tSMP_CB *p_cb, tSMP_INT_DATA *p_data); +extern void smp_proc_sl_key(tSMP_CB *p_cb, tSMP_INT_DATA *p_data); +extern void smp_start_enc(tSMP_CB *p_cb, tSMP_INT_DATA *p_data); +extern void smp_enc_cmpl(tSMP_CB *p_cb, tSMP_INT_DATA *p_data); +extern void smp_proc_discard(tSMP_CB *p_cb, tSMP_INT_DATA *p_data); +extern void smp_pairing_cmpl(tSMP_CB *p_cb, tSMP_INT_DATA *p_data); +extern void smp_decide_association_model(tSMP_CB *p_cb, tSMP_INT_DATA *p_data); +extern void smp_send_app_cback(tSMP_CB *p_cb, tSMP_INT_DATA *p_data); +extern void smp_proc_compare(tSMP_CB *p_cb, tSMP_INT_DATA *p_data); +extern void smp_check_auth_req(tSMP_CB *p_cb, tSMP_INT_DATA *p_data); +extern void smp_process_io_response(tSMP_CB *p_cb, tSMP_INT_DATA *p_data); +extern void smp_send_id_info(tSMP_CB *p_cb, tSMP_INT_DATA *p_data); +extern void smp_send_enc_info(tSMP_CB *p_cb, tSMP_INT_DATA *p_data); +extern void smp_send_csrk_info(tSMP_CB *p_cb, tSMP_INT_DATA *p_data); +extern void smp_send_ltk_reply(tSMP_CB *p_cb, tSMP_INT_DATA *p_data); +extern void smp_proc_pair_cmd(tSMP_CB *p_cb, tSMP_INT_DATA *p_data); +extern void smp_pair_terminate(tSMP_CB *p_cb, tSMP_INT_DATA *p_data); +extern void smp_idle_terminate(tSMP_CB *p_cb, tSMP_INT_DATA *p_data); +extern void smp_send_pair_rsp(tSMP_CB *p_cb, tSMP_INT_DATA *p_data); +extern void smp_key_distribution(tSMP_CB *p_cb, tSMP_INT_DATA *p_data); +extern void smp_proc_srk_info(tSMP_CB *p_cb, tSMP_INT_DATA *p_data); +extern void smp_generate_csrk(tSMP_CB *p_cb, tSMP_INT_DATA *p_data); +extern void smp_fast_conn_param(tSMP_CB *p_cb, tSMP_INT_DATA *p_data); +extern void smp_key_pick_key(tSMP_CB *p_cb, tSMP_INT_DATA *p_data); +extern void smp_both_have_public_keys(tSMP_CB *p_cb, tSMP_INT_DATA *p_data); +extern void smp_start_secure_connection_phase1(tSMP_CB *p_cb, tSMP_INT_DATA *p_data); +extern void smp_process_local_nonce(tSMP_CB *p_cb, tSMP_INT_DATA *p_data); +extern void smp_process_pairing_commitment(tSMP_CB *p_cb, tSMP_INT_DATA *p_data); +extern void smp_process_peer_nonce(tSMP_CB *p_cb, tSMP_INT_DATA *p_data); +extern void smp_process_dhkey_check(tSMP_CB *p_cb, tSMP_INT_DATA *p_data); +extern void smp_match_dhkey_checks(tSMP_CB *p_cb, tSMP_INT_DATA *p_data); +extern void smp_process_keypress_notification(tSMP_CB *p_cb, tSMP_INT_DATA *p_data); +extern void smp_move_to_secure_connections_phase2(tSMP_CB *p_cb, tSMP_INT_DATA *p_data); +extern void smp_phase_2_dhkey_checks_are_present(tSMP_CB *p_cb, tSMP_INT_DATA *p_data); +extern void smp_wait_for_both_public_keys(tSMP_CB *p_cb, tSMP_INT_DATA *p_data); +extern void smp_start_passkey_verification(tSMP_CB *p_cb, tSMP_INT_DATA *p_data); +extern void smp_process_secure_connection_oob_data(tSMP_CB *p_cb, tSMP_INT_DATA *p_data); +extern void smp_process_secure_connection_long_term_key(void); +extern void smp_set_local_oob_keys(tSMP_CB *p_cb, tSMP_INT_DATA *p_data); +extern void smp_set_local_oob_random_commitment(tSMP_CB *p_cb, tSMP_INT_DATA *p_data); +extern void smp_set_derive_link_key(tSMP_CB *p_cb, tSMP_INT_DATA *p_data); +extern void smp_derive_link_key_from_long_term_key(tSMP_CB *p_cb, tSMP_INT_DATA *p_data); +extern void smp_br_process_pairing_command(tSMP_CB *p_cb, tSMP_INT_DATA *p_data); +extern void smp_br_process_security_grant(tSMP_CB *p_cb, tSMP_INT_DATA *p_data); +extern void smp_br_process_slave_keys_response(tSMP_CB *p_cb, tSMP_INT_DATA *p_data); +extern void smp_br_send_pair_response(tSMP_CB *p_cb, tSMP_INT_DATA *p_data); +extern void smp_br_check_authorization_request(tSMP_CB *p_cb, tSMP_INT_DATA *p_data); +extern void smp_br_select_next_key(tSMP_CB *p_cb, tSMP_INT_DATA *p_data); +extern void smp_br_process_link_key(tSMP_CB *p_cb, tSMP_INT_DATA *p_data); +extern void smp_key_distribution_by_transport(tSMP_CB *p_cb, tSMP_INT_DATA *p_data); +extern void smp_br_pairing_complete(tSMP_CB *p_cb, tSMP_INT_DATA *p_data); + +/* smp_l2c */ +extern void smp_l2cap_if_init (void); +extern void smp_data_ind (BD_ADDR bd_addr, BT_HDR *p_buf); + +/* smp_util.c */ +extern BOOLEAN smp_send_cmd(UINT8 cmd_code, tSMP_CB *p_cb); +extern void smp_cb_cleanup(tSMP_CB *p_cb); +extern void smp_reset_control_value(tSMP_CB *p_cb); +extern void smp_proc_pairing_cmpl(tSMP_CB *p_cb); +extern void smp_convert_string_to_tk(BT_OCTET16 tk, UINT32 passkey); +extern void smp_mask_enc_key(UINT8 loc_enc_size, UINT8 * p_data); +extern void smp_rsp_timeout(TIMER_LIST_ENT *p_tle); +extern void smp_xor_128(BT_OCTET16 a, BT_OCTET16 b); +extern BOOLEAN smp_encrypt_data (UINT8 *key, UINT8 key_len, + UINT8 *plain_text, UINT8 pt_len, + tSMP_ENC *p_out); +extern BOOLEAN smp_command_has_invalid_parameters(tSMP_CB *p_cb); +extern void smp_reject_unexpected_pairing_command(BD_ADDR bd_addr); +extern tSMP_ASSO_MODEL smp_select_association_model(tSMP_CB *p_cb); +extern void smp_reverse_array(UINT8 *arr, UINT8 len); +extern UINT8 smp_calculate_random_input(UINT8 *random, UINT8 round); +extern void smp_collect_local_io_capabilities(UINT8 *iocap, tSMP_CB *p_cb); +extern void smp_collect_peer_io_capabilities(UINT8 *iocap, tSMP_CB *p_cb); +extern void smp_collect_local_ble_address(UINT8 *le_addr, tSMP_CB *p_cb); +extern void smp_collect_peer_ble_address(UINT8 *le_addr, tSMP_CB *p_cb); +extern BOOLEAN smp_check_commitment(tSMP_CB *p_cb); +extern void smp_save_secure_connections_long_term_key(tSMP_CB *p_cb); +extern BOOLEAN smp_calculate_f5_mackey_and_long_term_key(tSMP_CB *p_cb); +extern void smp_remove_fixed_channel(tSMP_CB *p_cb); +extern BOOLEAN smp_request_oob_data(tSMP_CB *p_cb); + +/* smp_keys.c */ +extern void smp_generate_srand_mrand_confirm (tSMP_CB *p_cb, tSMP_INT_DATA *p_data); +extern void smp_generate_compare (tSMP_CB *p_cb, tSMP_INT_DATA *p_data); +extern void smp_generate_stk (tSMP_CB *p_cb, tSMP_INT_DATA *p_data); +extern void smp_generate_ltk(tSMP_CB *p_cb, tSMP_INT_DATA *p_data); +extern void smp_generate_passkey (tSMP_CB *p_cb, tSMP_INT_DATA *p_data); +extern void smp_generate_rand_cont(tSMP_CB *p_cb, tSMP_INT_DATA *p_data); +extern void smp_create_private_key(tSMP_CB *p_cb, tSMP_INT_DATA *p_data); +extern void smp_use_oob_private_key(tSMP_CB *p_cb, tSMP_INT_DATA *p_data); +extern void smp_compute_dhkey(tSMP_CB *p_cb); +extern void smp_calculate_local_commitment(tSMP_CB *p_cb); +extern void smp_calculate_peer_commitment(tSMP_CB *p_cb, BT_OCTET16 output_buf); +extern void smp_calculate_numeric_comparison_display_number(tSMP_CB *p_cb, tSMP_INT_DATA *p_data); +extern void smp_calculate_local_dhkey_check(tSMP_CB *p_cb, tSMP_INT_DATA *p_data); +extern void smp_calculate_peer_dhkey_check(tSMP_CB *p_cb, tSMP_INT_DATA *p_data); +extern void smp_start_nonce_generation(tSMP_CB *p_cb); +extern BOOLEAN smp_calculate_link_key_from_long_term_key(tSMP_CB *p_cb); +extern BOOLEAN smp_calculate_long_term_key_from_link_key(tSMP_CB *p_cb); +extern void smp_calculate_f4(UINT8 *u, UINT8 *v, UINT8 *x, UINT8 z, UINT8 *c); +extern UINT32 smp_calculate_g2(UINT8 *u, UINT8 *v, UINT8 *x, UINT8 *y); +extern BOOLEAN smp_calculate_f5(UINT8 *w, UINT8 *n1, UINT8 *n2, UINT8 *a1, UINT8 *a2, + UINT8 *mac_key, UINT8 *ltk); +extern BOOLEAN smp_calculate_f5_mackey_or_long_term_key(UINT8 *t, UINT8 *counter, + UINT8 *key_id, UINT8 *n1, UINT8 *n2, UINT8 *a1, + UINT8 *a2, UINT8 *length, UINT8 *mac); +extern BOOLEAN smp_calculate_f5_key(UINT8 *w, UINT8 *t); +extern BOOLEAN smp_calculate_f6(UINT8 *w, UINT8 *n1, UINT8 *n2, UINT8 *r, UINT8 *iocap, + UINT8 *a1, UINT8 *a2, UINT8 *f3); +extern BOOLEAN smp_calculate_h6(UINT8 *w, UINT8 *keyid, UINT8 *h2); +#if SMP_DEBUG == TRUE +extern void smp_debug_print_nbyte_little_endian (UINT8 *p, const UINT8 *key_name, + UINT8 len); +#endif + +/* smp_cmac.c */ +extern BOOLEAN aes_cipher_msg_auth_code(BT_OCTET16 key, UINT8 *input, UINT16 length, + UINT16 tlen, UINT8 *p_signature); +extern void print128(BT_OCTET16 x, const UINT8 *key_name); + +#endif + +#endif /* SMP_INT_H */ diff --git a/components/bt/bluedroid/stack/l2cap/Kconfig b/components/bt/bluedroid/stack/l2cap/Kconfig new file mode 100644 index 0000000000..e69de29bb2 diff --git a/components/bt/bluedroid/stack/l2cap/l2c_api.c b/components/bt/bluedroid/stack/l2cap/l2c_api.c new file mode 100755 index 0000000000..7f698d6dda --- /dev/null +++ b/components/bt/bluedroid/stack/l2cap/l2c_api.c @@ -0,0 +1,1978 @@ +/****************************************************************************** + * + * Copyright (C) 1999-2012 Broadcom Corporation + * + * 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 L2CAP API code + * + ******************************************************************************/ + +//#define LOG_TAG "bt_l2cap" + +//#include +#include +#include +#include "bt_trace.h" +#include "gki.h" +#include "bt_types.h" +#include "hcidefs.h" +#include "hcimsgs.h" +#include "l2cdefs.h" +#include "l2c_int.h" +#include "btu.h" +#include "btm_api.h" +#include "allocator.h" + +/******************************************************************************* +** +** Function L2CA_Register +** +** Description Other layers call this function to register for L2CAP +** services. +** +** Returns PSM to use or zero if error. Typically, the PSM returned +** is the same as was passed in, but for an outgoing-only +** connection to a dynamic PSM, a "virtual" PSM is returned +** and should be used in the calls to L2CA_ConnectReq(), +** L2CA_ErtmConnectReq() and L2CA_Deregister() +** +*******************************************************************************/ +UINT16 L2CA_Register (UINT16 psm, tL2CAP_APPL_INFO *p_cb_info) +{ + tL2C_RCB *p_rcb; + UINT16 vpsm = psm; + + + /* Verify that the required callback info has been filled in + ** Note: Connection callbacks are required but not checked + ** for here because it is possible to be only a client + ** or only a server. + */ + if ((!p_cb_info->pL2CA_ConfigCfm_Cb) + || (!p_cb_info->pL2CA_ConfigInd_Cb) + || (!p_cb_info->pL2CA_DataInd_Cb) + || (!p_cb_info->pL2CA_DisconnectInd_Cb)) + { + L2CAP_TRACE_ERROR ("L2CAP - no cb registering PSM: 0x%04x", psm); + return (0); + } + + /* Verify PSM is valid */ + if (L2C_INVALID_PSM(psm)) + { + L2CAP_TRACE_ERROR ("L2CAP - invalid PSM value, PSM: 0x%04x", psm); + return (0); + } + + /* Check if this is a registration for an outgoing-only connection to */ + /* a dynamic PSM. If so, allocate a "virtual" PSM for the app to use. */ + if ( (psm >= 0x1001) && (p_cb_info->pL2CA_ConnectInd_Cb == NULL) ) + { + for (vpsm = 0x1002; vpsm < 0x8000; vpsm += 2) + { + if ((p_rcb = l2cu_find_rcb_by_psm (vpsm)) == NULL) + break; + } + + //L2CAP_TRACE_API ("L2CA_Register - Real PSM: 0x%04x Virtual PSM: 0x%04x", psm, vpsm); + } + + /* If registration block already there, just overwrite it */ + if ((p_rcb = l2cu_find_rcb_by_psm (vpsm)) == NULL) + { + if ((p_rcb = l2cu_allocate_rcb (vpsm)) == NULL) + { + L2CAP_TRACE_WARNING ("L2CAP - no RCB available, PSM: 0x%04x vPSM: 0x%04x", psm, vpsm); + return (0); + } + } + + p_rcb->api = *p_cb_info; + p_rcb->real_psm = psm; + + return (vpsm); +} + + + +/******************************************************************************* +** +** Function L2CA_Deregister +** +** Description Other layers call this function to de-register for L2CAP +** services. +** +** Returns void +** +*******************************************************************************/ +void L2CA_Deregister (UINT16 psm) +{ + tL2C_RCB *p_rcb; + tL2C_CCB *p_ccb; + tL2C_LCB *p_lcb; + int ii; + + + if ((p_rcb = l2cu_find_rcb_by_psm (psm)) != NULL) + { + p_lcb = &l2cb.lcb_pool[0]; + for (ii = 0; ii < MAX_L2CAP_LINKS; ii++, p_lcb++) + { + if (p_lcb->in_use) + { + if (((p_ccb = p_lcb->ccb_queue.p_first_ccb) == NULL) + || (p_lcb->link_state == LST_DISCONNECTING)) + continue; + + if ((p_ccb->in_use) && + ((p_ccb->chnl_state == CST_W4_L2CAP_DISCONNECT_RSP) || + (p_ccb->chnl_state == CST_W4_L2CA_DISCONNECT_RSP))) + continue; + + if (p_ccb->p_rcb == p_rcb) + l2c_csm_execute (p_ccb, L2CEVT_L2CA_DISCONNECT_REQ, NULL); + } + } + l2cu_release_rcb (p_rcb); + } + else + { + L2CAP_TRACE_WARNING ("L2CAP - PSM: 0x%04x not found for deregistration", psm); + } +} + +/******************************************************************************* +** +** Function L2CA_AllocatePSM +** +** Description Other layers call this function to find an unused PSM for L2CAP +** services. +** +** Returns PSM to use. +** +*******************************************************************************/ +UINT16 L2CA_AllocatePSM(void) +{ + BOOLEAN done = FALSE; + UINT16 psm = l2cb.dyn_psm; + + while (!done) + { + psm += 2; + if (psm > 0xfeff) + { + psm = 0x1001; + } + else if (psm & 0x0100) + { + /* the upper byte must be even */ + psm += 0x0100; + } + + /* if psm is in range of reserved BRCM Aware features */ + if ((BRCM_RESERVED_PSM_START <= psm)&&(psm <= BRCM_RESERVED_PSM_END)) + continue; + + /* make sure the newlly allocated psm is not used right now */ + if ((l2cu_find_rcb_by_psm (psm)) == NULL) + done = TRUE; + } + l2cb.dyn_psm = psm; + + return(psm); +} + +/******************************************************************************* +** +** Function L2CA_ConnectReq +** +** Description Higher layers call this function to create an L2CAP connection. +** Note that the connection is not established at this time, but +** connection establishment gets started. The callback function +** will be invoked when connection establishes or fails. +** +** Returns the CID of the connection, or 0 if it failed to start +** +*******************************************************************************/ +UINT16 L2CA_ConnectReq (UINT16 psm, BD_ADDR p_bd_addr) +{ + return L2CA_ErtmConnectReq (psm, p_bd_addr, NULL); +} + +/******************************************************************************* +** +** Function L2CA_ErtmConnectReq +** +** Description Higher layers call this function to create an L2CAP connection. +** Note that the connection is not established at this time, but +** connection establishment gets started. The callback function +** will be invoked when connection establishes or fails. +** +** Parameters: PSM: L2CAP PSM for the connection +** BD address of the peer +** Enhaced retransmission mode configurations + +** Returns the CID of the connection, or 0 if it failed to start +** +*******************************************************************************/ +UINT16 L2CA_ErtmConnectReq (UINT16 psm, BD_ADDR p_bd_addr, tL2CAP_ERTM_INFO *p_ertm_info) +{ + tL2C_LCB *p_lcb; + tL2C_CCB *p_ccb; + tL2C_RCB *p_rcb; + + //counter_add("l2cap.conn.req", 1); + L2CAP_TRACE_API ("L2CA_ErtmConnectReq() PSM: 0x%04x BDA: %08x%04x p_ertm_info: 0x%08x allowed:0x%x preferred:%d", psm, + (p_bd_addr[0]<<24)+(p_bd_addr[1]<<16)+(p_bd_addr[2]<<8)+p_bd_addr[3], + (p_bd_addr[4]<<8)+p_bd_addr[5], p_ertm_info, + (p_ertm_info) ? p_ertm_info->allowed_modes : 0, + (p_ertm_info) ? p_ertm_info->preferred_mode : 0); + + /* Fail if we have not established communications with the controller */ + if (!BTM_IsDeviceUp()) + { + L2CAP_TRACE_WARNING ("L2CAP connect req - BTU not ready"); + return (0); + } + /* Fail if the PSM is not registered */ + if ((p_rcb = l2cu_find_rcb_by_psm (psm)) == NULL) + { + L2CAP_TRACE_WARNING ("L2CAP - no RCB for L2CA_conn_req, PSM: 0x%04x", psm); + return (0); + } + + /* First, see if we already have a link to the remote */ + /* assume all ERTM l2cap connection is going over BR/EDR for now */ + if ((p_lcb = l2cu_find_lcb_by_bd_addr (p_bd_addr, BT_TRANSPORT_BR_EDR)) == NULL) + { + /* No link. Get an LCB and start link establishment */ + if ( ((p_lcb = l2cu_allocate_lcb (p_bd_addr, FALSE, BT_TRANSPORT_BR_EDR)) == NULL) + /* currently use BR/EDR for ERTM mode l2cap connection */ + || (l2cu_create_conn(p_lcb, BT_TRANSPORT_BR_EDR) == FALSE) ) + { + L2CAP_TRACE_WARNING ("L2CAP - conn not started for PSM: 0x%04x p_lcb: 0x%08x", psm, p_lcb); + return (0); + } + } + + /* Allocate a channel control block */ + if ((p_ccb = l2cu_allocate_ccb (p_lcb, 0)) == NULL) + { + L2CAP_TRACE_WARNING ("L2CAP - no CCB for L2CA_conn_req, PSM: 0x%04x", psm); + return (0); + } + + /* Save registration info */ + p_ccb->p_rcb = p_rcb; + + if (p_ertm_info) + { + p_ccb->ertm_info = *p_ertm_info; + + /* Replace default indicators with the actual default pool */ + if (p_ccb->ertm_info.fcr_rx_pool_id == L2CAP_DEFAULT_ERM_POOL_ID) + p_ccb->ertm_info.fcr_rx_pool_id = L2CAP_FCR_RX_POOL_ID; + + if (p_ccb->ertm_info.fcr_tx_pool_id == L2CAP_DEFAULT_ERM_POOL_ID) + p_ccb->ertm_info.fcr_tx_pool_id = L2CAP_FCR_TX_POOL_ID; + + if (p_ccb->ertm_info.user_rx_pool_id == L2CAP_DEFAULT_ERM_POOL_ID) + p_ccb->ertm_info.user_rx_pool_id = HCI_ACL_POOL_ID; + + if (p_ccb->ertm_info.user_tx_pool_id == L2CAP_DEFAULT_ERM_POOL_ID) + p_ccb->ertm_info.user_tx_pool_id = HCI_ACL_POOL_ID; + + p_ccb->max_rx_mtu = GKI_get_pool_bufsize (p_ertm_info->user_rx_pool_id) - + (L2CAP_MIN_OFFSET + L2CAP_SDU_LEN_OFFSET + L2CAP_FCS_LEN); + } + + /* If link is up, start the L2CAP connection */ + if (p_lcb->link_state == LST_CONNECTED) + { + l2c_csm_execute (p_ccb, L2CEVT_L2CA_CONNECT_REQ, NULL); + } + + /* If link is disconnecting, save link info to retry after disconnect + * Possible Race condition when a reconnect occurs + * on the channel during a disconnect of link. This + * ccb will be automatically retried after link disconnect + * arrives + */ + else if (p_lcb->link_state == LST_DISCONNECTING) + { + L2CAP_TRACE_DEBUG ("L2CAP API - link disconnecting: RETRY LATER"); + + /* Save ccb so it can be started after disconnect is finished */ + p_lcb->p_pending_ccb = p_ccb; + } + + L2CAP_TRACE_API ("L2CAP - L2CA_conn_req(psm: 0x%04x) returned CID: 0x%04x", psm, p_ccb->local_cid); + + /* Return the local CID as our handle */ + return (p_ccb->local_cid); +} + +bool L2CA_SetConnectionCallbacks(uint16_t local_cid, const tL2CAP_APPL_INFO *callbacks) { + assert(callbacks != NULL); + assert(callbacks->pL2CA_ConnectInd_Cb == NULL); + assert(callbacks->pL2CA_ConnectCfm_Cb != NULL); + assert(callbacks->pL2CA_ConfigInd_Cb != NULL); + assert(callbacks->pL2CA_ConfigCfm_Cb != NULL); + assert(callbacks->pL2CA_DisconnectInd_Cb != NULL); + assert(callbacks->pL2CA_DisconnectCfm_Cb != NULL); + assert(callbacks->pL2CA_CongestionStatus_Cb != NULL); + assert(callbacks->pL2CA_DataInd_Cb != NULL); + assert(callbacks->pL2CA_TxComplete_Cb != NULL); + + tL2C_CCB *channel_control_block = l2cu_find_ccb_by_cid(NULL, local_cid); + if (!channel_control_block) { + LOG_ERROR("%s no channel control block found for L2CAP LCID=0x%04x.", __func__, local_cid); + return false; + } + + // We're making a connection-specific registration control block so we check if + // we already have a private one allocated to us on the heap. If not, we make a + // new allocation, mark it as heap-allocated, and inherit the fields from the old + // control block. + tL2C_RCB *registration_control_block = channel_control_block->p_rcb; + if (!channel_control_block->should_free_rcb) { + registration_control_block = (tL2C_RCB *)osi_calloc(sizeof(tL2C_RCB)); + if (!registration_control_block) { + LOG_ERROR("%s unable to allocate registration control block.", __func__); + return false; + } + + *registration_control_block = *channel_control_block->p_rcb; + channel_control_block->p_rcb = registration_control_block; + channel_control_block->should_free_rcb = true; + } + + registration_control_block->api = *callbacks; + return true; +} + +/******************************************************************************* +** +** Function L2CA_ConnectRsp +** +** Description Higher layers call this function to accept an incoming +** L2CAP connection, for which they had gotten an connect +** indication callback. +** +** Returns TRUE for success, FALSE for failure +** +*******************************************************************************/ +BOOLEAN L2CA_ConnectRsp (BD_ADDR p_bd_addr, UINT8 id, UINT16 lcid, + UINT16 result, UINT16 status) +{ + return L2CA_ErtmConnectRsp (p_bd_addr, id, lcid, result, status, NULL); +} + + +/******************************************************************************* +** +** Function L2CA_ErtmConnectRsp +** +** Description Higher layers call this function to accept an incoming +** L2CAP connection, for which they had gotten an connect +** indication callback. +** +** Returns TRUE for success, FALSE for failure +** +*******************************************************************************/ +BOOLEAN L2CA_ErtmConnectRsp (BD_ADDR p_bd_addr, UINT8 id, UINT16 lcid, UINT16 result, + UINT16 status, tL2CAP_ERTM_INFO *p_ertm_info) +{ + tL2C_LCB *p_lcb; + tL2C_CCB *p_ccb; + + //counter_add("l2cap.conn.rsp", 1); + L2CAP_TRACE_API ("L2CA_ErtmConnectRsp() CID: 0x%04x Result: %d Status: %d BDA: %08x%04x p_ertm_info:0x%08x", + lcid, result, status, + (p_bd_addr[0]<<24)+(p_bd_addr[1]<<16)+(p_bd_addr[2]<<8)+p_bd_addr[3], + (p_bd_addr[4]<<8)+p_bd_addr[5], p_ertm_info); + + /* First, find the link control block */ + if ((p_lcb = l2cu_find_lcb_by_bd_addr (p_bd_addr, BT_TRANSPORT_BR_EDR)) == NULL) + { + /* No link. Get an LCB and start link establishment */ + L2CAP_TRACE_WARNING ("L2CAP - no LCB for L2CA_conn_rsp"); + return (FALSE); + } + + /* Now, find the channel control block */ + if ((p_ccb = l2cu_find_ccb_by_cid (p_lcb, lcid)) == NULL) + { + L2CAP_TRACE_WARNING ("L2CAP - no CCB for L2CA_conn_rsp"); + return (FALSE); + } + + /* The IDs must match */ + if (p_ccb->remote_id != id) + { + L2CAP_TRACE_WARNING ("L2CAP - bad id in L2CA_conn_rsp. Exp: %d Got: %d", p_ccb->remote_id, id); + return (FALSE); + } + + if (p_ertm_info) + { + p_ccb->ertm_info = *p_ertm_info; + + /* Replace default indicators with the actual default pool */ + if (p_ccb->ertm_info.fcr_rx_pool_id == L2CAP_DEFAULT_ERM_POOL_ID) + p_ccb->ertm_info.fcr_rx_pool_id = L2CAP_FCR_RX_POOL_ID; + + if (p_ccb->ertm_info.fcr_tx_pool_id == L2CAP_DEFAULT_ERM_POOL_ID) + p_ccb->ertm_info.fcr_tx_pool_id = L2CAP_FCR_TX_POOL_ID; + + if (p_ccb->ertm_info.user_rx_pool_id == L2CAP_DEFAULT_ERM_POOL_ID) + p_ccb->ertm_info.user_rx_pool_id = HCI_ACL_POOL_ID; + + if (p_ccb->ertm_info.user_tx_pool_id == L2CAP_DEFAULT_ERM_POOL_ID) + p_ccb->ertm_info.user_tx_pool_id = HCI_ACL_POOL_ID; + + p_ccb->max_rx_mtu = GKI_get_pool_bufsize (p_ertm_info->user_rx_pool_id) - (L2CAP_MIN_OFFSET + L2CAP_SDU_LEN_OFFSET + L2CAP_FCS_LEN); + } + + if (result == L2CAP_CONN_OK) + { + l2c_csm_execute (p_ccb, L2CEVT_L2CA_CONNECT_RSP, NULL); + } + else + { + tL2C_CONN_INFO conn_info; + + conn_info.l2cap_result = result; + conn_info.l2cap_status = status; + + if (result == L2CAP_CONN_PENDING) + l2c_csm_execute (p_ccb, L2CEVT_L2CA_CONNECT_RSP, &conn_info); + else + l2c_csm_execute (p_ccb, L2CEVT_L2CA_CONNECT_RSP_NEG, &conn_info); + } + + return (TRUE); +} + + +/******************************************************************************* +** +** Function L2CA_ConfigReq +** +** Description Higher layers call this function to send configuration. +** +** Note: The FCR options of p_cfg are not used. +** +** Returns TRUE if configuration sent, else FALSE +** +*******************************************************************************/ +BOOLEAN L2CA_ConfigReq (UINT16 cid, tL2CAP_CFG_INFO *p_cfg) +{ + tL2C_CCB *p_ccb; + + //counter_add("l2cap.cfg.req", 1); + L2CAP_TRACE_API ("L2CA_ConfigReq() CID 0x%04x: fcr_present:%d (mode %d) mtu_present:%d (%d)", + cid, p_cfg->fcr_present, p_cfg->fcr.mode, p_cfg->mtu_present, p_cfg->mtu); + + /* Find the channel control block. We don't know the link it is on. */ + if ((p_ccb = l2cu_find_ccb_by_cid (NULL, cid)) == NULL) + { + L2CAP_TRACE_WARNING ("L2CAP - no CCB for L2CA_cfg_req, CID: %d", cid); + return (FALSE); + } + + /* We need to have at least one mode type common with the peer */ + if (!l2c_fcr_adj_our_req_options(p_ccb, p_cfg)) + return (FALSE); + + /* Don't adjust FCR options if not used */ + if ((!p_cfg->fcr_present)||(p_cfg->fcr.mode == L2CAP_FCR_BASIC_MODE)) + { + /* FCR and FCS options are not used in basic mode */ + p_cfg->fcs_present = FALSE; + p_cfg->ext_flow_spec_present = FALSE; + + if ( (p_cfg->mtu_present) && (p_cfg->mtu > L2CAP_MTU_SIZE) ) + { + L2CAP_TRACE_WARNING ("L2CAP - adjust MTU: %u too large", p_cfg->mtu); + p_cfg->mtu = L2CAP_MTU_SIZE; + } + } + + /* Save the adjusted configuration in case it needs to be used for renegotiation */ + p_ccb->our_cfg = *p_cfg; + + l2c_csm_execute (p_ccb, L2CEVT_L2CA_CONFIG_REQ, p_cfg); + + return (TRUE); +} + + +/******************************************************************************* +** +** Function L2CA_ConfigRsp +** +** Description Higher layers call this function to send a configuration +** response. +** +** Returns TRUE if configuration response sent, else FALSE +** +*******************************************************************************/ +BOOLEAN L2CA_ConfigRsp (UINT16 cid, tL2CAP_CFG_INFO *p_cfg) +{ + tL2C_CCB *p_ccb; + + //counter_add("l2cap.cfg.rsp", 1); + L2CAP_TRACE_API ("L2CA_ConfigRsp() CID: 0x%04x Result: %d MTU present:%d Flush TO:%d FCR:%d FCS:%d", + cid, p_cfg->result, p_cfg->mtu_present, p_cfg->flush_to_present, p_cfg->fcr_present, p_cfg->fcs_present); + + /* Find the channel control block. We don't know the link it is on. */ + if ((p_ccb = l2cu_find_ccb_by_cid (NULL, cid)) == NULL) + { + L2CAP_TRACE_WARNING ("L2CAP - no CCB for L2CA_cfg_rsp, CID: %d", cid); + return (FALSE); + } + + if ( (p_cfg->result == L2CAP_CFG_OK) || (p_cfg->result == L2CAP_CFG_PENDING) ) + l2c_csm_execute (p_ccb, L2CEVT_L2CA_CONFIG_RSP, p_cfg); + else + { + p_cfg->fcr_present = FALSE; /* FCR options already negotiated before this point */ + + /* Clear out any cached options that are being returned as an error (excluding FCR) */ + if (p_cfg->mtu_present) + p_ccb->peer_cfg.mtu_present = FALSE; + if (p_cfg->flush_to_present) + p_ccb->peer_cfg.flush_to_present = FALSE; + if (p_cfg->qos_present) + p_ccb->peer_cfg.qos_present = FALSE; + + l2c_csm_execute (p_ccb, L2CEVT_L2CA_CONFIG_RSP_NEG, p_cfg); + } + + return (TRUE); +} + + +/******************************************************************************* +** +** Function L2CA_DisconnectReq +** +** Description Higher layers call this function to disconnect a channel. +** +** Returns TRUE if disconnect sent, else FALSE +** +*******************************************************************************/ +BOOLEAN L2CA_DisconnectReq (UINT16 cid) +{ + tL2C_CCB *p_ccb; + + //counter_add("l2cap.disconn.req", 1); + L2CAP_TRACE_API ("L2CA_DisconnectReq() CID: 0x%04x", cid); + + /* Find the channel control block. We don't know the link it is on. */ + if ((p_ccb = l2cu_find_ccb_by_cid (NULL, cid)) == NULL) + { + L2CAP_TRACE_WARNING ("L2CAP - no CCB for L2CA_disc_req, CID: %d", cid); + return (FALSE); + } + + l2c_csm_execute (p_ccb, L2CEVT_L2CA_DISCONNECT_REQ, NULL); + + return (TRUE); +} + +/******************************************************************************* +** +** Function L2CA_DisconnectRsp +** +** Description Higher layers call this function to acknowledge the +** disconnection of a channel. +** +** Returns void +** +*******************************************************************************/ +BOOLEAN L2CA_DisconnectRsp (UINT16 cid) +{ + tL2C_CCB *p_ccb; + + //counter_add("l2cap.disconn.rsp", 1); + L2CAP_TRACE_API ("L2CA_DisconnectRsp() CID: 0x%04x", cid); + + /* Find the channel control block. We don't know the link it is on. */ + if ((p_ccb = l2cu_find_ccb_by_cid (NULL, cid)) == NULL) + { + L2CAP_TRACE_WARNING ("L2CAP - no CCB for L2CA_disc_rsp, CID: %d", cid); + return (FALSE); + } + + l2c_csm_execute (p_ccb, L2CEVT_L2CA_DISCONNECT_RSP, NULL); + + return (TRUE); +} + +/******************************************************************************* +** +** Function L2CA_Ping +** +** Description Higher layers call this function to send an echo request. +** +** Returns TRUE if echo request sent, else FALSE. +** +*******************************************************************************/ +BOOLEAN L2CA_Ping (BD_ADDR p_bd_addr, tL2CA_ECHO_RSP_CB *p_callback) +{ + tL2C_LCB *p_lcb; + + L2CAP_TRACE_API ("L2CA_Ping() BDA: %02x-%02x-%02x-%02x-%02x-%02x", + p_bd_addr[0], p_bd_addr[1], p_bd_addr[2], p_bd_addr[3], p_bd_addr[4], p_bd_addr[5]); + + /* Fail if we have not established communications with the controller */ + if (!BTM_IsDeviceUp()) + return (FALSE); + + /* First, see if we already have a link to the remote */ + if ((p_lcb = l2cu_find_lcb_by_bd_addr (p_bd_addr, BT_TRANSPORT_BR_EDR)) == NULL) + { + /* No link. Get an LCB and start link establishment */ + if ((p_lcb = l2cu_allocate_lcb (p_bd_addr, FALSE, BT_TRANSPORT_BR_EDR)) == NULL) + { + L2CAP_TRACE_WARNING ("L2CAP - no LCB for L2CA_ping"); + return (FALSE); + } + if (l2cu_create_conn(p_lcb, BT_TRANSPORT_BR_EDR) == FALSE) + { + return (FALSE); + } + + p_lcb->p_echo_rsp_cb = p_callback; + + return (TRUE); + } + + /* We only allow 1 ping outstanding at a time */ + if (p_lcb->p_echo_rsp_cb != NULL) + { + L2CAP_TRACE_WARNING ("L2CAP - rejected second L2CA_ping"); + return (FALSE); + } + + /* Have a link control block. If link is disconnecting, tell user to retry later */ + if (p_lcb->link_state == LST_DISCONNECTING) + { + L2CAP_TRACE_WARNING ("L2CAP - L2CA_ping rejected - link disconnecting"); + return (FALSE); + } + + /* Save address of callback */ + p_lcb->p_echo_rsp_cb = p_callback; + + if (p_lcb->link_state == LST_CONNECTED) + { + l2cu_adj_id(p_lcb, L2CAP_ADJ_BRCM_ID); /* Make sure not using Broadcom ID */ + l2cu_send_peer_echo_req (p_lcb, NULL, 0); + btu_start_timer (&p_lcb->timer_entry, BTU_TTYPE_L2CAP_LINK, L2CAP_ECHO_RSP_TOUT); + } + + return (TRUE); +} + +/******************************************************************************* +** +** Function L2CA_Echo +** +** Description Higher layers call this function to send an echo request +** with application-specific data. +** +** Returns TRUE if echo request sent, else FALSE. +** +*******************************************************************************/ +BOOLEAN L2CA_Echo (BD_ADDR p_bd_addr, BT_HDR *p_data, tL2CA_ECHO_DATA_CB *p_callback) +{ + tL2C_LCB *p_lcb; + UINT8 *pp; + + L2CAP_TRACE_API ("L2CA_Echo() BDA: %08X%04X", + ((p_bd_addr[0] << 24) + (p_bd_addr[1] << 16) + (p_bd_addr[2] << 8) + (p_bd_addr[3])), + ((p_bd_addr[4] << 8) + (p_bd_addr[5]))); + + /* Fail if we have not established communications with the controller */ + if (!BTM_IsDeviceUp()) + return (FALSE); + + if ((memcmp(BT_BD_ANY, p_bd_addr, BD_ADDR_LEN) == 0) && (p_data == NULL)) + { + /* Only register callback without sending message. */ + l2cb.p_echo_data_cb = p_callback; + return TRUE; + } + + /* We assume the upper layer will call this function only when the link is established. */ + if ((p_lcb = l2cu_find_lcb_by_bd_addr (p_bd_addr, BT_TRANSPORT_BR_EDR)) == NULL) + { + L2CAP_TRACE_ERROR ("L2CA_Echo ERROR : link not established"); + return FALSE; + } + + if (p_lcb->link_state != LST_CONNECTED) + { + L2CAP_TRACE_ERROR ("L2CA_Echo ERROR : link is not connected"); + return FALSE; + } + + /* Save address of callback */ + l2cb.p_echo_data_cb = p_callback; + + /* Set the pointer to the beginning of the data */ + pp = (UINT8 *)(p_data + 1) + p_data->offset; + l2cu_adj_id(p_lcb, L2CAP_ADJ_BRCM_ID); /* Make sure not using Broadcom ID */ + l2cu_send_peer_echo_req (p_lcb, pp, p_data->len); + + return (TRUE); + +} + +bool L2CA_GetIdentifiers(uint16_t lcid, uint16_t *rcid, uint16_t *handle) { + tL2C_CCB *control_block = l2cu_find_ccb_by_cid(NULL, lcid); + if (!control_block) + return false; + + if (rcid) + *rcid = control_block->remote_cid; + if (handle) + *handle = control_block->p_lcb->handle; + + return true; +} + +/******************************************************************************* +** +** Function L2CA_SetIdleTimeout +** +** Description Higher layers call this function to set the idle timeout for +** a connection, or for all future connections. The "idle timeout" +** is the amount of time that a connection can remain up with +** no L2CAP channels on it. A timeout of zero means that the +** connection will be torn down immediately when the last channel +** is removed. A timeout of 0xFFFF means no timeout. Values are +** in seconds. +** +** Returns TRUE if command succeeded, FALSE if failed +** +** NOTE This timeout takes effect after at least 1 channel has been +** established and removed. L2CAP maintains its own timer from +** whan a connection is established till the first channel is +** set up. +*******************************************************************************/ +BOOLEAN L2CA_SetIdleTimeout (UINT16 cid, UINT16 timeout, BOOLEAN is_global) +{ + tL2C_CCB *p_ccb; + tL2C_LCB *p_lcb; + + if (is_global) + { + l2cb.idle_timeout = timeout; + } + else + { + /* Find the channel control block. We don't know the link it is on. */ + if ((p_ccb = l2cu_find_ccb_by_cid (NULL, cid)) == NULL) + { + L2CAP_TRACE_WARNING ("L2CAP - no CCB for L2CA_SetIdleTimeout, CID: %d", cid); + return (FALSE); + } + + p_lcb = p_ccb->p_lcb; + + if ((p_lcb) && (p_lcb->in_use) && (p_lcb->link_state == LST_CONNECTED)) + p_lcb->idle_timeout = timeout; + else + return (FALSE); + } + + return (TRUE); +} + +/******************************************************************************* +** +** Function L2CA_SetIdleTimeoutByBdAddr +** +** Description Higher layers call this function to set the idle timeout for +** a connection. The "idle timeout" is the amount of time that +** a connection can remain up with no L2CAP channels on it. +** A timeout of zero means that the connection will be torn +** down immediately when the last channel is removed. +** A timeout of 0xFFFF means no timeout. Values are in seconds. +** A bd_addr is the remote BD address. If bd_addr = BT_BD_ANY, +** then the idle timeouts for all active l2cap links will be +** changed. +** +** Returns TRUE if command succeeded, FALSE if failed +** +** NOTE This timeout applies to all logical channels active on the +** ACL link. +*******************************************************************************/ +BOOLEAN L2CA_SetIdleTimeoutByBdAddr(BD_ADDR bd_addr, UINT16 timeout, tBT_TRANSPORT transport) +{ + tL2C_LCB *p_lcb; + + if (memcmp (BT_BD_ANY, bd_addr, BD_ADDR_LEN)) + { + p_lcb = l2cu_find_lcb_by_bd_addr( bd_addr, transport); + if ((p_lcb) && (p_lcb->in_use) && (p_lcb->link_state == LST_CONNECTED)) + { + p_lcb->idle_timeout = timeout; + + if (!p_lcb->ccb_queue.p_first_ccb) + l2cu_no_dynamic_ccbs (p_lcb); + } + else + return FALSE; + } + else + { + int xx; + tL2C_LCB *p_lcb = &l2cb.lcb_pool[0]; + + for (xx = 0; xx < MAX_L2CAP_LINKS; xx++, p_lcb++) + { + if ((p_lcb->in_use) && (p_lcb->link_state == LST_CONNECTED)) + { + p_lcb->idle_timeout = timeout; + + if (!p_lcb->ccb_queue.p_first_ccb) + l2cu_no_dynamic_ccbs (p_lcb); + } + } + } + + return TRUE; +} + +/******************************************************************************* +** +** Function L2CA_SetTraceLevel +** +** Description This function sets the trace level for L2CAP. If called with +** a value of 0xFF, it simply reads the current trace level. +** +** Returns the new (current) trace level +** +*******************************************************************************/ +UINT8 L2CA_SetTraceLevel (UINT8 new_level) +{ + if (new_level != 0xFF) + l2cb.l2cap_trace_level = new_level; + + return (l2cb.l2cap_trace_level); +} + + +/******************************************************************************* +** +** Function L2CA_SetDesireRole +** +** Description This function sets the desire role for L2CAP. +** If the new role is L2CAP_ROLE_ALLOW_SWITCH, allow switch on +** HciCreateConnection. +** If the new role is L2CAP_ROLE_DISALLOW_SWITCH, do not allow switch on +** HciCreateConnection. +** +** If the new role is a valid role (HCI_ROLE_MASTER or HCI_ROLE_SLAVE), +** the desire role is set to the new value. Otherwise, it is not changed. +** +** Returns the new (current) role +** +*******************************************************************************/ +UINT8 L2CA_SetDesireRole (UINT8 new_role) +{ + L2CAP_TRACE_API ("L2CA_SetDesireRole() new:x%x, disallow_switch:%d", + new_role, l2cb.disallow_switch); + + if (L2CAP_ROLE_CHECK_SWITCH != (L2CAP_ROLE_CHECK_SWITCH & new_role)) + { + /* do not process the allow_switch when both bits are set */ + if (new_role & L2CAP_ROLE_ALLOW_SWITCH) + { + l2cb.disallow_switch = FALSE; + } + if (new_role & L2CAP_ROLE_DISALLOW_SWITCH) + { + l2cb.disallow_switch = TRUE; + } + } + + if (new_role == HCI_ROLE_MASTER || new_role == HCI_ROLE_SLAVE) + l2cb.desire_role = new_role; + + return (l2cb.desire_role); +} + +/******************************************************************************* +** +** Function L2CA_LocalLoopbackReq +** +** Description This function sets up a CID for local loopback +** +** Returns CID of 0 if none. +** +*******************************************************************************/ +UINT16 L2CA_LocalLoopbackReq (UINT16 psm, UINT16 handle, BD_ADDR p_bd_addr) +{ + tL2C_LCB *p_lcb; + tL2C_CCB *p_ccb; + tL2C_RCB *p_rcb; + + L2CAP_TRACE_API ("L2CA_LocalLoopbackReq() PSM: %d Handle: 0x%04x", psm, handle); + + /* Fail if we have not established communications with the controller */ + if (!BTM_IsDeviceUp()) + { + L2CAP_TRACE_WARNING ("L2CAP loop req - BTU not ready"); + return (0); + } + + /* Fail if the PSM is not registered */ + if ((p_rcb = l2cu_find_rcb_by_psm (psm)) == NULL) + { + L2CAP_TRACE_WARNING ("L2CAP - no RCB for L2CA_conn_req, PSM: %d", psm); + return (0); + } + + if ((p_lcb = l2cu_allocate_lcb (p_bd_addr, FALSE, BT_TRANSPORT_BR_EDR)) == NULL) + { + L2CAP_TRACE_WARNING ("L2CAP - no LCB for L2CA_conn_req"); + return (0); + } + + p_lcb->link_state = LST_CONNECTED; + p_lcb->handle = handle; + + /* Allocate a channel control block */ + if ((p_ccb = l2cu_allocate_ccb (p_lcb, 0)) == NULL) + { + L2CAP_TRACE_WARNING ("L2CAP - no CCB for L2CA_conn_req"); + return (0); + } + + /* Save registration info */ + p_ccb->p_rcb = p_rcb; + p_ccb->chnl_state = CST_OPEN; + p_ccb->remote_cid = p_ccb->local_cid; + p_ccb->config_done = CFG_DONE_MASK; + + /* Return the local CID as our handle */ + return (p_ccb->local_cid); +} + +/******************************************************************************* +** +** Function L2CA_SetAclPriority +** +** Description Sets the transmission priority for a channel. +** (For initial implementation only two values are valid. +** L2CAP_PRIORITY_NORMAL and L2CAP_PRIORITY_HIGH). +** +** Returns TRUE if a valid channel, else FALSE +** +*******************************************************************************/ +BOOLEAN L2CA_SetAclPriority (BD_ADDR bd_addr, UINT8 priority) +{ + L2CAP_TRACE_API ("L2CA_SetAclPriority() bdaddr: %02x%02x%02x%02x%04x, priority:%d", + bd_addr[0], bd_addr[1], bd_addr[2], + bd_addr[3], (bd_addr[4] << 8) + bd_addr[5], priority); + + return (l2cu_set_acl_priority(bd_addr, priority, FALSE)); +} + +/******************************************************************************* +** +** Function L2CA_FlowControl +** +** Description Higher layers call this function to flow control a channel. +** +** data_enabled - TRUE data flows, FALSE data is stopped +** +** Returns TRUE if valid channel, else FALSE +** +*******************************************************************************/ +BOOLEAN L2CA_FlowControl (UINT16 cid, BOOLEAN data_enabled) +{ + tL2C_CCB *p_ccb; + BOOLEAN on_off = !data_enabled; + + L2CAP_TRACE_API ("L2CA_FlowControl(%d) CID: 0x%04x", on_off, cid); + + /* Find the channel control block. We don't know the link it is on. */ + if ((p_ccb = l2cu_find_ccb_by_cid (NULL, cid)) == NULL) + { + L2CAP_TRACE_WARNING ("L2CAP - no CCB for L2CA_FlowControl, CID: 0x%04x data_enabled: %d", cid, data_enabled); + return (FALSE); + } + + if (p_ccb->peer_cfg.fcr.mode != L2CAP_FCR_ERTM_MODE) + { + L2CAP_TRACE_EVENT ("L2CA_FlowControl() invalid mode:%d", p_ccb->peer_cfg.fcr.mode); + return (FALSE); + } + if (p_ccb->fcrb.local_busy != on_off) + { + p_ccb->fcrb.local_busy = on_off; + + if ( (p_ccb->chnl_state == CST_OPEN) && (!p_ccb->fcrb.wait_ack) ) + { + if (on_off) + l2c_fcr_send_S_frame (p_ccb, L2CAP_FCR_SUP_RNR, 0); + else + l2c_fcr_send_S_frame (p_ccb, L2CAP_FCR_SUP_RR, L2CAP_FCR_P_BIT); + } + } + + return (TRUE); +} + +/******************************************************************************* +** +** Function L2CA_SendTestSFrame +** +** Description Higher layers call this function to send a test S-frame. +** +** Returns TRUE if valid Channel, else FALSE +** +*******************************************************************************/ +BOOLEAN L2CA_SendTestSFrame (UINT16 cid, UINT8 sup_type, UINT8 back_track) +{ + tL2C_CCB *p_ccb; + + L2CAP_TRACE_API ("L2CA_SendTestSFrame() CID: 0x%04x Type: 0x%02x back_track: %u", cid, sup_type, back_track); + + /* Find the channel control block. We don't know the link it is on. */ + if ((p_ccb = l2cu_find_ccb_by_cid (NULL, cid)) == NULL) + { + L2CAP_TRACE_WARNING ("L2CAP - no CCB for L2CA_SendTestSFrame, CID: %d", cid); + return (FALSE); + } + + if ( (p_ccb->chnl_state != CST_OPEN) || (p_ccb->peer_cfg.fcr.mode != L2CAP_FCR_ERTM_MODE) ) + return (FALSE); + + p_ccb->fcrb.next_seq_expected -= back_track; + + l2c_fcr_send_S_frame (p_ccb, (UINT16)(sup_type & 3), (UINT16)(sup_type & (L2CAP_FCR_P_BIT | L2CAP_FCR_F_BIT))); + + return (TRUE); +} + + +/******************************************************************************* +** +** Function L2CA_SetTxPriority +** +** Description Sets the transmission priority for a channel. +** +** Returns TRUE if a valid channel, else FALSE +** +*******************************************************************************/ +BOOLEAN L2CA_SetTxPriority (UINT16 cid, tL2CAP_CHNL_PRIORITY priority) +{ + tL2C_CCB *p_ccb; + + L2CAP_TRACE_API ("L2CA_SetTxPriority() CID: 0x%04x, priority:%d", cid, priority); + + /* Find the channel control block. We don't know the link it is on. */ + if ((p_ccb = l2cu_find_ccb_by_cid (NULL, cid)) == NULL) + { + L2CAP_TRACE_WARNING ("L2CAP - no CCB for L2CA_SetTxPriority, CID: %d", cid); + return (FALSE); + } + + /* it will update the order of CCB in LCB by priority and update round robin service variables */ + l2cu_change_pri_ccb (p_ccb, priority); + + return (TRUE); +} + +/******************************************************************************* +** +** Function L2CA_SetChnlDataRate +** +** Description Sets the tx/rx data rate for a channel. +** +** Returns TRUE if a valid channel, else FALSE +** +*******************************************************************************/ +BOOLEAN L2CA_SetChnlDataRate (UINT16 cid, tL2CAP_CHNL_DATA_RATE tx, tL2CAP_CHNL_DATA_RATE rx) +{ + tL2C_CCB *p_ccb; + + L2CAP_TRACE_API ("L2CA_SetChnlDataRate() CID: 0x%04x, tx:%d, rx:%d", cid, tx, rx); + + /* Find the channel control block. We don't know the link it is on. */ + if ((p_ccb = l2cu_find_ccb_by_cid (NULL, cid)) == NULL) + { + L2CAP_TRACE_WARNING ("L2CAP - no CCB for L2CA_SetChnlDataRate, CID: %d", cid); + return (FALSE); + } + + p_ccb->tx_data_rate = tx; + p_ccb->rx_data_rate = rx; + + /* Adjust channel buffer allocation */ + l2c_link_adjust_chnl_allocation (); + + return(TRUE); +} + +/******************************************************************************* +** +** Function L2CA_SetFlushTimeout +** +** Description This function set the automatic flush time out in Baseband +** for ACL-U packets. +** BdAddr : the remote BD address of ACL link. If it is BT_DB_ANY +** then the flush time out will be applied to all ACL link. +** FlushTimeout: flush time out in ms +** 0x0000 : No automatic flush +** L2CAP_NO_RETRANSMISSION : No retransmission +** 0x0002 - 0xFFFE : flush time out, if (flush_tout*8)+3/5) +** <= HCI_MAX_AUTO_FLUSH_TOUT (in 625us slot). +** Otherwise, return FALSE. +** L2CAP_NO_AUTOMATIC_FLUSH : No automatic flush +** +** Returns TRUE if command succeeded, FALSE if failed +** +** NOTE This flush timeout applies to all logical channels active on the +** ACL link. +*******************************************************************************/ +BOOLEAN L2CA_SetFlushTimeout (BD_ADDR bd_addr, UINT16 flush_tout) +{ + tL2C_LCB *p_lcb; + UINT16 hci_flush_to; + UINT32 temp; + + /* no automatic flush (infinite timeout) */ + if (flush_tout == 0x0000) + { + hci_flush_to = flush_tout; + flush_tout = L2CAP_NO_AUTOMATIC_FLUSH; + } + /* no retransmission */ + else if (flush_tout == L2CAP_NO_RETRANSMISSION) + { + /* not mandatory range for controller */ + /* Packet is flushed before getting any ACK/NACK */ + /* To do this, flush timeout should be 1 baseband slot */ + hci_flush_to = flush_tout; + } + /* no automatic flush (infinite timeout) */ + else if (flush_tout == L2CAP_NO_AUTOMATIC_FLUSH) + { + hci_flush_to = 0x0000; + } + else + { + /* convert L2CAP flush_to to 0.625 ms units, with round */ + temp = (((UINT32)flush_tout * 8) + 3) / 5; + + /* if L2CAP flush_to within range of HCI, set HCI flush timeout */ + if (temp > HCI_MAX_AUTO_FLUSH_TOUT) + { + L2CAP_TRACE_WARNING("WARNING L2CA_SetFlushTimeout timeout(0x%x) is out of range", flush_tout); + return FALSE; + } + else + { + hci_flush_to = (UINT16)temp; + } + } + + if (memcmp (BT_BD_ANY, bd_addr, BD_ADDR_LEN)) + { + p_lcb = l2cu_find_lcb_by_bd_addr (bd_addr, BT_TRANSPORT_BR_EDR); + + if ((p_lcb) && (p_lcb->in_use) && (p_lcb->link_state == LST_CONNECTED)) + { + if (p_lcb->link_flush_tout != flush_tout) + { + p_lcb->link_flush_tout = flush_tout; + + L2CAP_TRACE_API ("L2CA_SetFlushTimeout 0x%04x ms for bd_addr [...;%02x%02x%02x]", + flush_tout, bd_addr[3], bd_addr[4], bd_addr[5]); + + if (!btsnd_hcic_write_auto_flush_tout (p_lcb->handle, hci_flush_to)) + return (FALSE); + } + } + else + { + L2CAP_TRACE_WARNING ("WARNING L2CA_SetFlushTimeout No lcb for bd_addr [...;%02x%02x%02x]", + bd_addr[3], bd_addr[4], bd_addr[5]); + return (FALSE); + } + } + else + { + int xx; + p_lcb = &l2cb.lcb_pool[0]; + + for (xx = 0; xx < MAX_L2CAP_LINKS; xx++, p_lcb++) + { + if ((p_lcb->in_use) && (p_lcb->link_state == LST_CONNECTED)) + { + if (p_lcb->link_flush_tout != flush_tout) + { + p_lcb->link_flush_tout = flush_tout; + + L2CAP_TRACE_API ("L2CA_SetFlushTimeout 0x%04x ms for bd_addr [...;%02x%02x%02x]", + flush_tout, p_lcb->remote_bd_addr[3], + p_lcb->remote_bd_addr[4], p_lcb->remote_bd_addr[5]); + + if (!btsnd_hcic_write_auto_flush_tout(p_lcb->handle, hci_flush_to)) + return (FALSE); + } + } + } + } + + return (TRUE); +} + +/******************************************************************************* +** +** Function L2CA_GetPeerFeatures +** +** Description Get a peers features and fixed channel map +** +** Parameters: BD address of the peer +** Pointers to features and channel mask storage area +** +** Return value: TRUE if peer is connected +** +*******************************************************************************/ +BOOLEAN L2CA_GetPeerFeatures (BD_ADDR bd_addr, UINT32 *p_ext_feat, UINT8 *p_chnl_mask) +{ + tL2C_LCB *p_lcb; + + /* We must already have a link to the remote */ + if ((p_lcb = l2cu_find_lcb_by_bd_addr (bd_addr, BT_TRANSPORT_BR_EDR)) == NULL) + { + L2CAP_TRACE_WARNING ("L2CA_GetPeerFeatures() No BDA: %08x%04x", + (bd_addr[0]<<24)+(bd_addr[1]<<16)+(bd_addr[2]<<8)+bd_addr[3], + (bd_addr[4]<<8)+bd_addr[5]); + return (FALSE); + } + + L2CAP_TRACE_API ("L2CA_GetPeerFeatures() BDA: %08x%04x ExtFea: 0x%08x Chnl_Mask[0]: 0x%02x", + (bd_addr[0]<<24)+(bd_addr[1]<<16)+(bd_addr[2]<<8)+bd_addr[3], + (bd_addr[4]<<8)+bd_addr[5], p_lcb->peer_ext_fea, p_lcb->peer_chnl_mask[0]); + + *p_ext_feat = p_lcb->peer_ext_fea; + + memcpy (p_chnl_mask, p_lcb->peer_chnl_mask, L2CAP_FIXED_CHNL_ARRAY_SIZE); + + return (TRUE); +} + +/******************************************************************************* +** +** Function L2CA_GetBDAddrbyHandle +** +** Description Get BD address for the given HCI handle +** +** Parameters: HCI handle +** BD address of the peer +** +** Return value: TRUE if found lcb for the given handle, FALSE otherwise +** +*******************************************************************************/ +BOOLEAN L2CA_GetBDAddrbyHandle (UINT16 handle, BD_ADDR bd_addr) +{ + tL2C_LCB *p_lcb = NULL; + BOOLEAN found_dev = FALSE; + + p_lcb = l2cu_find_lcb_by_handle (handle); + if (p_lcb) + { + found_dev = TRUE; + memcpy (bd_addr, p_lcb->remote_bd_addr, BD_ADDR_LEN); + } + + return found_dev; +} + +/******************************************************************************* +** +** Function L2CA_GetChnlFcrMode +** +** Description Get the channel FCR mode +** +** Parameters: Local CID +** +** Return value: Channel mode +** +*******************************************************************************/ +UINT8 L2CA_GetChnlFcrMode (UINT16 lcid) +{ + tL2C_CCB *p_ccb = l2cu_find_ccb_by_cid (NULL, lcid); + + if (p_ccb) + { + L2CAP_TRACE_API ("L2CA_GetChnlFcrMode() returns mode %d", p_ccb->peer_cfg.fcr.mode); + return (p_ccb->peer_cfg.fcr.mode); + } + + L2CAP_TRACE_API ("L2CA_GetChnlFcrMode() returns mode L2CAP_FCR_BASIC_MODE"); + return (L2CAP_FCR_BASIC_MODE); +} + +#if (L2CAP_NUM_FIXED_CHNLS > 0) +/******************************************************************************* +** +** Function L2CA_RegisterFixedChannel +** +** Description Register a fixed channel. +** +** Parameters: Fixed Channel # +** Channel Callbacks and config +** +** Return value: - +** +*******************************************************************************/ +BOOLEAN L2CA_RegisterFixedChannel (UINT16 fixed_cid, tL2CAP_FIXED_CHNL_REG *p_freg) +{ + if ( (fixed_cid < L2CAP_FIRST_FIXED_CHNL) || (fixed_cid > L2CAP_LAST_FIXED_CHNL) ) + { + L2CAP_TRACE_ERROR ("L2CA_RegisterFixedChannel() Invalid CID: 0x%04x", fixed_cid); + + return (FALSE); + } + + l2cb.fixed_reg[fixed_cid - L2CAP_FIRST_FIXED_CHNL] = *p_freg; + return (TRUE); +} + +/******************************************************************************* +** +** Function L2CA_ConnectFixedChnl +** +** Description Connect an fixed signalling channel to a remote device. +** +** Parameters: Fixed CID +** BD Address of remote +** +** Return value: TRUE if connection started +** +*******************************************************************************/ +BOOLEAN L2CA_ConnectFixedChnl (UINT16 fixed_cid, BD_ADDR rem_bda) +{ + tL2C_LCB *p_lcb; + tBT_TRANSPORT transport = BT_TRANSPORT_BR_EDR; + + L2CAP_TRACE_API ("%s() CID: 0x%04x BDA: %08x%04x", __func__, fixed_cid, + (rem_bda[0]<<24)+(rem_bda[1]<<16)+(rem_bda[2]<<8)+rem_bda[3], (rem_bda[4]<<8)+rem_bda[5]); + + // Check CID is valid and registered + if ( (fixed_cid < L2CAP_FIRST_FIXED_CHNL) || (fixed_cid > L2CAP_LAST_FIXED_CHNL) + || (l2cb.fixed_reg[fixed_cid - L2CAP_FIRST_FIXED_CHNL].pL2CA_FixedData_Cb == NULL) ) + { + L2CAP_TRACE_ERROR ("%s() Invalid CID: 0x%04x", __func__, fixed_cid); + return (FALSE); + } + + // Fail if BT is not yet up + if (!BTM_IsDeviceUp()) + { + L2CAP_TRACE_WARNING ("%s(0x%04x) - BTU not ready", __func__, fixed_cid); + return (FALSE); + } + +#if BLE_INCLUDED == TRUE + if (fixed_cid >= L2CAP_ATT_CID && fixed_cid <= L2CAP_SMP_CID) + transport = BT_TRANSPORT_LE; +#endif + + tL2C_BLE_FIXED_CHNLS_MASK peer_channel_mask; + + // If we already have a link to the remote, check if it supports that CID + if ((p_lcb = l2cu_find_lcb_by_bd_addr (rem_bda, transport)) != NULL) + { + // Fixed channels are mandatory on LE transports so ignore the received + // channel mask and use the locally cached LE channel mask. + +#if BLE_INCLUDED == TRUE + if (transport == BT_TRANSPORT_LE) + peer_channel_mask = l2cb.l2c_ble_fixed_chnls_mask; + else +#endif + peer_channel_mask = p_lcb->peer_chnl_mask[0]; + + // Check for supported channel + if (!(peer_channel_mask & (1 << fixed_cid))) + { + L2CAP_TRACE_EVENT ("%s() CID:0x%04x BDA: %08x%04x not supported", __func__, + fixed_cid,(rem_bda[0]<<24)+(rem_bda[1]<<16)+(rem_bda[2]<<8)+rem_bda[3], + (rem_bda[4]<<8)+rem_bda[5]); + return FALSE; + } + + // Get a CCB and link the lcb to it + if (!l2cu_initialize_fixed_ccb (p_lcb, fixed_cid, + &l2cb.fixed_reg[fixed_cid - L2CAP_FIRST_FIXED_CHNL].fixed_chnl_opts)) + { + L2CAP_TRACE_WARNING ("%s(0x%04x) - LCB but no CCB", __func__, fixed_cid); + return FALSE; + } + + // racing with disconnecting, queue the connection request + if (p_lcb->link_state == LST_DISCONNECTING) + { + L2CAP_TRACE_DEBUG ("$s() - link disconnecting: RETRY LATER", __func__); + /* Save ccb so it can be started after disconnect is finished */ + p_lcb->p_pending_ccb = p_lcb->p_fixed_ccbs[fixed_cid - L2CAP_FIRST_FIXED_CHNL]; + return TRUE; + } + +#if BLE_INCLUDED == TRUE + (*l2cb.fixed_reg[fixed_cid - L2CAP_FIRST_FIXED_CHNL].pL2CA_FixedConn_Cb) + (fixed_cid,p_lcb->remote_bd_addr, TRUE, 0, p_lcb->transport); +#else + (*l2cb.fixed_reg[fixed_cid - L2CAP_FIRST_FIXED_CHNL].pL2CA_FixedConn_Cb) + (fixed_cid, p_lcb->remote_bd_addr, TRUE, 0, BT_TRANSPORT_BR_EDR); +#endif + return TRUE; + } + + // No link. Get an LCB and start link establishment + if ((p_lcb = l2cu_allocate_lcb (rem_bda, FALSE, transport)) == NULL) + { + L2CAP_TRACE_WARNING ("%s(0x%04x) - no LCB", __func__, fixed_cid); + return FALSE; + } + + // Get a CCB and link the lcb to it + if (!l2cu_initialize_fixed_ccb (p_lcb, fixed_cid, + &l2cb.fixed_reg[fixed_cid - L2CAP_FIRST_FIXED_CHNL].fixed_chnl_opts)) + { + p_lcb->disc_reason = L2CAP_CONN_NO_RESOURCES; + L2CAP_TRACE_WARNING ("%s(0x%04x) - no CCB", __func__, fixed_cid); + l2cu_release_lcb (p_lcb); + return FALSE; + } + + if (!l2cu_create_conn(p_lcb, transport)) + { + L2CAP_TRACE_WARNING ("%s() - create_conn failed", __func__); + l2cu_release_lcb (p_lcb); + return FALSE; + } + return TRUE; +} + +/******************************************************************************* +** +** Function L2CA_SendFixedChnlData +** +** Description Write data on a fixed channel. +** +** Parameters: Fixed CID +** BD Address of remote +** Pointer to buffer of type BT_HDR +** +** Return value L2CAP_DW_SUCCESS, if data accepted +** L2CAP_DW_FAILED, if error +** +*******************************************************************************/ +UINT16 L2CA_SendFixedChnlData (UINT16 fixed_cid, BD_ADDR rem_bda, BT_HDR *p_buf) +{ + tL2C_LCB *p_lcb; + tBT_TRANSPORT transport = BT_TRANSPORT_BR_EDR; + + L2CAP_TRACE_API ("L2CA_SendFixedChnlData() CID: 0x%04x BDA: %08x%04x", fixed_cid, + (rem_bda[0]<<24)+(rem_bda[1]<<16)+(rem_bda[2]<<8)+rem_bda[3], (rem_bda[4]<<8)+rem_bda[5]); + +#if BLE_INCLUDED == TRUE + if (fixed_cid >= L2CAP_ATT_CID && fixed_cid <= L2CAP_SMP_CID) + transport = BT_TRANSPORT_LE; +#endif + + // Check CID is valid and registered + if ( (fixed_cid < L2CAP_FIRST_FIXED_CHNL) || (fixed_cid > L2CAP_LAST_FIXED_CHNL) + || (l2cb.fixed_reg[fixed_cid - L2CAP_FIRST_FIXED_CHNL].pL2CA_FixedData_Cb == NULL) ) + { + L2CAP_TRACE_ERROR ("L2CA_SendFixedChnlData() Invalid CID: 0x%04x", fixed_cid); + GKI_freebuf (p_buf); + return (L2CAP_DW_FAILED); + } + + // Fail if BT is not yet up + if (!BTM_IsDeviceUp()) + { + L2CAP_TRACE_WARNING ("L2CA_SendFixedChnlData(0x%04x) - BTU not ready", fixed_cid); + GKI_freebuf (p_buf); + return (L2CAP_DW_FAILED); + } + + // We need to have a link up + if ((p_lcb = l2cu_find_lcb_by_bd_addr (rem_bda, transport)) == NULL || + /* if link is disconnecting, also report data sending failure */ + p_lcb->link_state == LST_DISCONNECTING) + { + L2CAP_TRACE_WARNING ("L2CA_SendFixedChnlData(0x%04x) - no LCB", fixed_cid); + GKI_freebuf (p_buf); + return (L2CAP_DW_FAILED); + } + + tL2C_BLE_FIXED_CHNLS_MASK peer_channel_mask; + + // Select peer channels mask to use depending on transport +#if BLE_INCLUDED == TRUE + if (transport == BT_TRANSPORT_LE) + peer_channel_mask = l2cb.l2c_ble_fixed_chnls_mask; + else +#endif + peer_channel_mask = p_lcb->peer_chnl_mask[0]; + + if ((peer_channel_mask & (1 << fixed_cid)) == 0) + { + L2CAP_TRACE_WARNING ("L2CA_SendFixedChnlData() - peer does not support fixed chnl: 0x%04x", fixed_cid); + GKI_freebuf (p_buf); + return (L2CAP_DW_FAILED); + } + + p_buf->event = 0; + p_buf->layer_specific = L2CAP_FLUSHABLE_CH_BASED; + + if (!p_lcb->p_fixed_ccbs[fixed_cid - L2CAP_FIRST_FIXED_CHNL]) + { + if (!l2cu_initialize_fixed_ccb (p_lcb, fixed_cid, &l2cb.fixed_reg[fixed_cid - L2CAP_FIRST_FIXED_CHNL].fixed_chnl_opts)) + { + L2CAP_TRACE_WARNING ("L2CA_SendFixedChnlData() - no CCB for chnl: 0x%4x", fixed_cid); + GKI_freebuf (p_buf); + return (L2CAP_DW_FAILED); + } + } + + // If already congested, do not accept any more packets + if (p_lcb->p_fixed_ccbs[fixed_cid - L2CAP_FIRST_FIXED_CHNL]->cong_sent) + { + L2CAP_TRACE_ERROR ("L2CAP - CID: 0x%04x cannot send, already congested \ + xmit_hold_q.count: %u buff_quota: %u", fixed_cid, + GKI_queue_length(&p_lcb->p_fixed_ccbs[fixed_cid - L2CAP_FIRST_FIXED_CHNL]->xmit_hold_q), + p_lcb->p_fixed_ccbs[fixed_cid - L2CAP_FIRST_FIXED_CHNL]->buff_quota); + GKI_freebuf (p_buf); + return (L2CAP_DW_FAILED); + } + + l2c_enqueue_peer_data (p_lcb->p_fixed_ccbs[fixed_cid - L2CAP_FIRST_FIXED_CHNL], p_buf); + + l2c_link_check_send_pkts (p_lcb, NULL, NULL); + + // If there is no dynamic CCB on the link, restart the idle timer each time something is sent + if (p_lcb->in_use && p_lcb->link_state == LST_CONNECTED && !p_lcb->ccb_queue.p_first_ccb) + { + l2cu_no_dynamic_ccbs (p_lcb); + } + + if (p_lcb->p_fixed_ccbs[fixed_cid - L2CAP_FIRST_FIXED_CHNL]->cong_sent) + return (L2CAP_DW_CONGESTED); + + return (L2CAP_DW_SUCCESS); +} + +/******************************************************************************* +** +** Function L2CA_RemoveFixedChnl +** +** Description Remove a fixed channel to a remote device. +** +** Parameters: Fixed CID +** BD Address of remote +** Idle timeout to use (or 0xFFFF if don't care) +** +** Return value: TRUE if channel removed +** +*******************************************************************************/ +BOOLEAN L2CA_RemoveFixedChnl (UINT16 fixed_cid, BD_ADDR rem_bda) +{ + tL2C_LCB *p_lcb; + tL2C_CCB *p_ccb; + tBT_TRANSPORT transport = BT_TRANSPORT_BR_EDR; + + /* Check CID is valid and registered */ + if ( (fixed_cid < L2CAP_FIRST_FIXED_CHNL) || (fixed_cid > L2CAP_LAST_FIXED_CHNL) + || (l2cb.fixed_reg[fixed_cid - L2CAP_FIRST_FIXED_CHNL].pL2CA_FixedData_Cb == NULL) ) + { + L2CAP_TRACE_ERROR ("L2CA_RemoveFixedChnl() Invalid CID: 0x%04x", fixed_cid); + return (FALSE); + } + +#if BLE_INCLUDED == TRUE + if (fixed_cid >= L2CAP_ATT_CID && fixed_cid <= L2CAP_SMP_CID) + transport = BT_TRANSPORT_LE; +#endif + + /* Is a fixed channel connected to the remote BDA ?*/ + p_lcb = l2cu_find_lcb_by_bd_addr (rem_bda, transport); + + if ( ((p_lcb) == NULL) || (!p_lcb->p_fixed_ccbs[fixed_cid - L2CAP_FIRST_FIXED_CHNL]) ) + { + L2CAP_TRACE_WARNING ("L2CA_RemoveFixedChnl() CID: 0x%04x BDA: %08x%04x not connected", fixed_cid, + (rem_bda[0]<<24)+(rem_bda[1]<<16)+(rem_bda[2]<<8)+rem_bda[3], (rem_bda[4]<<8)+rem_bda[5]); + return (FALSE); + } + + L2CAP_TRACE_API ("L2CA_RemoveFixedChnl() CID: 0x%04x BDA: %08x%04x", fixed_cid, + (rem_bda[0]<<24)+(rem_bda[1]<<16)+(rem_bda[2]<<8)+rem_bda[3], (rem_bda[4]<<8)+rem_bda[5]); + + /* Release the CCB, starting an inactivity timeout on the LCB if no other CCBs exist */ + p_ccb = p_lcb->p_fixed_ccbs[fixed_cid - L2CAP_FIRST_FIXED_CHNL]; + + p_lcb->p_fixed_ccbs[fixed_cid - L2CAP_FIRST_FIXED_CHNL] = NULL; + p_lcb->disc_reason = HCI_ERR_CONN_CAUSE_LOCAL_HOST; + +#if BLE_INCLUDED == TRUE + // Retain the link for a few more seconds after SMP pairing is done, since the Android + // platform always does service discovery after pairing is complete. This will avoid + // the link down (pairing is complete) and an immediate re-connection for service + // discovery. + // Some devices do not do auto advertising when link is dropped, thus fail the second + // connection and service discovery. + if ((fixed_cid == L2CAP_ATT_CID ) && !p_lcb->ccb_queue.p_first_ccb) + p_lcb->idle_timeout = 0; +#endif + + l2cu_release_ccb (p_ccb); + + return (TRUE); +} + +/******************************************************************************* +** +** Function L2CA_SetFixedChannelTout +** +** Description Higher layers call this function to set the idle timeout for +** a fixed channel. The "idle timeout" is the amount of time that +** a connection can remain up with no L2CAP channels on it. +** A timeout of zero means that the connection will be torn +** down immediately when the last channel is removed. +** A timeout of 0xFFFF means no timeout. Values are in seconds. +** A bd_addr is the remote BD address. If bd_addr = BT_BD_ANY, +** then the idle timeouts for all active l2cap links will be +** changed. +** +** Returns TRUE if command succeeded, FALSE if failed +** +*******************************************************************************/ +BOOLEAN L2CA_SetFixedChannelTout (BD_ADDR rem_bda, UINT16 fixed_cid, UINT16 idle_tout) +{ + tL2C_LCB *p_lcb; + tBT_TRANSPORT transport = BT_TRANSPORT_BR_EDR; + +#if BLE_INCLUDED == TRUE + if (fixed_cid >= L2CAP_ATT_CID && fixed_cid <= L2CAP_SMP_CID) + transport = BT_TRANSPORT_LE; +#endif + + /* Is a fixed channel connected to the remote BDA ?*/ + p_lcb = l2cu_find_lcb_by_bd_addr (rem_bda, transport); + if ( ((p_lcb) == NULL) || (!p_lcb->p_fixed_ccbs[fixed_cid - L2CAP_FIRST_FIXED_CHNL]) ) + { + L2CAP_TRACE_WARNING ("L2CA_SetFixedChannelTout() CID: 0x%04x BDA: %08x%04x not connected", fixed_cid, + (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->p_fixed_ccbs[fixed_cid - L2CAP_FIRST_FIXED_CHNL]->fixed_chnl_idle_tout = idle_tout; + + if (p_lcb->in_use && p_lcb->link_state == LST_CONNECTED && !p_lcb->ccb_queue.p_first_ccb) + { + /* If there are no dynamic CCBs, (re)start the idle timer in case we changed it */ + l2cu_no_dynamic_ccbs (p_lcb); + } + + return TRUE; +} + +#endif /* #if (L2CAP_NUM_FIXED_CHNLS > 0) */ + +/******************************************************************************* +** +** Function L2CA_GetCurrentConfig +** +** Description This function returns configurations of L2CAP channel +** pp_our_cfg : pointer of our saved configuration options +** p_our_cfg_bits : valid config in bitmap +** pp_peer_cfg: pointer of peer's saved configuration options +** p_peer_cfg_bits : valid config in bitmap +** +** Returns TRUE if successful +** +*******************************************************************************/ +BOOLEAN L2CA_GetCurrentConfig (UINT16 lcid, + tL2CAP_CFG_INFO **pp_our_cfg, tL2CAP_CH_CFG_BITS *p_our_cfg_bits, + tL2CAP_CFG_INFO **pp_peer_cfg, tL2CAP_CH_CFG_BITS *p_peer_cfg_bits) +{ + tL2C_CCB *p_ccb; + + L2CAP_TRACE_API ("L2CA_GetCurrentConfig() CID: 0x%04x", lcid); + + p_ccb = l2cu_find_ccb_by_cid(NULL, lcid); + + if (p_ccb) + { + *pp_our_cfg = &(p_ccb->our_cfg); + + /* convert valid config items into bitmap */ + *p_our_cfg_bits = 0; + if (p_ccb->our_cfg.mtu_present) + *p_our_cfg_bits |= L2CAP_CH_CFG_MASK_MTU; + if (p_ccb->our_cfg.qos_present) + *p_our_cfg_bits |= L2CAP_CH_CFG_MASK_QOS; + if (p_ccb->our_cfg.flush_to_present) + *p_our_cfg_bits |= L2CAP_CH_CFG_MASK_FLUSH_TO; + if (p_ccb->our_cfg.fcr_present) + *p_our_cfg_bits |= L2CAP_CH_CFG_MASK_FCR; + if (p_ccb->our_cfg.fcs_present) + *p_our_cfg_bits |= L2CAP_CH_CFG_MASK_FCS; + if (p_ccb->our_cfg.ext_flow_spec_present) + *p_our_cfg_bits |= L2CAP_CH_CFG_MASK_EXT_FLOW_SPEC; + + *pp_peer_cfg = &(p_ccb->peer_cfg); + *p_peer_cfg_bits = p_ccb->peer_cfg_bits; + + return TRUE; + } + else + { + L2CAP_TRACE_ERROR ("No CCB for CID:0x%04x", lcid); + return FALSE; + } +} + +/******************************************************************************* +** +** Function L2CA_RegForNoCPEvt +** +** Description Register callback for Number of Completed Packets event. +** +** Input Param p_cb - callback for Number of completed packets event +** p_bda - BT address of remote device +** +** Returns TRUE if registered OK, else FALSE +** +*******************************************************************************/ +BOOLEAN L2CA_RegForNoCPEvt(tL2CA_NOCP_CB *p_cb, BD_ADDR p_bda) +{ + tL2C_LCB *p_lcb; + + /* Find the link that is associated with this remote bdaddr */ + p_lcb = l2cu_find_lcb_by_bd_addr (p_bda, BT_TRANSPORT_BR_EDR); + + /* If no link for this handle, nothing to do. */ + if (!p_lcb) + return FALSE; + + p_lcb->p_nocp_cb = p_cb; + + return TRUE; +} + +/******************************************************************************* +** +** Function L2CA_DataWrite +** +** Description Higher layers call this function to write data. +** +** Returns L2CAP_DW_SUCCESS, if data accepted, else FALSE +** L2CAP_DW_CONGESTED, if data accepted and the channel is congested +** L2CAP_DW_FAILED, if error +** +*******************************************************************************/ +UINT8 L2CA_DataWrite (UINT16 cid, BT_HDR *p_data) +{ + L2CAP_TRACE_API ("L2CA_DataWrite() CID: 0x%04x Len: %d", cid, p_data->len); + return l2c_data_write (cid, p_data, L2CAP_FLUSHABLE_CH_BASED); +} + +/******************************************************************************* +** +** Function L2CA_SetChnlFlushability +** +** Description Higher layers call this function to set a channels +** flushability flags +** +** Returns TRUE if CID found, else FALSE +** +*******************************************************************************/ +BOOLEAN L2CA_SetChnlFlushability (UINT16 cid, BOOLEAN is_flushable) +{ +#if (L2CAP_NON_FLUSHABLE_PB_INCLUDED == TRUE) + + tL2C_CCB *p_ccb; + + /* Find the channel control block. We don't know the link it is on. */ + if ((p_ccb = l2cu_find_ccb_by_cid (NULL, cid)) == NULL) + { + L2CAP_TRACE_WARNING ("L2CAP - no CCB for L2CA_SetChnlFlushability, CID: %d", cid); + return (FALSE); + } + + p_ccb->is_flushable = is_flushable; + + L2CAP_TRACE_API ("L2CA_SetChnlFlushability() CID: 0x%04x is_flushable: %d", cid, is_flushable); + +#endif + + return (TRUE); +} + +/******************************************************************************* +** +** Function L2CA_DataWriteEx +** +** Description Higher layers call this function to write data with extended +** flags. +** flags : L2CAP_FLUSHABLE_CH_BASED +** L2CAP_FLUSHABLE_PKT +** L2CAP_NON_FLUSHABLE_PKT +** +** Returns L2CAP_DW_SUCCESS, if data accepted, else FALSE +** L2CAP_DW_CONGESTED, if data accepted and the channel is congested +** L2CAP_DW_FAILED, if error +** +*******************************************************************************/ +UINT8 L2CA_DataWriteEx (UINT16 cid, BT_HDR *p_data, UINT16 flags) +{ + L2CAP_TRACE_API ("L2CA_DataWriteEx() CID: 0x%04x Len: %d Flags:0x%04X", + cid, p_data->len, flags); + return l2c_data_write (cid, p_data, flags); +} + +/******************************************************************************* +** +** Function L2CA_FlushChannel +** +** Description This function flushes none, some or all buffers queued up +** for xmission for a particular CID. If called with +** L2CAP_FLUSH_CHANS_GET (0), it simply returns the number +** of buffers queued for that CID L2CAP_FLUSH_CHANS_ALL (0xffff) +** flushes all buffers. All other values specifies the maximum +** buffers to flush. +** +** Returns Number of buffers left queued for that CID +** +*******************************************************************************/ +UINT16 L2CA_FlushChannel (UINT16 lcid, UINT16 num_to_flush) +{ + tL2C_CCB *p_ccb; + tL2C_LCB *p_lcb; + UINT16 num_left = 0, + num_flushed1 = 0, + num_flushed2 = 0; + + p_ccb = l2cu_find_ccb_by_cid(NULL, lcid); + + if ( !p_ccb || ((p_lcb = p_ccb->p_lcb) == NULL) ) + { + L2CAP_TRACE_WARNING ("L2CA_FlushChannel() abnormally returning 0 CID: 0x%04x", lcid); + return (0); + } + + if (num_to_flush != L2CAP_FLUSH_CHANS_GET) + { + L2CAP_TRACE_API ("L2CA_FlushChannel (FLUSH) CID: 0x%04x NumToFlush: %d QC: %u pFirst: 0x%08x", + lcid, num_to_flush, GKI_queue_length(&p_ccb->xmit_hold_q), GKI_getfirst(&p_ccb->xmit_hold_q)); + } + else + { + L2CAP_TRACE_API ("L2CA_FlushChannel (QUERY) CID: 0x%04x", lcid); + } + + /* Cannot flush eRTM buffers once they have a sequence number */ + if (p_ccb->peer_cfg.fcr.mode != L2CAP_FCR_ERTM_MODE) + { +#if L2CAP_NON_FLUSHABLE_PB_INCLUDED == TRUE + if (num_to_flush != L2CAP_FLUSH_CHANS_GET) + { + /* If the controller supports enhanced flush, flush the data queued at the controller */ + if ( (HCI_NON_FLUSHABLE_PB_SUPPORTED(BTM_ReadLocalFeatures ())) + && (BTM_GetNumScoLinks() == 0) ) + { + if ( l2cb.is_flush_active == FALSE ) + { + l2cb.is_flush_active = TRUE; + + /* The only packet type defined - 0 - Automatically-Flushable Only */ + btsnd_hcic_enhanced_flush (p_lcb->handle, 0); + } + } + } +#endif + + // Iterate though list and flush the amount requested from + // the transmit data queue that satisfy the layer and event conditions. + for (const list_node_t *node = list_begin(p_lcb->link_xmit_data_q); + (num_to_flush > 0) && node != list_end(p_lcb->link_xmit_data_q);) { + BT_HDR *p_buf = (BT_HDR *)list_node(node); + node = list_next(node); + if ((p_buf->layer_specific == 0) && (p_buf->event == lcid)) { + num_to_flush--; + num_flushed1++; + + list_remove(p_lcb->link_xmit_data_q, p_buf); + GKI_freebuf(p_buf); + } + } + } + + /* If needed, flush buffers in the CCB xmit hold queue */ + while ( (num_to_flush != 0) && (!GKI_queue_is_empty(&p_ccb->xmit_hold_q))) + { + BT_HDR *p_buf = (BT_HDR *)GKI_dequeue (&p_ccb->xmit_hold_q); + if (p_buf) + GKI_freebuf (p_buf); + num_to_flush--; + num_flushed2++; + } + + /* If app needs to track all packets, call him */ + if ( (p_ccb->p_rcb) && (p_ccb->p_rcb->api.pL2CA_TxComplete_Cb) && (num_flushed2) ) + (*p_ccb->p_rcb->api.pL2CA_TxComplete_Cb)(p_ccb->local_cid, num_flushed2); + + /* Now count how many are left */ + for (const list_node_t *node = list_begin(p_lcb->link_xmit_data_q); + node != list_end(p_lcb->link_xmit_data_q); + node = list_next(node)) { + + BT_HDR *p_buf = (BT_HDR *)list_node(node); + if (p_buf->event == lcid) + num_left++; + } + + /* Add in the number in the CCB xmit queue */ + num_left += GKI_queue_length(&p_ccb->xmit_hold_q); + + /* Return the local number of buffers left for the CID */ + L2CAP_TRACE_DEBUG ("L2CA_FlushChannel() flushed: %u + %u, num_left: %u", num_flushed1, num_flushed2, num_left); + + /* If we were congested, and now we are not, tell the app */ + l2cu_check_channel_congestion (p_ccb); + + return (num_left); +} + diff --git a/components/bt/bluedroid/stack/l2cap/l2c_ble.c b/components/bt/bluedroid/stack/l2cap/l2c_ble.c new file mode 100755 index 0000000000..d3d34ac47f --- /dev/null +++ b/components/bt/bluedroid/stack/l2cap/l2c_ble.c @@ -0,0 +1,1082 @@ +/****************************************************************************** + * + * Copyright (C) 2009-2012 Broadcom Corporation + * + * 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 functions relating to BLE management. + * + ******************************************************************************/ + +#include +#include "bt_target.h" +//#include "bt_utils.h" +#include "l2cdefs.h" +#include "l2c_int.h" +#include "btu.h" +#include "btm_int.h" +#include "hcimsgs.h" +#include "controller.h" + +#if (BLE_INCLUDED == TRUE) +static void l2cble_start_conn_update (tL2C_LCB *p_lcb); + +/******************************************************************************* +** +** Function L2CA_CancelBleConnectReq +** +** Description Cancel a pending connection attempt to a BLE device. +** +** Parameters: BD Address of remote +** +** Return value: TRUE if connection was cancelled +** +*******************************************************************************/ +BOOLEAN L2CA_CancelBleConnectReq (BD_ADDR rem_bda) +{ + tL2C_LCB *p_lcb; + + /* There can be only one BLE connection request outstanding at a time */ + if (btm_ble_get_conn_st() == BLE_CONN_IDLE) + { + L2CAP_TRACE_WARNING ("L2CA_CancelBleConnectReq - no connection pending"); + return(FALSE); + } + + if (memcmp (rem_bda, l2cb.ble_connecting_bda, BD_ADDR_LEN)) + { + L2CAP_TRACE_WARNING ("L2CA_CancelBleConnectReq - different BDA Connecting: %08x%04x Cancel: %08x%04x", + (l2cb.ble_connecting_bda[0]<<24)+(l2cb.ble_connecting_bda[1]<<16)+(l2cb.ble_connecting_bda[2]<<8)+l2cb.ble_connecting_bda[3], + (l2cb.ble_connecting_bda[4]<<8)+l2cb.ble_connecting_bda[5], + (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 (btsnd_hcic_ble_create_conn_cancel()) + { + p_lcb = l2cu_find_lcb_by_bd_addr(rem_bda, BT_TRANSPORT_LE); + /* Do not remove lcb if an LE link is already up as a peripheral */ + if (p_lcb != NULL && + !(p_lcb->link_role == HCI_ROLE_SLAVE && BTM_ACL_IS_CONNECTED(rem_bda))) + { + p_lcb->disc_reason = L2CAP_CONN_CANCEL; + l2cu_release_lcb (p_lcb); + } + /* update state to be cancel, wait for connection cancel complete */ + btm_ble_set_conn_st (BLE_CONN_CANCEL); + + return(TRUE); + } + else + return(FALSE); +} + +/******************************************************************************* +** +** 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 L2CA_EnableUpdateBleConnParams +** +** Description Enable or disable update based on the request from the peer +** +** Parameters: BD Address of remote +** +** Return value: TRUE if update started +** +*******************************************************************************/ +BOOLEAN L2CA_EnableUpdateBleConnParams (BD_ADDR rem_bda, BOOLEAN enable) +{ + tL2C_LCB *p_lcb; + + /* 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 (!p_lcb) + { + L2CAP_TRACE_WARNING ("L2CA_EnableUpdateBleConnParams - 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); + } + + L2CAP_TRACE_API ("%s - BD_ADDR %08x%04x enable %d current upd state 0x%02x",__FUNCTION__, + (rem_bda[0]<<24)+(rem_bda[1]<<16)+(rem_bda[2]<<8)+rem_bda[3], + (rem_bda[4]<<8)+rem_bda[5], enable, p_lcb->conn_update_mask); + + if (p_lcb->transport != BT_TRANSPORT_LE) + { + L2CAP_TRACE_WARNING ("%s - BD_ADDR %08x%04x not LE (link role %d)", __FUNCTION__, + (rem_bda[0]<<24)+(rem_bda[1]<<16)+(rem_bda[2]<<8)+rem_bda[3], + (rem_bda[4]<<8)+rem_bda[5], p_lcb->link_role); + return (FALSE); + } + + if (enable) + p_lcb->conn_update_mask &= ~L2C_BLE_CONN_UPDATE_DISABLE; + else + p_lcb->conn_update_mask |= L2C_BLE_CONN_UPDATE_DISABLE; + + l2cble_start_conn_update(p_lcb); + + return (TRUE); +} + + +/******************************************************************************* +** +** Function L2CA_GetBleConnRole +** +** Description This function returns the connection role. +** +** Returns link role. +** +*******************************************************************************/ +UINT8 L2CA_GetBleConnRole (BD_ADDR bd_addr) +{ + UINT8 role = HCI_ROLE_UNKNOWN; + + tL2C_LCB *p_lcb; + + if ((p_lcb = l2cu_find_lcb_by_bd_addr (bd_addr, BT_TRANSPORT_LE)) != NULL) + role = p_lcb->link_role; + + return role; +} +/******************************************************************************* +** +** Function L2CA_GetDisconnectReason +** +** Description This function returns the disconnect reason code. +** +** Returns disconnect reason +** +*******************************************************************************/ +UINT16 L2CA_GetDisconnectReason (BD_ADDR remote_bda, tBT_TRANSPORT transport) +{ + tL2C_LCB *p_lcb; + UINT16 reason = 0; + + if ((p_lcb = l2cu_find_lcb_by_bd_addr (remote_bda, transport)) != NULL) + reason = p_lcb->disc_reason; + + L2CAP_TRACE_DEBUG ("L2CA_GetDisconnectReason=%d ",reason); + + return reason; +} + +/******************************************************************************* +** +** 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 l2cble_scanner_conn_comp +** +** Description This function is called when an HCI Connection Complete +** event is received while we are a scanner (so we are master). +** +** Returns void +** +*******************************************************************************/ +void l2cble_scanner_conn_comp (UINT16 handle, BD_ADDR bda, tBLE_ADDR_TYPE type, + UINT16 conn_interval, UINT16 conn_latency, UINT16 conn_timeout) +{ + int i; + tL2C_LCB *p_lcb; + tBTM_SEC_DEV_REC *p_dev_rec = btm_find_or_alloc_dev (bda); + + L2CAP_TRACE_DEBUG ("l2cble_scanner_conn_comp: HANDLE=%d addr_type=%d conn_interval=%d slave_latency=%d supervision_tout=%d", + handle, type, conn_interval, conn_latency, conn_timeout); + + l2cb.is_ble_connecting = FALSE; + + /* See if we have a link control block for the remote device */ + p_lcb = l2cu_find_lcb_by_bd_addr (bda, BT_TRANSPORT_LE); + + /* If we don't have one, create one. this is auto connection complete. */ + if (!p_lcb) + { + p_lcb = l2cu_allocate_lcb (bda, FALSE, BT_TRANSPORT_LE); + if (!p_lcb) + { + btm_sec_disconnect (handle, HCI_ERR_NO_CONNECTION); + L2CAP_TRACE_ERROR ("l2cble_scanner_conn_comp - failed to allocate LCB"); + return; + } + else + { + if (!l2cu_initialize_fixed_ccb (p_lcb, L2CAP_ATT_CID, &l2cb.fixed_reg[L2CAP_ATT_CID - L2CAP_FIRST_FIXED_CHNL].fixed_chnl_opts)) + { + btm_sec_disconnect (handle, HCI_ERR_NO_CONNECTION); + L2CAP_TRACE_WARNING ("l2cble_scanner_conn_comp - LCB but no CCB"); + return ; + } + } + } + else if (p_lcb->link_state != LST_CONNECTING) + { + L2CAP_TRACE_ERROR ("L2CAP got BLE scanner conn_comp in bad state: %d", p_lcb->link_state); + return; + } + btu_stop_timer(&p_lcb->timer_entry); + + /* Save the handle */ + p_lcb->handle = handle; + + /* Connected OK. Change state to connected, we were scanning so we are master */ + p_lcb->link_role = HCI_ROLE_MASTER; + p_lcb->transport = BT_TRANSPORT_LE; + + /* update link parameter, set slave link as non-spec default upon link up */ + p_lcb->min_interval = p_lcb->max_interval = conn_interval; + p_lcb->timeout = conn_timeout; + p_lcb->latency = conn_latency; + p_lcb->conn_update_mask = L2C_BLE_NOT_DEFAULT_PARAM; + + /* If there are any preferred connection parameters, set them now */ + if ( (p_dev_rec->conn_params.min_conn_int >= BTM_BLE_CONN_INT_MIN ) && + (p_dev_rec->conn_params.min_conn_int <= BTM_BLE_CONN_INT_MAX ) && + (p_dev_rec->conn_params.max_conn_int >= BTM_BLE_CONN_INT_MIN ) && + (p_dev_rec->conn_params.max_conn_int <= BTM_BLE_CONN_INT_MAX ) && + (p_dev_rec->conn_params.slave_latency <= BTM_BLE_CONN_LATENCY_MAX ) && + (p_dev_rec->conn_params.supervision_tout >= BTM_BLE_CONN_SUP_TOUT_MIN) && + (p_dev_rec->conn_params.supervision_tout <= BTM_BLE_CONN_SUP_TOUT_MAX) && + ((conn_interval < p_dev_rec->conn_params.min_conn_int && + p_dev_rec->conn_params.min_conn_int != BTM_BLE_CONN_PARAM_UNDEF) || + (conn_interval > p_dev_rec->conn_params.max_conn_int) || + (conn_latency > p_dev_rec->conn_params.slave_latency) || + (conn_timeout > p_dev_rec->conn_params.supervision_tout))) + { + L2CAP_TRACE_ERROR ("upd_ll_conn_params: HANDLE=%d min_conn_int=%d max_conn_int=%d slave_latency=%d supervision_tout=%d", + handle, p_dev_rec->conn_params.min_conn_int, p_dev_rec->conn_params.max_conn_int, + p_dev_rec->conn_params.slave_latency, p_dev_rec->conn_params.supervision_tout); + + p_lcb->min_interval = p_dev_rec->conn_params.min_conn_int; + p_lcb->max_interval = p_dev_rec->conn_params.max_conn_int; + p_lcb->timeout = p_dev_rec->conn_params.supervision_tout; + p_lcb->latency = p_dev_rec->conn_params.slave_latency; + + btsnd_hcic_ble_upd_ll_conn_params (handle, + p_dev_rec->conn_params.min_conn_int, + p_dev_rec->conn_params.max_conn_int, + p_dev_rec->conn_params.slave_latency, + p_dev_rec->conn_params.supervision_tout, + 0, 0); + } + + /* Tell BTM Acl management about the link */ + btm_acl_created (bda, NULL, p_dev_rec->sec_bd_name, handle, p_lcb->link_role, BT_TRANSPORT_LE); + + p_lcb->peer_chnl_mask[0] = L2CAP_FIXED_CHNL_ATT_BIT | L2CAP_FIXED_CHNL_BLE_SIG_BIT | L2CAP_FIXED_CHNL_SMP_BIT; + + btm_ble_set_conn_st(BLE_CONN_IDLE); + +#if BLE_PRIVACY_SPT == TRUE + btm_ble_disable_resolving_list(BTM_BLE_RL_INIT, TRUE); +#endif +} + + +/******************************************************************************* +** +** Function l2cble_advertiser_conn_comp +** +** Description This function is called when an HCI Connection Complete +** event is received while we are an advertiser (so we are slave). +** +** Returns void +** +*******************************************************************************/ +void l2cble_advertiser_conn_comp (UINT16 handle, BD_ADDR bda, tBLE_ADDR_TYPE type, + UINT16 conn_interval, UINT16 conn_latency, UINT16 conn_timeout) +{ + int i; + tL2C_LCB *p_lcb; + tBTM_SEC_DEV_REC *p_dev_rec; + UNUSED(type); + UNUSED(conn_interval); + UNUSED(conn_latency); + UNUSED(conn_timeout); + + /* See if we have a link control block for the remote device */ + p_lcb = l2cu_find_lcb_by_bd_addr (bda, BT_TRANSPORT_LE); + + /* If we don't have one, create one and accept the connection. */ + if (!p_lcb) + { + p_lcb = l2cu_allocate_lcb (bda, FALSE, BT_TRANSPORT_LE); + if (!p_lcb) + { + btm_sec_disconnect (handle, HCI_ERR_NO_CONNECTION); + L2CAP_TRACE_ERROR ("l2cble_advertiser_conn_comp - failed to allocate LCB"); + return; + } + else + { + if (!l2cu_initialize_fixed_ccb (p_lcb, L2CAP_ATT_CID, &l2cb.fixed_reg[L2CAP_ATT_CID - L2CAP_FIRST_FIXED_CHNL].fixed_chnl_opts)) + { + btm_sec_disconnect (handle, HCI_ERR_NO_CONNECTION); + L2CAP_TRACE_WARNING ("l2cble_scanner_conn_comp - LCB but no CCB"); + return ; + } + } + } + + /* Save the handle */ + p_lcb->handle = handle; + + /* Connected OK. Change state to connected, we were advertising, so we are slave */ + p_lcb->link_role = HCI_ROLE_SLAVE; + p_lcb->transport = BT_TRANSPORT_LE; + + /* update link parameter, set slave link as non-spec default upon link up */ + p_lcb->min_interval = p_lcb->max_interval = conn_interval; + p_lcb->timeout = conn_timeout; + p_lcb->latency = conn_latency; + p_lcb->conn_update_mask = L2C_BLE_NOT_DEFAULT_PARAM; + + /* Tell BTM Acl management about the link */ + p_dev_rec = btm_find_or_alloc_dev (bda); + + btm_acl_created (bda, NULL, p_dev_rec->sec_bd_name, handle, p_lcb->link_role, BT_TRANSPORT_LE); + +#if BLE_PRIVACY_SPT == TRUE + btm_ble_disable_resolving_list(BTM_BLE_RL_ADV, TRUE); +#endif + + p_lcb->peer_chnl_mask[0] = L2CAP_FIXED_CHNL_ATT_BIT | L2CAP_FIXED_CHNL_BLE_SIG_BIT | L2CAP_FIXED_CHNL_SMP_BIT; + + if (!HCI_LE_SLAVE_INIT_FEAT_EXC_SUPPORTED(controller_get_interface()->get_features_ble()->as_array)) + { + p_lcb->link_state = LST_CONNECTED; + l2cu_process_fixed_chnl_resp (p_lcb); + } + + /* when adv and initiating are both active, cancel the direct connection */ + if (l2cb.is_ble_connecting && memcmp(bda, l2cb.ble_connecting_bda, BD_ADDR_LEN) == 0) + { + L2CA_CancelBleConnectReq(bda); + } +} + +/******************************************************************************* +** +** Function l2cble_conn_comp +** +** Description This function is called when an HCI Connection Complete +** event is received. +** +** Returns void +** +*******************************************************************************/ +void l2cble_conn_comp(UINT16 handle, UINT8 role, BD_ADDR bda, tBLE_ADDR_TYPE type, + UINT16 conn_interval, UINT16 conn_latency, UINT16 conn_timeout) +{ + btm_ble_update_link_topology_mask(role, TRUE); + + if (role == HCI_ROLE_MASTER) + { + l2cble_scanner_conn_comp(handle, bda, type, conn_interval, conn_latency, conn_timeout); + } + else + { + l2cble_advertiser_conn_comp(handle, bda, type, conn_interval, conn_latency, conn_timeout); + } +} + +/******************************************************************************* +** +** 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; + } + } +} + +/******************************************************************************* +** +** Function l2cble_process_conn_update_evt +** +** Description This function enables the connection update request from remote +** after a successful connection update response is received. +** +** Returns void +** +*******************************************************************************/ +void l2cble_process_conn_update_evt (UINT16 handle, UINT8 status) +{ + tL2C_LCB *p_lcb; + + L2CAP_TRACE_DEBUG("l2cble_process_conn_update_evt"); + + /* See if we have a link control block for the remote device */ + p_lcb = l2cu_find_lcb_by_handle(handle); + if (!p_lcb) + { + L2CAP_TRACE_WARNING("l2cble_process_conn_update_evt: Invalid handle: %d", handle); + return; + } + + p_lcb->conn_update_mask &= ~L2C_BLE_UPDATE_PENDING; + + if (status != HCI_SUCCESS) + { + L2CAP_TRACE_WARNING("l2cble_process_conn_update_evt: Error status: %d", status); + } + + l2cble_start_conn_update(p_lcb); + + L2CAP_TRACE_DEBUG("l2cble_process_conn_update_evt: conn_update_mask=%d", p_lcb->conn_update_mask); +} +/******************************************************************************* +** +** Function l2cble_process_sig_cmd +** +** Description This function is called when a signalling packet is received +** on the BLE signalling CID +** +** Returns void +** +*******************************************************************************/ +void l2cble_process_sig_cmd (tL2C_LCB *p_lcb, UINT8 *p, UINT16 pkt_len) +{ + UINT8 *p_pkt_end; + UINT8 cmd_code, id; + UINT16 cmd_len; + UINT16 min_interval, max_interval, latency, timeout; + + p_pkt_end = p + pkt_len; + + STREAM_TO_UINT8 (cmd_code, p); + STREAM_TO_UINT8 (id, p); + STREAM_TO_UINT16 (cmd_len, p); + + /* Check command length does not exceed packet length */ + if ((p + cmd_len) > p_pkt_end) + { + L2CAP_TRACE_WARNING ("L2CAP - LE - format error, pkt_len: %d cmd_len: %d code: %d", pkt_len, cmd_len, cmd_code); + return; + } + + switch (cmd_code) + { + case L2CAP_CMD_REJECT: + case L2CAP_CMD_ECHO_RSP: + case L2CAP_CMD_INFO_RSP: + p += 2; + break; + case L2CAP_CMD_ECHO_REQ: + case L2CAP_CMD_INFO_REQ: + l2cu_send_peer_cmd_reject (p_lcb, L2CAP_CMD_REJ_NOT_UNDERSTOOD, id, 0, 0); + break; + + case L2CAP_CMD_BLE_UPDATE_REQ: + STREAM_TO_UINT16 (min_interval, p); /* 0x0006 - 0x0C80 */ + STREAM_TO_UINT16 (max_interval, p); /* 0x0006 - 0x0C80 */ + STREAM_TO_UINT16 (latency, p); /* 0x0000 - 0x03E8 */ + STREAM_TO_UINT16 (timeout, p); /* 0x000A - 0x0C80 */ + /* If we are a master, the slave wants to update the parameters */ + if (p_lcb->link_role == HCI_ROLE_MASTER) + { + if (min_interval < BTM_BLE_CONN_INT_MIN_LIMIT) + min_interval = BTM_BLE_CONN_INT_MIN_LIMIT; + + if (min_interval < BTM_BLE_CONN_INT_MIN || min_interval > BTM_BLE_CONN_INT_MAX || + max_interval < BTM_BLE_CONN_INT_MIN || max_interval > BTM_BLE_CONN_INT_MAX || + latency > BTM_BLE_CONN_LATENCY_MAX || + /*(timeout >= max_interval && latency > (timeout * 10/(max_interval * 1.25) - 1)) ||*/ + timeout < BTM_BLE_CONN_SUP_TOUT_MIN || timeout > BTM_BLE_CONN_SUP_TOUT_MAX || + max_interval < min_interval) + { + l2cu_send_peer_ble_par_rsp (p_lcb, L2CAP_CFG_UNACCEPTABLE_PARAMS, id); + } + else + { + + l2cu_send_peer_ble_par_rsp (p_lcb, L2CAP_CFG_OK, id); + + p_lcb->min_interval = min_interval; + p_lcb->max_interval = max_interval; + p_lcb->latency = latency; + p_lcb->timeout = timeout; + p_lcb->conn_update_mask |= L2C_BLE_NEW_CONN_PARAM; + + l2cble_start_conn_update(p_lcb); + } + } + else + l2cu_send_peer_cmd_reject (p_lcb, L2CAP_CMD_REJ_NOT_UNDERSTOOD, id, 0, 0); + break; + + case L2CAP_CMD_BLE_UPDATE_RSP: + p += 2; + break; + + default: + L2CAP_TRACE_WARNING ("L2CAP - LE - unknown cmd code: %d", cmd_code); + l2cu_send_peer_cmd_reject (p_lcb, L2CAP_CMD_REJ_NOT_UNDERSTOOD, id, 0, 0); + return; + } +} + +/******************************************************************************* +** +** Function l2cble_init_direct_conn +** +** Description This function is to initate a direct connection +** +** Returns TRUE connection initiated, FALSE otherwise. +** +*******************************************************************************/ +BOOLEAN l2cble_init_direct_conn (tL2C_LCB *p_lcb) +{ + tBTM_SEC_DEV_REC *p_dev_rec = btm_find_or_alloc_dev (p_lcb->remote_bd_addr); + tBTM_BLE_CB *p_cb = &btm_cb.ble_ctr_cb; + UINT16 scan_int; + UINT16 scan_win; + BD_ADDR peer_addr; + UINT8 peer_addr_type = BLE_ADDR_PUBLIC; + UINT8 own_addr_type = BLE_ADDR_PUBLIC; + + /* There can be only one BLE connection request outstanding at a time */ + if (p_dev_rec == NULL) + { + L2CAP_TRACE_WARNING ("unknown device, can not initate connection"); + return(FALSE); + } + + scan_int = (p_cb->scan_int == BTM_BLE_SCAN_PARAM_UNDEF) ? BTM_BLE_SCAN_FAST_INT : p_cb->scan_int; + scan_win = (p_cb->scan_win == BTM_BLE_SCAN_PARAM_UNDEF) ? BTM_BLE_SCAN_FAST_WIN : p_cb->scan_win; + + peer_addr_type = p_lcb->ble_addr_type; + memcpy(peer_addr, p_lcb->remote_bd_addr, BD_ADDR_LEN); + +#if ( (defined BLE_PRIVACY_SPT) && (BLE_PRIVACY_SPT == TRUE)) + own_addr_type = btm_cb.ble_ctr_cb.privacy_mode ? BLE_ADDR_RANDOM : BLE_ADDR_PUBLIC; + if (p_dev_rec->ble.in_controller_list & BTM_RESOLVING_LIST_BIT) + { + if (btm_cb.ble_ctr_cb.privacy_mode >= BTM_PRIVACY_1_2) + own_addr_type |= BLE_ADDR_TYPE_ID_BIT; + + btm_ble_enable_resolving_list(BTM_BLE_RL_INIT); + btm_random_pseudo_to_identity_addr(peer_addr, &peer_addr_type); + } + else + btm_ble_disable_resolving_list(BTM_BLE_RL_INIT, TRUE); +#endif + + if (!btm_ble_topology_check(BTM_BLE_STATE_INIT)) + { + l2cu_release_lcb (p_lcb); + L2CAP_TRACE_ERROR("initate direct connection fail, topology limitation"); + return FALSE; + } + + if (!btsnd_hcic_ble_create_ll_conn (scan_int,/* UINT16 scan_int */ + scan_win, /* UINT16 scan_win */ + FALSE, /* UINT8 white_list */ + peer_addr_type, /* UINT8 addr_type_peer */ + peer_addr, /* BD_ADDR bda_peer */ + own_addr_type, /* UINT8 addr_type_own */ + (UINT16) ((p_dev_rec->conn_params.min_conn_int != BTM_BLE_CONN_PARAM_UNDEF) ? + p_dev_rec->conn_params.min_conn_int : BTM_BLE_CONN_INT_MIN_DEF), /* UINT16 conn_int_min */ + (UINT16) ((p_dev_rec->conn_params.max_conn_int != BTM_BLE_CONN_PARAM_UNDEF) ? + p_dev_rec->conn_params.max_conn_int : BTM_BLE_CONN_INT_MAX_DEF), /* UINT16 conn_int_max */ + (UINT16) ((p_dev_rec->conn_params.slave_latency != BTM_BLE_CONN_PARAM_UNDEF) ? + p_dev_rec->conn_params.slave_latency : BTM_BLE_CONN_SLAVE_LATENCY_DEF), /* UINT16 conn_latency */ + (UINT16) ((p_dev_rec->conn_params.supervision_tout != BTM_BLE_CONN_PARAM_UNDEF) ? + p_dev_rec->conn_params.supervision_tout : BTM_BLE_CONN_TIMEOUT_DEF), /* conn_timeout */ + 0, /* UINT16 min_len */ + 0)) /* UINT16 max_len */ + { + l2cu_release_lcb (p_lcb); + L2CAP_TRACE_ERROR("initate direct connection fail, no resources"); + return (FALSE); + } + else + { + p_lcb->link_state = LST_CONNECTING; + l2cb.is_ble_connecting = TRUE; + memcpy (l2cb.ble_connecting_bda, p_lcb->remote_bd_addr, BD_ADDR_LEN); + btu_start_timer (&p_lcb->timer_entry, BTU_TTYPE_L2CAP_LINK, L2CAP_BLE_LINK_CONNECT_TOUT); + btm_ble_set_conn_st (BLE_DIR_CONN); + + return (TRUE); + } +} + +/******************************************************************************* +** +** Function l2cble_create_conn +** +** Description This function initiates an acl connection via HCI +** +** Returns TRUE if successful, FALSE if connection not started. +** +*******************************************************************************/ +BOOLEAN l2cble_create_conn (tL2C_LCB *p_lcb) +{ + tBTM_BLE_CONN_ST conn_st = btm_ble_get_conn_st(); + BOOLEAN rt = FALSE; + + /* There can be only one BLE connection request outstanding at a time */ + if (conn_st == BLE_CONN_IDLE) + { + rt = l2cble_init_direct_conn(p_lcb); + } + else + { + L2CAP_TRACE_WARNING ("L2CAP - LE - cannot start new connection at conn st: %d", conn_st); + + btm_ble_enqueue_direct_conn_req(p_lcb); + + if (conn_st == BLE_BG_CONN) + btm_ble_suspend_bg_conn(); + + rt = TRUE; + } + return rt; +} + +/******************************************************************************* +** +** Function l2c_link_processs_ble_num_bufs +** +** Description This function is called when a "controller buffer size" +** event is first received from the controller. It updates +** the L2CAP values. +** +** Returns void +** +*******************************************************************************/ +void l2c_link_processs_ble_num_bufs (UINT16 num_lm_ble_bufs) +{ + if (num_lm_ble_bufs == 0) + { + num_lm_ble_bufs = L2C_DEF_NUM_BLE_BUF_SHARED; + l2cb.num_lm_acl_bufs -= L2C_DEF_NUM_BLE_BUF_SHARED; + } + + l2cb.num_lm_ble_bufs = l2cb.controller_le_xmit_window = num_lm_ble_bufs; +} + +/******************************************************************************* +** +** Function l2c_ble_link_adjust_allocation +** +** Description This function is called when a link is created or removed +** to calculate the amount of packets each link may send to +** the HCI without an ack coming back. +** +** Currently, this is a simple allocation, dividing the +** number of Controller Packets by the number of links. In +** the future, QOS configuration should be examined. +** +** Returns void +** +*******************************************************************************/ +void l2c_ble_link_adjust_allocation (void) +{ + UINT16 qq, yy, qq_remainder; + tL2C_LCB *p_lcb; + UINT16 hi_quota, low_quota; + UINT16 num_lowpri_links = 0; + UINT16 num_hipri_links = 0; + UINT16 controller_xmit_quota = l2cb.num_lm_ble_bufs; + UINT16 high_pri_link_quota = L2CAP_HIGH_PRI_MIN_XMIT_QUOTA_A; + + /* If no links active, reset buffer quotas and controller buffers */ + if (l2cb.num_ble_links_active == 0) + { + l2cb.controller_le_xmit_window = l2cb.num_lm_ble_bufs; + l2cb.ble_round_robin_quota = l2cb.ble_round_robin_unacked = 0; + return; + } + + /* First, count the links */ + for (yy = 0, p_lcb = &l2cb.lcb_pool[0]; yy < MAX_L2CAP_LINKS; yy++, p_lcb++) + { + if (p_lcb->in_use && p_lcb->transport == BT_TRANSPORT_LE) + { + if (p_lcb->acl_priority == L2CAP_PRIORITY_HIGH) + num_hipri_links++; + else + num_lowpri_links++; + } + } + + /* now adjust high priority link quota */ + low_quota = num_lowpri_links ? 1 : 0; + while ( (num_hipri_links * high_pri_link_quota + low_quota) > controller_xmit_quota ) + high_pri_link_quota--; + + + /* Work out the xmit quota and buffer quota high and low priorities */ + hi_quota = num_hipri_links * high_pri_link_quota; + low_quota = (hi_quota < controller_xmit_quota) ? controller_xmit_quota - hi_quota : 1; + + /* Work out and save the HCI xmit quota for each low priority link */ + + /* If each low priority link cannot have at least one buffer */ + if (num_lowpri_links > low_quota) + { + l2cb.ble_round_robin_quota = low_quota; + qq = qq_remainder = 0; + } + /* If each low priority link can have at least one buffer */ + else if (num_lowpri_links > 0) + { + l2cb.ble_round_robin_quota = 0; + l2cb.ble_round_robin_unacked = 0; + qq = low_quota / num_lowpri_links; + qq_remainder = low_quota % num_lowpri_links; + } + /* If no low priority link */ + else + { + l2cb.ble_round_robin_quota = 0; + l2cb.ble_round_robin_unacked = 0; + qq = qq_remainder = 0; + } + L2CAP_TRACE_EVENT ("l2c_ble_link_adjust_allocation num_hipri: %u num_lowpri: %u low_quota: %u round_robin_quota: %u qq: %u", + num_hipri_links, num_lowpri_links, low_quota, + l2cb.ble_round_robin_quota, qq); + + /* Now, assign the quotas to each link */ + for (yy = 0, p_lcb = &l2cb.lcb_pool[0]; yy < MAX_L2CAP_LINKS; yy++, p_lcb++) + { + if (p_lcb->in_use && p_lcb->transport == BT_TRANSPORT_LE) + { + if (p_lcb->acl_priority == L2CAP_PRIORITY_HIGH) + { + p_lcb->link_xmit_quota = high_pri_link_quota; + } + else + { + /* Safety check in case we switched to round-robin with something outstanding */ + /* if sent_not_acked is added into round_robin_unacked then don't add it again */ + /* l2cap keeps updating sent_not_acked for exiting from round robin */ + if (( p_lcb->link_xmit_quota > 0 )&&( qq == 0 )) + l2cb.ble_round_robin_unacked += p_lcb->sent_not_acked; + + p_lcb->link_xmit_quota = qq; + if (qq_remainder > 0) + { + p_lcb->link_xmit_quota++; + qq_remainder--; + } + } + + L2CAP_TRACE_EVENT("l2c_ble_link_adjust_allocation LCB %d Priority: %d XmitQuota: %d", + yy, p_lcb->acl_priority, p_lcb->link_xmit_quota); + + L2CAP_TRACE_EVENT(" SentNotAcked: %d RRUnacked: %d", + p_lcb->sent_not_acked, l2cb.round_robin_unacked); + + /* There is a special case where we have readjusted the link quotas and */ + /* this link may have sent anything but some other link sent packets so */ + /* so we may need a timer to kick off this link's transmissions. */ + if ( (p_lcb->link_state == LST_CONNECTED) + && (!list_is_empty(p_lcb->link_xmit_data_q)) + && (p_lcb->sent_not_acked < p_lcb->link_xmit_quota) ) + btu_start_timer (&p_lcb->timer_entry, BTU_TTYPE_L2CAP_LINK, L2CAP_LINK_FLOW_CONTROL_TOUT); + } + } +} + +#if (defined BLE_LLT_INCLUDED) && (BLE_LLT_INCLUDED == TRUE) +/******************************************************************************* +** +** Function l2cble_process_rc_param_request_evt +** +** Description process LE Remote Connection Parameter Request Event. +** +** Returns void +** +*******************************************************************************/ +void l2cble_process_rc_param_request_evt(UINT16 handle, UINT16 int_min, UINT16 int_max, + UINT16 latency, UINT16 timeout) +{ + tL2C_LCB *p_lcb = l2cu_find_lcb_by_handle (handle); + + if (p_lcb != NULL) + { + p_lcb->min_interval = int_min; + p_lcb->max_interval = int_max; + p_lcb->latency = latency; + p_lcb->timeout = timeout; + + /* if update is enabled, always accept connection parameter update */ + if ((p_lcb->conn_update_mask & L2C_BLE_CONN_UPDATE_DISABLE) == 0) + { + btsnd_hcic_ble_rc_param_req_reply(handle, int_min, int_max, latency, timeout, 0, 0); + } + else + { + L2CAP_TRACE_EVENT ("L2CAP - LE - update currently disabled"); + p_lcb->conn_update_mask |= L2C_BLE_NEW_CONN_PARAM; + btsnd_hcic_ble_rc_param_req_neg_reply (handle,HCI_ERR_UNACCEPT_CONN_INTERVAL); + } + + } + else + { + L2CAP_TRACE_WARNING("No link to update connection parameter") + } +} +#endif + +/******************************************************************************* +** +** Function l2cble_update_data_length +** +** Description This function update link tx data length if applicable +** +** Returns void +** +*******************************************************************************/ +void l2cble_update_data_length(tL2C_LCB *p_lcb) +{ + UINT16 tx_mtu = 0; + UINT16 i = 0; + + L2CAP_TRACE_DEBUG("%s", __FUNCTION__); + + /* See if we have a link control block for the connection */ + if (p_lcb == NULL) + return; + + for (i = 0; i < L2CAP_NUM_FIXED_CHNLS; i++) + { + if (i + L2CAP_FIRST_FIXED_CHNL != L2CAP_BLE_SIGNALLING_CID) + { + if ((p_lcb->p_fixed_ccbs[i] != NULL) && + (tx_mtu < (p_lcb->p_fixed_ccbs[i]->tx_data_len + L2CAP_PKT_OVERHEAD))) + tx_mtu = p_lcb->p_fixed_ccbs[i]->tx_data_len + L2CAP_PKT_OVERHEAD; + } + } + + if (tx_mtu > BTM_BLE_DATA_SIZE_MAX) + tx_mtu = BTM_BLE_DATA_SIZE_MAX; + + /* update TX data length if changed */ + if (p_lcb->tx_data_len != tx_mtu) + BTM_SetBleDataLength(p_lcb->remote_bd_addr, tx_mtu); + +} + +/******************************************************************************* +** +** Function l2cble_process_data_length_change_evt +** +** Description This function process the data length change event +** +** Returns void +** +*******************************************************************************/ +void l2cble_process_data_length_change_event(UINT16 handle, UINT16 tx_data_len, UINT16 rx_data_len) +{ + tL2C_LCB *p_lcb = l2cu_find_lcb_by_handle(handle); + + L2CAP_TRACE_DEBUG("%s TX data len = %d", __FUNCTION__, tx_data_len); + if (p_lcb == NULL) + return; + + if (tx_data_len > 0) + p_lcb->tx_data_len = tx_data_len; + + /* ignore rx_data len for now */ +} + +/******************************************************************************* +** +** Function l2cble_set_fixed_channel_tx_data_length +** +** Description This function update max fixed channel tx data length if applicable +** +** Returns void +** +*******************************************************************************/ +void l2cble_set_fixed_channel_tx_data_length(BD_ADDR remote_bda, UINT16 fix_cid, UINT16 tx_mtu) +{ + tL2C_LCB *p_lcb = l2cu_find_lcb_by_bd_addr(remote_bda, BT_TRANSPORT_LE); + UINT16 cid = fix_cid - L2CAP_FIRST_FIXED_CHNL; + + L2CAP_TRACE_DEBUG("%s TX MTU = %d", __FUNCTION__, tx_mtu); + + if (!controller_get_interface()->supports_ble_packet_extension()) + { + L2CAP_TRACE_WARNING("%s, request not supported", __FUNCTION__); + return; + } + + /* See if we have a link control block for the connection */ + if (p_lcb == NULL) + return; + + if (p_lcb->p_fixed_ccbs[cid] != NULL) + { + if (tx_mtu > BTM_BLE_DATA_SIZE_MAX) + tx_mtu = BTM_BLE_DATA_SIZE_MAX; + + p_lcb->p_fixed_ccbs[cid]->tx_data_len = tx_mtu; + } + + l2cble_update_data_length(p_lcb); +} + +#endif /* (BLE_INCLUDED == TRUE) */ diff --git a/components/bt/bluedroid/stack/l2cap/l2c_csm.c b/components/bt/bluedroid/stack/l2cap/l2c_csm.c new file mode 100755 index 0000000000..7a77f36f18 --- /dev/null +++ b/components/bt/bluedroid/stack/l2cap/l2c_csm.c @@ -0,0 +1,1328 @@ +/****************************************************************************** + * + * Copyright (C) 1999-2012 Broadcom Corporation + * + * 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 L2CAP channel state machine + * + ******************************************************************************/ + +#include +#include +#include + +#include "bt_target.h" +#include "gki.h" +#include "hcidefs.h" +#include "hcimsgs.h" +#include "l2cdefs.h" +#include "l2c_int.h" +#include "btm_int.h" +#include "btu.h" +#include "hcimsgs.h" + +/********************************************************************************/ +/* L O C A L F U N C T I O N P R O T O T Y P E S */ +/********************************************************************************/ +static void l2c_csm_closed (tL2C_CCB *p_ccb, UINT16 event, void *p_data); +static void l2c_csm_orig_w4_sec_comp (tL2C_CCB *p_ccb, UINT16 event, void *p_data); +static void l2c_csm_term_w4_sec_comp (tL2C_CCB *p_ccb, UINT16 event, void *p_data); +static void l2c_csm_w4_l2cap_connect_rsp (tL2C_CCB *p_ccb, UINT16 event, void *p_data); +static void l2c_csm_w4_l2ca_connect_rsp (tL2C_CCB *p_ccb, UINT16 event, void *p_data); +static void l2c_csm_config (tL2C_CCB *p_ccb, UINT16 event, void *p_data); +static void l2c_csm_open (tL2C_CCB *p_ccb, UINT16 event, void *p_data); +static void l2c_csm_w4_l2cap_disconnect_rsp (tL2C_CCB *p_ccb, UINT16 event, void *p_data); +static void l2c_csm_w4_l2ca_disconnect_rsp (tL2C_CCB *p_ccb, UINT16 event, void *p_data); + +#if (BT_TRACE_VERBOSE == TRUE) +static char *l2c_csm_get_event_name (UINT16 event); +#endif + +/******************************************************************************* +** +** Function l2c_csm_execute +** +** Description This function executes the state machine. +** +** Returns void +** +*******************************************************************************/ +void l2c_csm_execute (tL2C_CCB *p_ccb, UINT16 event, void *p_data) +{ + switch (p_ccb->chnl_state) + { + case CST_CLOSED: + l2c_csm_closed (p_ccb, event, p_data); + break; + + case CST_ORIG_W4_SEC_COMP: + l2c_csm_orig_w4_sec_comp (p_ccb, event, p_data); + break; + + case CST_TERM_W4_SEC_COMP: + l2c_csm_term_w4_sec_comp (p_ccb, event, p_data); + break; + + case CST_W4_L2CAP_CONNECT_RSP: + l2c_csm_w4_l2cap_connect_rsp (p_ccb, event, p_data); + break; + + case CST_W4_L2CA_CONNECT_RSP: + l2c_csm_w4_l2ca_connect_rsp (p_ccb, event, p_data); + break; + + case CST_CONFIG: + l2c_csm_config (p_ccb, event, p_data); + break; + + case CST_OPEN: + l2c_csm_open (p_ccb, event, p_data); + break; + + case CST_W4_L2CAP_DISCONNECT_RSP: + l2c_csm_w4_l2cap_disconnect_rsp (p_ccb, event, p_data); + break; + + case CST_W4_L2CA_DISCONNECT_RSP: + l2c_csm_w4_l2ca_disconnect_rsp (p_ccb, event, p_data); + break; + + default: + L2CAP_TRACE_DEBUG("Unhandled event! event = %d",event); + break; + } +} + +/******************************************************************************* +** +** Function l2c_csm_closed +** +** Description This function handles events when the channel is in +** CLOSED state. This state exists only when the link is +** being initially established. +** +** Returns void +** +*******************************************************************************/ +static void l2c_csm_closed (tL2C_CCB *p_ccb, UINT16 event, void *p_data) +{ + tL2C_CONN_INFO *p_ci = (tL2C_CONN_INFO *)p_data; + UINT16 local_cid = p_ccb->local_cid; + tL2CA_DISCONNECT_IND_CB *disconnect_ind; + tL2CA_CONNECT_CFM_CB *connect_cfm; + + if (p_ccb->p_rcb == NULL) + { +#if (BT_TRACE_VERBOSE == TRUE) + L2CAP_TRACE_ERROR ("L2CAP - LCID: 0x%04x st: CLOSED evt: %s p_rcb == NULL", p_ccb->local_cid, l2c_csm_get_event_name (event)); +#else + L2CAP_TRACE_ERROR ("L2CAP - LCID: 0x%04x st: CLOSED evt: 0x%04x p_rcb == NULL", p_ccb->local_cid, event); +#endif + return; + } + +#if (L2CAP_UCD_INCLUDED == TRUE) + if ( local_cid == L2CAP_CONNECTIONLESS_CID ) + { + /* check if this event can be processed by UCD */ + if ( l2c_ucd_process_event (p_ccb, event, p_data) ) + { + /* The event is processed by UCD state machine */ + return; + } + } +#endif + + disconnect_ind = p_ccb->p_rcb->api.pL2CA_DisconnectInd_Cb; + connect_cfm = p_ccb->p_rcb->api.pL2CA_ConnectCfm_Cb; + +#if (BT_TRACE_VERBOSE == TRUE) + L2CAP_TRACE_EVENT ("L2CAP - LCID: 0x%04x st: CLOSED evt: %s", p_ccb->local_cid, l2c_csm_get_event_name (event)); +#else + L2CAP_TRACE_EVENT ("L2CAP - st: CLOSED evt: %d", event); +#endif + + switch (event) + { + case L2CEVT_LP_DISCONNECT_IND: /* Link was disconnected */ + L2CAP_TRACE_API ("L2CAP - Calling Disconnect_Ind_Cb(), CID: 0x%04x No Conf Needed", p_ccb->local_cid); + l2cu_release_ccb (p_ccb); + (*disconnect_ind)(local_cid, FALSE); + break; + + case L2CEVT_LP_CONNECT_CFM: /* Link came up */ + p_ccb->chnl_state = CST_ORIG_W4_SEC_COMP; + btm_sec_l2cap_access_req (p_ccb->p_lcb->remote_bd_addr, p_ccb->p_rcb->psm, + p_ccb->p_lcb->handle, TRUE, &l2c_link_sec_comp, p_ccb); + break; + + case L2CEVT_LP_CONNECT_CFM_NEG: /* Link failed */ + /* Disconnect unless ACL collision and upper layer wants to handle it */ + if (p_ci->status != HCI_ERR_CONNECTION_EXISTS + || !btm_acl_notif_conn_collision(p_ccb->p_lcb->remote_bd_addr)) + { + L2CAP_TRACE_API ("L2CAP - Calling ConnectCfm_Cb(), CID: 0x%04x Status: %d", p_ccb->local_cid, p_ci->status); + l2cu_release_ccb (p_ccb); + (*connect_cfm)(local_cid, p_ci->status); + } + break; + + case L2CEVT_L2CA_CONNECT_REQ: /* API connect request */ + /* Cancel sniff mode if needed */ + { + tBTM_PM_PWR_MD settings; +// btla-specific ++ + memset((void*)&settings, 0, sizeof(settings)); +// btla-specific -- + settings.mode = BTM_PM_MD_ACTIVE; +/* COVERITY +Event uninit_use_in_call: Using uninitialized value "settings" (field "settings".timeout uninitialized) in call to function "BTM_SetPowerMode" [details] +Event uninit_use_in_call: Using uninitialized value "settings.max" in call to function "BTM_SetPowerMode" [details] +Event uninit_use_in_call: Using uninitialized value "settings.min" in call to function "BTM_SetPowerMode" +// FALSE-POSITIVE error from Coverity test-tool. Please do NOT remove following comment. +// coverity[uninit_use_in_call] False-positive: setting the mode to BTM_PM_MD_ACTIVE only uses settings.mode the other data members of tBTM_PM_PWR_MD are ignored +*/ + BTM_SetPowerMode (BTM_PM_SET_ONLY_ID, p_ccb->p_lcb->remote_bd_addr, &settings); + } + + /* If sec access does not result in started SEC_COM or COMP_NEG are already processed */ + if (btm_sec_l2cap_access_req (p_ccb->p_lcb->remote_bd_addr, p_ccb->p_rcb->psm, + p_ccb->p_lcb->handle, TRUE, &l2c_link_sec_comp, p_ccb) == BTM_CMD_STARTED) + p_ccb->chnl_state = CST_ORIG_W4_SEC_COMP; + break; + + case L2CEVT_SEC_COMP: + p_ccb->chnl_state = CST_W4_L2CAP_CONNECT_RSP; + + /* Wait for the info resp in this state before sending connect req (if needed) */ + if (!p_ccb->p_lcb->w4_info_rsp) + { + /* Need to have at least one compatible channel to continue */ + if (!l2c_fcr_chk_chan_modes(p_ccb)) + { + l2cu_release_ccb (p_ccb); + (*p_ccb->p_rcb->api.pL2CA_ConnectCfm_Cb)(local_cid, L2CAP_CONN_NO_LINK); + } + else + { + l2cu_send_peer_connect_req (p_ccb); + btu_start_timer (&p_ccb->timer_entry, BTU_TTYPE_L2CAP_CHNL, L2CAP_CHNL_CONNECT_TOUT); + } + } + break; + + case L2CEVT_SEC_COMP_NEG: /* something is really bad with security */ + L2CAP_TRACE_API ("L2CAP - Calling ConnectCfm_Cb(), CID: 0x%04x Status: %d", p_ccb->local_cid, L2CAP_CONN_TIMEOUT); + l2cu_release_ccb (p_ccb); + (*connect_cfm)(local_cid, L2CAP_CONN_SECURITY_BLOCK); + break; + + case L2CEVT_L2CAP_CONNECT_REQ: /* Peer connect request */ + /* stop link timer to avoid race condition between A2MP, Security, and L2CAP */ + btu_stop_timer (&p_ccb->p_lcb->timer_entry); + + /* Cancel sniff mode if needed */ + { + tBTM_PM_PWR_MD settings; +// btla-specific ++ + memset((void*)&settings, 0, sizeof(settings)); +// btla-specific -- + settings.mode = BTM_PM_MD_ACTIVE; +/* COVERITY +Event uninit_use_in_call: Using uninitialized value "settings" (field "settings".timeout uninitialized) in call to function "BTM_SetPowerMode" [details] +Event uninit_use_in_call: Using uninitialized value "settings.max" in call to function "BTM_SetPowerMode" [details] +Event uninit_use_in_call: Using uninitialized value "settings.min" in call to function "BTM_SetPowerMode" +// FALSE-POSITIVE error from Coverity test-tool. Please do NOT remove following comment. +// coverity[uninit_use_in_call] False-positive: setting the mode to BTM_PM_MD_ACTIVE only uses settings.mode the other data members of tBTM_PM_PWR_MD are ignored +*/ + BTM_SetPowerMode (BTM_PM_SET_ONLY_ID, p_ccb->p_lcb->remote_bd_addr, &settings); + } + + p_ccb->chnl_state = CST_TERM_W4_SEC_COMP; + if (btm_sec_l2cap_access_req (p_ccb->p_lcb->remote_bd_addr, p_ccb->p_rcb->psm, + p_ccb->p_lcb->handle, FALSE, &l2c_link_sec_comp, p_ccb) == BTM_CMD_STARTED) + { + /* started the security process, tell the peer to set a longer timer */ + l2cu_send_peer_connect_rsp(p_ccb, L2CAP_CONN_PENDING, 0); + } + break; + + case L2CEVT_TIMEOUT: + L2CAP_TRACE_API ("L2CAP - Calling ConnectCfm_Cb(), CID: 0x%04x Status: %d", p_ccb->local_cid, L2CAP_CONN_TIMEOUT); + l2cu_release_ccb (p_ccb); + (*connect_cfm)(local_cid, L2CAP_CONN_TIMEOUT); + break; + + case L2CEVT_L2CAP_DATA: /* Peer data packet rcvd */ + case L2CEVT_L2CA_DATA_WRITE: /* Upper layer data to send */ + GKI_freebuf (p_data); + break; + + case L2CEVT_L2CA_DISCONNECT_REQ: /* Upper wants to disconnect */ + l2cu_release_ccb (p_ccb); + break; + } +} + + +/******************************************************************************* +** +** Function l2c_csm_orig_w4_sec_comp +** +** Description This function handles events when the channel is in +** CST_ORIG_W4_SEC_COMP state. +** +** Returns void +** +*******************************************************************************/ +static void l2c_csm_orig_w4_sec_comp (tL2C_CCB *p_ccb, UINT16 event, void *p_data) +{ + tL2CA_DISCONNECT_IND_CB *disconnect_ind = p_ccb->p_rcb->api.pL2CA_DisconnectInd_Cb; + tL2CA_CONNECT_CFM_CB *connect_cfm = p_ccb->p_rcb->api.pL2CA_ConnectCfm_Cb; + UINT16 local_cid = p_ccb->local_cid; + +#if (BT_TRACE_VERBOSE == TRUE) + L2CAP_TRACE_EVENT ("L2CAP - LCID: 0x%04x st: ORIG_W4_SEC_COMP evt: %s", p_ccb->local_cid, l2c_csm_get_event_name (event)); +#else + L2CAP_TRACE_EVENT ("L2CAP - st: ORIG_W4_SEC_COMP evt: %d", event); +#endif + +#if (L2CAP_UCD_INCLUDED == TRUE) + if ( local_cid == L2CAP_CONNECTIONLESS_CID ) + { + /* check if this event can be processed by UCD */ + if ( l2c_ucd_process_event (p_ccb, event, p_data) ) + { + /* The event is processed by UCD state machine */ + return; + } + } +#endif + + switch (event) + { + case L2CEVT_LP_DISCONNECT_IND: /* Link was disconnected */ + L2CAP_TRACE_API ("L2CAP - Calling Disconnect_Ind_Cb(), CID: 0x%04x No Conf Needed", p_ccb->local_cid); + l2cu_release_ccb (p_ccb); + (*disconnect_ind)(local_cid, FALSE); + break; + + case L2CEVT_SEC_RE_SEND_CMD: /* BTM has enough info to proceed */ + case L2CEVT_LP_CONNECT_CFM: /* Link came up */ + btm_sec_l2cap_access_req (p_ccb->p_lcb->remote_bd_addr, p_ccb->p_rcb->psm, + p_ccb->p_lcb->handle, TRUE, &l2c_link_sec_comp, p_ccb); + break; + + case L2CEVT_SEC_COMP: /* Security completed success */ + /* Wait for the info resp in this state before sending connect req (if needed) */ + p_ccb->chnl_state = CST_W4_L2CAP_CONNECT_RSP; + if (!p_ccb->p_lcb->w4_info_rsp) + { + /* Need to have at least one compatible channel to continue */ + if (!l2c_fcr_chk_chan_modes(p_ccb)) + { + l2cu_release_ccb (p_ccb); + (*connect_cfm)(local_cid, L2CAP_CONN_NO_LINK); + } + else + { + btu_start_timer (&p_ccb->timer_entry, BTU_TTYPE_L2CAP_CHNL, L2CAP_CHNL_CONNECT_TOUT); + l2cu_send_peer_connect_req (p_ccb); /* Start Connection */ + } + } + break; + + case L2CEVT_SEC_COMP_NEG: + L2CAP_TRACE_API ("L2CAP - Calling ConnectCfm_Cb(), CID: 0x%04x Status: %d", p_ccb->local_cid, HCI_ERR_AUTH_FAILURE); + + /* If last channel immediately disconnect the ACL for better security. + Also prevents a race condition between BTM and L2CAP */ + if ( (p_ccb == p_ccb->p_lcb->ccb_queue.p_first_ccb) && (p_ccb == p_ccb->p_lcb->ccb_queue.p_last_ccb) ) + { + p_ccb->p_lcb->idle_timeout = 0; + } + + l2cu_release_ccb (p_ccb); + (*connect_cfm)(local_cid, HCI_ERR_AUTH_FAILURE); + break; + + case L2CEVT_L2CA_DATA_WRITE: /* Upper layer data to send */ + case L2CEVT_L2CAP_DATA: /* Peer data packet rcvd */ + GKI_freebuf (p_data); + break; + + case L2CEVT_L2CA_DISCONNECT_REQ: /* Upper wants to disconnect */ + /* Tell security manager to abort */ + btm_sec_abort_access_req (p_ccb->p_lcb->remote_bd_addr); + + l2cu_release_ccb (p_ccb); + break; + } +} + + +/******************************************************************************* +** +** Function l2c_csm_term_w4_sec_comp +** +** Description This function handles events when the channel is in +** CST_TERM_W4_SEC_COMP state. +** +** Returns void +** +*******************************************************************************/ +static void l2c_csm_term_w4_sec_comp (tL2C_CCB *p_ccb, UINT16 event, void *p_data) +{ +#if (BT_TRACE_VERBOSE == TRUE) + L2CAP_TRACE_EVENT ("L2CAP - LCID: 0x%04x st: TERM_W4_SEC_COMP evt: %s", p_ccb->local_cid, l2c_csm_get_event_name (event)); +#else + L2CAP_TRACE_EVENT ("L2CAP - st: TERM_W4_SEC_COMP evt: %d", event); +#endif + +#if (L2CAP_UCD_INCLUDED == TRUE) + if ( p_ccb->local_cid == L2CAP_CONNECTIONLESS_CID ) + { + /* check if this event can be processed by UCD */ + if ( l2c_ucd_process_event (p_ccb, event, p_data) ) + { + /* The event is processed by UCD state machine */ + return; + } + } +#endif + + switch (event) + { + case L2CEVT_LP_DISCONNECT_IND: /* Link was disconnected */ + /* Tell security manager to abort */ + btm_sec_abort_access_req (p_ccb->p_lcb->remote_bd_addr); + + l2cu_release_ccb (p_ccb); + break; + + case L2CEVT_SEC_COMP: + p_ccb->chnl_state = CST_W4_L2CA_CONNECT_RSP; + + /* Wait for the info resp in next state before sending connect ind (if needed) */ + if (!p_ccb->p_lcb->w4_info_rsp) + { + /* Don't need to get info from peer or already retrieved so continue */ + btu_start_timer (&p_ccb->timer_entry, BTU_TTYPE_L2CAP_CHNL, L2CAP_CHNL_CONNECT_TOUT); + L2CAP_TRACE_API ("L2CAP - Calling Connect_Ind_Cb(), CID: 0x%04x", p_ccb->local_cid); + + (*p_ccb->p_rcb->api.pL2CA_ConnectInd_Cb) (p_ccb->p_lcb->remote_bd_addr, p_ccb->local_cid, + p_ccb->p_rcb->psm, p_ccb->remote_id); + } + else + { + /* + ** L2CAP Connect Response will be sent out by 3 sec timer expiration + ** because Bluesoleil doesn't respond to L2CAP Information Request. + ** Bluesoleil seems to disconnect ACL link as failure case, because + ** it takes too long (4~7secs) to get response. + ** product version : Bluesoleil 2.1.1.0 EDR Release 060123 + ** stack version : 05.04.11.20060119 + */ + + /* Waiting for the info resp, tell the peer to set a longer timer */ + l2cu_send_peer_connect_rsp(p_ccb, L2CAP_CONN_PENDING, 0); + } + break; + + case L2CEVT_SEC_COMP_NEG: + if (((tL2C_CONN_INFO *)p_data)->status == BTM_DELAY_CHECK) + { + /* start a timer - encryption change not received before L2CAP connect req */ + btu_start_timer (&p_ccb->timer_entry, BTU_TTYPE_L2CAP_CHNL, L2CAP_DELAY_CHECK_SM4); + } + else + { + l2cu_send_peer_connect_rsp (p_ccb, L2CAP_CONN_SECURITY_BLOCK, 0); + l2cu_release_ccb (p_ccb); + } + break; + + case L2CEVT_L2CA_DATA_WRITE: /* Upper layer data to send */ + case L2CEVT_L2CAP_DATA: /* Peer data packet rcvd */ + GKI_freebuf (p_data); + break; + + case L2CEVT_L2CA_DISCONNECT_REQ: /* Upper wants to disconnect */ + l2cu_release_ccb (p_ccb); + break; + + case L2CEVT_L2CAP_DISCONNECT_REQ: /* Peer disconnected request */ + l2cu_send_peer_disc_rsp (p_ccb->p_lcb, p_ccb->remote_id, p_ccb->local_cid, p_ccb->remote_cid); + + /* Tell security manager to abort */ + btm_sec_abort_access_req (p_ccb->p_lcb->remote_bd_addr); + + l2cu_release_ccb (p_ccb); + break; + + case L2CEVT_TIMEOUT: + /* SM4 related. */ + if (!btsnd_hcic_disconnect (p_ccb->p_lcb->handle, HCI_ERR_AUTH_FAILURE)) + { + L2CAP_TRACE_API ("L2CAP - Calling btsnd_hcic_disconnect for handle %i failed", p_ccb->p_lcb->handle); + btu_start_timer (&p_ccb->timer_entry, BTU_TTYPE_L2CAP_CHNL, 1); + } + break; + + case L2CEVT_SEC_RE_SEND_CMD: /* BTM has enough info to proceed */ + btm_sec_l2cap_access_req (p_ccb->p_lcb->remote_bd_addr, p_ccb->p_rcb->psm, + p_ccb->p_lcb->handle, FALSE, &l2c_link_sec_comp, p_ccb); + break; + } +} + + +/******************************************************************************* +** +** Function l2c_csm_w4_l2cap_connect_rsp +** +** Description This function handles events when the channel is in +** CST_W4_L2CAP_CONNECT_RSP state. +** +** Returns void +** +*******************************************************************************/ +static void l2c_csm_w4_l2cap_connect_rsp (tL2C_CCB *p_ccb, UINT16 event, void *p_data) +{ + tL2C_CONN_INFO *p_ci = (tL2C_CONN_INFO *)p_data; + tL2CA_DISCONNECT_IND_CB *disconnect_ind = p_ccb->p_rcb->api.pL2CA_DisconnectInd_Cb; + tL2CA_CONNECT_CFM_CB *connect_cfm = p_ccb->p_rcb->api.pL2CA_ConnectCfm_Cb; + UINT16 local_cid = p_ccb->local_cid; + +#if (BT_TRACE_VERBOSE == TRUE) + L2CAP_TRACE_EVENT ("L2CAP - LCID: 0x%04x st: W4_L2CAP_CON_RSP evt: %s", p_ccb->local_cid, l2c_csm_get_event_name (event)); +#else + L2CAP_TRACE_EVENT ("L2CAP - st: W4_L2CAP_CON_RSP evt: %d", event); +#endif + + switch (event) + { + case L2CEVT_LP_DISCONNECT_IND: /* Link was disconnected */ + /* Send disc indication unless peer to peer race condition AND normal disconnect */ + /* *((UINT8 *)p_data) != HCI_ERR_PEER_USER happens when peer device try to disconnect for normal reason */ + p_ccb->chnl_state = CST_CLOSED; + if ((p_ccb->flags & CCB_FLAG_NO_RETRY) || !p_data || (*((UINT8 *)p_data) != HCI_ERR_PEER_USER)) + { + L2CAP_TRACE_API ("L2CAP - Calling Disconnect_Ind_Cb(), CID: 0x%04x No Conf Needed", + p_ccb->local_cid); + l2cu_release_ccb (p_ccb); + (*disconnect_ind)(local_cid, FALSE); + } + p_ccb->flags |= CCB_FLAG_NO_RETRY; + break; + + case L2CEVT_L2CAP_CONNECT_RSP: /* Got peer connect confirm */ + p_ccb->remote_cid = p_ci->remote_cid; + p_ccb->chnl_state = CST_CONFIG; + btu_start_timer (&p_ccb->timer_entry, BTU_TTYPE_L2CAP_CHNL, L2CAP_CHNL_CFG_TIMEOUT); + L2CAP_TRACE_API ("L2CAP - Calling Connect_Cfm_Cb(), CID: 0x%04x, Success", p_ccb->local_cid); + + (*p_ccb->p_rcb->api.pL2CA_ConnectCfm_Cb)(local_cid, L2CAP_CONN_OK); + break; + + case L2CEVT_L2CAP_CONNECT_RSP_PND: /* Got peer connect pending */ + p_ccb->remote_cid = p_ci->remote_cid; + btu_start_timer (&p_ccb->timer_entry, BTU_TTYPE_L2CAP_CHNL, L2CAP_CHNL_CONNECT_TOUT_EXT); + if (p_ccb->p_rcb->api.pL2CA_ConnectPnd_Cb) + { + L2CAP_TRACE_API ("L2CAP - Calling Connect_Pnd_Cb(), CID: 0x%04x", p_ccb->local_cid); + (*p_ccb->p_rcb->api.pL2CA_ConnectPnd_Cb)(p_ccb->local_cid); + } + break; + + case L2CEVT_L2CAP_CONNECT_RSP_NEG: /* Peer rejected connection */ + L2CAP_TRACE_API ("L2CAP - Calling Connect_Cfm_Cb(), CID: 0x%04x, Failure Code: %d", p_ccb->local_cid, p_ci->l2cap_result); + l2cu_release_ccb (p_ccb); + (*connect_cfm)(local_cid, p_ci->l2cap_result); + break; + + case L2CEVT_TIMEOUT: + L2CAP_TRACE_API ("L2CAP - Calling Connect_Cfm_Cb(), CID: 0x%04x, Timeout", p_ccb->local_cid); + l2cu_release_ccb (p_ccb); + (*connect_cfm)(local_cid, L2CAP_CONN_TIMEOUT); + break; + + case L2CEVT_L2CA_DISCONNECT_REQ: /* Upper wants to disconnect */ + /* If we know peer CID from connect pending, we can send disconnect */ + if (p_ccb->remote_cid != 0) + { + l2cu_send_peer_disc_req (p_ccb); + p_ccb->chnl_state = CST_W4_L2CAP_DISCONNECT_RSP; + btu_start_timer (&p_ccb->timer_entry, BTU_TTYPE_L2CAP_CHNL, L2CAP_CHNL_DISCONNECT_TOUT); + } + else + l2cu_release_ccb (p_ccb); + break; + + case L2CEVT_L2CA_DATA_WRITE: /* Upper layer data to send */ + case L2CEVT_L2CAP_DATA: /* Peer data packet rcvd */ + GKI_freebuf (p_data); + break; + + case L2CEVT_L2CAP_INFO_RSP: + /* Need to have at least one compatible channel to continue */ + if (!l2c_fcr_chk_chan_modes(p_ccb)) + { + l2cu_release_ccb (p_ccb); + (*connect_cfm)(local_cid, L2CAP_CONN_NO_LINK); + } + else + { + /* We have feature info, so now send peer connect request */ + btu_start_timer (&p_ccb->timer_entry, BTU_TTYPE_L2CAP_CHNL, L2CAP_CHNL_CONNECT_TOUT); + l2cu_send_peer_connect_req (p_ccb); /* Start Connection */ + } + break; + } +} + + +/******************************************************************************* +** +** Function l2c_csm_w4_l2ca_connect_rsp +** +** Description This function handles events when the channel is in +** CST_W4_L2CA_CONNECT_RSP state. +** +** Returns void +** +*******************************************************************************/ +static void l2c_csm_w4_l2ca_connect_rsp (tL2C_CCB *p_ccb, UINT16 event, void *p_data) +{ + tL2C_CONN_INFO *p_ci; + tL2CA_DISCONNECT_IND_CB *disconnect_ind = p_ccb->p_rcb->api.pL2CA_DisconnectInd_Cb; + UINT16 local_cid = p_ccb->local_cid; + +#if (BT_TRACE_VERBOSE == TRUE) + L2CAP_TRACE_EVENT ("L2CAP - LCID: 0x%04x st: W4_L2CA_CON_RSP evt: %s", p_ccb->local_cid, l2c_csm_get_event_name (event)); +#else + L2CAP_TRACE_EVENT ("L2CAP - st: W4_L2CA_CON_RSP evt: %d", event); +#endif + + switch (event) + { + case L2CEVT_LP_DISCONNECT_IND: /* Link was disconnected */ + L2CAP_TRACE_API ("L2CAP - Calling Disconnect_Ind_Cb(), CID: 0x%04x No Conf Needed", p_ccb->local_cid); + l2cu_release_ccb (p_ccb); + (*disconnect_ind)(local_cid, FALSE); + break; + + case L2CEVT_L2CA_CONNECT_RSP: + p_ci = (tL2C_CONN_INFO *)p_data; + + /* Result should be OK or PENDING */ + if ((!p_ci) || (p_ci->l2cap_result == L2CAP_CONN_OK)) + { + l2cu_send_peer_connect_rsp (p_ccb, L2CAP_CONN_OK, 0); + p_ccb->chnl_state = CST_CONFIG; + btu_start_timer (&p_ccb->timer_entry, BTU_TTYPE_L2CAP_CHNL, L2CAP_CHNL_CFG_TIMEOUT); + } + else + { + /* If pending, stay in same state and start extended timer */ + l2cu_send_peer_connect_rsp (p_ccb, p_ci->l2cap_result, p_ci->l2cap_status); + btu_start_timer (&p_ccb->timer_entry, BTU_TTYPE_L2CAP_CHNL, L2CAP_CHNL_CONNECT_TOUT_EXT); + } + break; + + case L2CEVT_L2CA_CONNECT_RSP_NEG: + p_ci = (tL2C_CONN_INFO *)p_data; + l2cu_send_peer_connect_rsp (p_ccb, p_ci->l2cap_result, p_ci->l2cap_status); + l2cu_release_ccb (p_ccb); + break; + + case L2CEVT_TIMEOUT: + l2cu_send_peer_connect_rsp (p_ccb, L2CAP_CONN_NO_PSM, 0); + L2CAP_TRACE_API ("L2CAP - Calling Disconnect_Ind_Cb(), CID: 0x%04x No Conf Needed", p_ccb->local_cid); + l2cu_release_ccb (p_ccb); + (*disconnect_ind)(local_cid, FALSE); + break; + + case L2CEVT_L2CA_DATA_WRITE: /* Upper layer data to send */ + case L2CEVT_L2CAP_DATA: /* Peer data packet rcvd */ + GKI_freebuf (p_data); + break; + + case L2CEVT_L2CA_DISCONNECT_REQ: /* Upper wants to disconnect */ + l2cu_send_peer_disc_req (p_ccb); + p_ccb->chnl_state = CST_W4_L2CAP_DISCONNECT_RSP; + btu_start_timer (&p_ccb->timer_entry, BTU_TTYPE_L2CAP_CHNL, L2CAP_CHNL_DISCONNECT_TOUT); + break; + + case L2CEVT_L2CAP_INFO_RSP: + /* We have feature info, so now give the upper layer connect IND */ + btu_start_timer (&p_ccb->timer_entry, BTU_TTYPE_L2CAP_CHNL, L2CAP_CHNL_CONNECT_TOUT); + L2CAP_TRACE_API ("L2CAP - Calling Connect_Ind_Cb(), CID: 0x%04x", p_ccb->local_cid); + + (*p_ccb->p_rcb->api.pL2CA_ConnectInd_Cb) (p_ccb->p_lcb->remote_bd_addr, + p_ccb->local_cid, + p_ccb->p_rcb->psm, + p_ccb->remote_id); + break; + } +} + + +/******************************************************************************* +** +** Function l2c_csm_config +** +** Description This function handles events when the channel is in +** CONFIG state. +** +** Returns void +** +*******************************************************************************/ +static void l2c_csm_config (tL2C_CCB *p_ccb, UINT16 event, void *p_data) +{ + tL2CAP_CFG_INFO *p_cfg = (tL2CAP_CFG_INFO *)p_data; + tL2CA_DISCONNECT_IND_CB *disconnect_ind = p_ccb->p_rcb->api.pL2CA_DisconnectInd_Cb; + UINT16 local_cid = p_ccb->local_cid; + UINT8 cfg_result; + +#if (BT_TRACE_VERBOSE == TRUE) + L2CAP_TRACE_EVENT ("L2CAP - LCID: 0x%04x st: CONFIG evt: %s", p_ccb->local_cid, l2c_csm_get_event_name (event)); +#else + L2CAP_TRACE_EVENT ("L2CAP - st: CONFIG evt: %d", event); +#endif + + switch (event) + { + case L2CEVT_LP_DISCONNECT_IND: /* Link was disconnected */ + L2CAP_TRACE_API ("L2CAP - Calling Disconnect_Ind_Cb(), CID: 0x%04x No Conf Needed", p_ccb->local_cid); + l2cu_release_ccb (p_ccb); + (*disconnect_ind)(local_cid, FALSE); + break; + + case L2CEVT_L2CAP_CONFIG_REQ: /* Peer config request */ + + if ((cfg_result = l2cu_process_peer_cfg_req (p_ccb, p_cfg)) == L2CAP_PEER_CFG_OK) + { + L2CAP_TRACE_EVENT ("L2CAP - Calling Config_Req_Cb(), CID: 0x%04x, C-bit %d", + p_ccb->local_cid, (p_cfg->flags & L2CAP_CFG_FLAGS_MASK_CONT)); + (*p_ccb->p_rcb->api.pL2CA_ConfigInd_Cb)(p_ccb->local_cid, p_cfg); + } + else if (cfg_result == L2CAP_PEER_CFG_DISCONNECT) + { + /* Disconnect if channels are incompatible */ + L2CAP_TRACE_EVENT ("L2CAP - incompatible configurations disconnect"); + l2cu_disconnect_chnl (p_ccb); + } + else /* Return error to peer so he can renegotiate if possible */ + { + L2CAP_TRACE_EVENT ("L2CAP - incompatible configurations trying reconfig"); + l2cu_send_peer_config_rsp (p_ccb, p_cfg); + } + break; + + case L2CEVT_L2CAP_CONFIG_RSP: /* Peer config response */ + l2cu_process_peer_cfg_rsp (p_ccb, p_cfg); + + if (p_cfg->result != L2CAP_CFG_PENDING) + { + /* TBD: When config options grow beyong minimum MTU (48 bytes) + * logic needs to be added to handle responses with + * continuation bit set in flags field. + * 1. Send additional config request out until C-bit is cleared in response + */ + p_ccb->config_done |= OB_CFG_DONE; + + if (p_ccb->config_done & IB_CFG_DONE) + { + /* Verify two sides are in compatible modes before continuing */ + if (p_ccb->our_cfg.fcr.mode != p_ccb->peer_cfg.fcr.mode) + { + l2cu_send_peer_disc_req (p_ccb); + L2CAP_TRACE_WARNING ("L2CAP - Calling Disconnect_Ind_Cb(Incompatible CFG), CID: 0x%04x No Conf Needed", p_ccb->local_cid); + l2cu_release_ccb (p_ccb); + (*disconnect_ind)(local_cid, FALSE); + break; + } + + p_ccb->config_done |= RECONFIG_FLAG; + p_ccb->chnl_state = CST_OPEN; + l2c_link_adjust_chnl_allocation (); + btu_stop_timer (&p_ccb->timer_entry); + + /* If using eRTM and waiting for an ACK, restart the ACK timer */ + if (p_ccb->fcrb.wait_ack) + l2c_fcr_start_timer(p_ccb); + + /* + ** check p_ccb->our_cfg.fcr.mon_tout and p_ccb->our_cfg.fcr.rtrans_tout + ** we may set them to zero when sending config request during renegotiation + */ + if ((p_ccb->our_cfg.fcr.mode == L2CAP_FCR_ERTM_MODE) + &&((p_ccb->our_cfg.fcr.mon_tout == 0)||(p_ccb->our_cfg.fcr.rtrans_tout))) + { + l2c_fcr_adj_monitor_retran_timeout (p_ccb); + } + +#if (L2CAP_ERTM_STATS == TRUE) + p_ccb->fcrb.connect_tick_count = GKI_get_os_tick_count(); +#endif + /* See if we can forward anything on the hold queue */ + if (!GKI_queue_is_empty(&p_ccb->xmit_hold_q)) + { + l2c_link_check_send_pkts (p_ccb->p_lcb, NULL, NULL); + } + } + } + + L2CAP_TRACE_API ("L2CAP - Calling Config_Rsp_Cb(), CID: 0x%04x", p_ccb->local_cid); + (*p_ccb->p_rcb->api.pL2CA_ConfigCfm_Cb)(p_ccb->local_cid, p_cfg); + break; + + case L2CEVT_L2CAP_CONFIG_RSP_NEG: /* Peer config error rsp */ + /* Disable the Timer */ + btu_stop_timer (&p_ccb->timer_entry); + + /* If failure was channel mode try to renegotiate */ + if (l2c_fcr_renegotiate_chan(p_ccb, p_cfg) == FALSE) + { + L2CAP_TRACE_API ("L2CAP - Calling Config_Rsp_Cb(), CID: 0x%04x, Failure: %d", p_ccb->local_cid, p_cfg->result); + (*p_ccb->p_rcb->api.pL2CA_ConfigCfm_Cb)(p_ccb->local_cid, p_cfg); + } + break; + + case L2CEVT_L2CAP_DISCONNECT_REQ: /* Peer disconnected request */ + btu_start_timer (&p_ccb->timer_entry, BTU_TTYPE_L2CAP_CHNL, L2CAP_CHNL_DISCONNECT_TOUT); + p_ccb->chnl_state = CST_W4_L2CA_DISCONNECT_RSP; + L2CAP_TRACE_API ("L2CAP - Calling Disconnect_Ind_Cb(), CID: 0x%04x Conf Needed", p_ccb->local_cid); + (*p_ccb->p_rcb->api.pL2CA_DisconnectInd_Cb)(p_ccb->local_cid, TRUE); + break; + + case L2CEVT_L2CA_CONFIG_REQ: /* Upper layer config req */ + l2cu_process_our_cfg_req (p_ccb, p_cfg); + l2cu_send_peer_config_req (p_ccb, p_cfg); + btu_start_timer (&p_ccb->timer_entry, BTU_TTYPE_L2CAP_CHNL, L2CAP_CHNL_CFG_TIMEOUT); + break; + + case L2CEVT_L2CA_CONFIG_RSP: /* Upper layer config rsp */ + l2cu_process_our_cfg_rsp (p_ccb, p_cfg); + + /* Not finished if continuation flag is set */ + if ( (p_cfg->flags & L2CAP_CFG_FLAGS_MASK_CONT) || (p_cfg->result == L2CAP_CFG_PENDING) ) + { + /* Send intermediate response; remain in cfg state */ + l2cu_send_peer_config_rsp (p_ccb, p_cfg); + break; + } + + /* Local config done; clear cached configuration in case reconfig takes place later */ + p_ccb->peer_cfg.mtu_present = FALSE; + p_ccb->peer_cfg.flush_to_present = FALSE; + p_ccb->peer_cfg.qos_present = FALSE; + + p_ccb->config_done |= IB_CFG_DONE; + + if (p_ccb->config_done & OB_CFG_DONE) + { + /* Verify two sides are in compatible modes before continuing */ + if (p_ccb->our_cfg.fcr.mode != p_ccb->peer_cfg.fcr.mode) + { + l2cu_send_peer_disc_req (p_ccb); + L2CAP_TRACE_WARNING ("L2CAP - Calling Disconnect_Ind_Cb(Incompatible CFG), CID: 0x%04x No Conf Needed", p_ccb->local_cid); + l2cu_release_ccb (p_ccb); + (*disconnect_ind)(local_cid, FALSE); + break; + } + + p_ccb->config_done |= RECONFIG_FLAG; + p_ccb->chnl_state = CST_OPEN; + l2c_link_adjust_chnl_allocation (); + btu_stop_timer (&p_ccb->timer_entry); + } + + l2cu_send_peer_config_rsp (p_ccb, p_cfg); + + /* If using eRTM and waiting for an ACK, restart the ACK timer */ + if (p_ccb->fcrb.wait_ack) + l2c_fcr_start_timer(p_ccb); + +#if (L2CAP_ERTM_STATS == TRUE) + p_ccb->fcrb.connect_tick_count = GKI_get_os_tick_count(); +#endif + + /* See if we can forward anything on the hold queue */ + if ( (p_ccb->chnl_state == CST_OPEN) && (!GKI_queue_is_empty(&p_ccb->xmit_hold_q))) + { + l2c_link_check_send_pkts (p_ccb->p_lcb, NULL, NULL); + } + break; + + case L2CEVT_L2CA_CONFIG_RSP_NEG: /* Upper layer config reject */ + l2cu_send_peer_config_rsp (p_ccb, p_cfg); + btu_start_timer (&p_ccb->timer_entry, BTU_TTYPE_L2CAP_CHNL, L2CAP_CHNL_CFG_TIMEOUT); + break; + + case L2CEVT_L2CA_DISCONNECT_REQ: /* Upper wants to disconnect */ + l2cu_send_peer_disc_req (p_ccb); + p_ccb->chnl_state = CST_W4_L2CAP_DISCONNECT_RSP; + btu_start_timer (&p_ccb->timer_entry, BTU_TTYPE_L2CAP_CHNL, L2CAP_CHNL_DISCONNECT_TOUT); + break; + + case L2CEVT_L2CAP_DATA: /* Peer data packet rcvd */ + L2CAP_TRACE_API ("L2CAP - Calling DataInd_Cb(), CID: 0x%04x", p_ccb->local_cid); +#if (L2CAP_NUM_FIXED_CHNLS > 0) + if (p_ccb->local_cid >= L2CAP_FIRST_FIXED_CHNL && + p_ccb->local_cid <= L2CAP_LAST_FIXED_CHNL) + { + if (p_ccb->local_cid < L2CAP_BASE_APPL_CID) + { + if (l2cb.fixed_reg[p_ccb->local_cid - L2CAP_FIRST_FIXED_CHNL].pL2CA_FixedData_Cb) + (*l2cb.fixed_reg[p_ccb->local_cid - L2CAP_FIRST_FIXED_CHNL].pL2CA_FixedData_Cb) + (p_ccb->local_cid, p_ccb->p_lcb->remote_bd_addr,(BT_HDR *)p_data); + else + GKI_freebuf (p_data); + break; + } + } +#endif + (*p_ccb->p_rcb->api.pL2CA_DataInd_Cb)(p_ccb->local_cid, (BT_HDR *)p_data); + break; + + case L2CEVT_L2CA_DATA_WRITE: /* Upper layer data to send */ + if (p_ccb->config_done & OB_CFG_DONE) + l2c_enqueue_peer_data (p_ccb, (BT_HDR *)p_data); + else + GKI_freebuf (p_data); + break; + + case L2CEVT_TIMEOUT: + l2cu_send_peer_disc_req (p_ccb); + L2CAP_TRACE_API ("L2CAP - Calling Disconnect_Ind_Cb(), CID: 0x%04x No Conf Needed", + p_ccb->local_cid); + l2cu_release_ccb (p_ccb); + (*disconnect_ind)(local_cid, FALSE); + break; + } +} + + +/******************************************************************************* +** +** Function l2c_csm_open +** +** Description This function handles events when the channel is in +** OPEN state. +** +** Returns void +** +*******************************************************************************/ +static void l2c_csm_open (tL2C_CCB *p_ccb, UINT16 event, void *p_data) +{ + UINT16 local_cid = p_ccb->local_cid; + tL2CAP_CFG_INFO *p_cfg; + tL2C_CHNL_STATE tempstate; + UINT8 tempcfgdone; + UINT8 cfg_result; + +#if (BT_TRACE_VERBOSE == TRUE) + L2CAP_TRACE_EVENT ("L2CAP - LCID: 0x%04x st: OPEN evt: %s", + p_ccb->local_cid, l2c_csm_get_event_name (event)); +#else + L2CAP_TRACE_EVENT ("L2CAP - st: OPEN evt: %d", event); +#endif + +#if (L2CAP_UCD_INCLUDED == TRUE) + if ( local_cid == L2CAP_CONNECTIONLESS_CID ) + { + /* check if this event can be processed by UCD */ + if ( l2c_ucd_process_event (p_ccb, event, p_data) ) + { + /* The event is processed by UCD state machine */ + return; + } + } +#endif + + switch (event) + { + case L2CEVT_LP_DISCONNECT_IND: /* Link was disconnected */ + L2CAP_TRACE_API ("L2CAP - Calling Disconnect_Ind_Cb(), CID: 0x%04x No Conf Needed", + p_ccb->local_cid); + l2cu_release_ccb (p_ccb); + if (p_ccb->p_rcb) + (*p_ccb->p_rcb->api.pL2CA_DisconnectInd_Cb)(local_cid, FALSE); + break; + + case L2CEVT_LP_QOS_VIOLATION_IND: /* QOS violation */ + /* Tell upper layer. If service guaranteed, then clear the channel */ + if (p_ccb->p_rcb->api.pL2CA_QoSViolationInd_Cb) + (*p_ccb->p_rcb->api.pL2CA_QoSViolationInd_Cb)(p_ccb->p_lcb->remote_bd_addr); + break; + + case L2CEVT_L2CAP_CONFIG_REQ: /* Peer config request */ + p_cfg = (tL2CAP_CFG_INFO *)p_data; + + tempstate = p_ccb->chnl_state; + tempcfgdone = p_ccb->config_done; + p_ccb->chnl_state = CST_CONFIG; + p_ccb->config_done &= ~CFG_DONE_MASK; + + btu_start_timer (&p_ccb->timer_entry, BTU_TTYPE_L2CAP_CHNL, L2CAP_CHNL_CFG_TIMEOUT); + + if ((cfg_result = l2cu_process_peer_cfg_req (p_ccb, p_cfg)) == L2CAP_PEER_CFG_OK) + { + (*p_ccb->p_rcb->api.pL2CA_ConfigInd_Cb)(p_ccb->local_cid, p_cfg); + } + + /* Error in config parameters: reset state and config flag */ + else if (cfg_result == L2CAP_PEER_CFG_UNACCEPTABLE) + { + btu_stop_timer(&p_ccb->timer_entry); + p_ccb->chnl_state = tempstate; + p_ccb->config_done = tempcfgdone; + l2cu_send_peer_config_rsp (p_ccb, p_cfg); + } + else /* L2CAP_PEER_CFG_DISCONNECT */ + { + /* Disconnect if channels are incompatible + * Note this should not occur if reconfigure + * since this should have never passed original config. + */ + l2cu_disconnect_chnl (p_ccb); + } + break; + + case L2CEVT_L2CAP_DISCONNECT_REQ: /* Peer disconnected request */ +// btla-specific ++ + /* Make sure we are not in sniff mode */ + { + tBTM_PM_PWR_MD settings; + memset((void*)&settings, 0, sizeof(settings)); + settings.mode = BTM_PM_MD_ACTIVE; + BTM_SetPowerMode (BTM_PM_SET_ONLY_ID, p_ccb->p_lcb->remote_bd_addr, &settings); + } +// btla-specific -- + + p_ccb->chnl_state = CST_W4_L2CA_DISCONNECT_RSP; + btu_start_timer (&p_ccb->timer_entry, BTU_TTYPE_L2CAP_CHNL, L2CAP_CHNL_DISCONNECT_TOUT); + L2CAP_TRACE_API ("L2CAP - Calling Disconnect_Ind_Cb(), CID: 0x%04x Conf Needed", p_ccb->local_cid); + (*p_ccb->p_rcb->api.pL2CA_DisconnectInd_Cb)(p_ccb->local_cid, TRUE); + break; + + case L2CEVT_L2CAP_DATA: /* Peer data packet rcvd */ + if((p_ccb->p_rcb) && (p_ccb->p_rcb->api.pL2CA_DataInd_Cb)) + (*p_ccb->p_rcb->api.pL2CA_DataInd_Cb)(p_ccb->local_cid, (BT_HDR *)p_data); + break; + + case L2CEVT_L2CA_DISCONNECT_REQ: /* Upper wants to disconnect */ + /* Make sure we are not in sniff mode */ + { + tBTM_PM_PWR_MD settings; + memset((void*)&settings, 0, sizeof(settings)); + settings.mode = BTM_PM_MD_ACTIVE; + BTM_SetPowerMode (BTM_PM_SET_ONLY_ID, p_ccb->p_lcb->remote_bd_addr, &settings); + } + + l2cu_send_peer_disc_req (p_ccb); + p_ccb->chnl_state = CST_W4_L2CAP_DISCONNECT_RSP; + btu_start_timer (&p_ccb->timer_entry, BTU_TTYPE_L2CAP_CHNL, L2CAP_CHNL_DISCONNECT_TOUT); + break; + + case L2CEVT_L2CA_DATA_WRITE: /* Upper layer data to send */ + l2c_enqueue_peer_data (p_ccb, (BT_HDR *)p_data); + l2c_link_check_send_pkts (p_ccb->p_lcb, NULL, NULL); + break; + + case L2CEVT_L2CA_CONFIG_REQ: /* Upper layer config req */ + p_ccb->chnl_state = CST_CONFIG; + p_ccb->config_done &= ~CFG_DONE_MASK; + l2cu_process_our_cfg_req (p_ccb, (tL2CAP_CFG_INFO *)p_data); + l2cu_send_peer_config_req (p_ccb, (tL2CAP_CFG_INFO *)p_data); + btu_start_timer (&p_ccb->timer_entry, BTU_TTYPE_L2CAP_CHNL, L2CAP_CHNL_CFG_TIMEOUT); + break; + + case L2CEVT_TIMEOUT: + /* Process the monitor/retransmission time-outs in flow control/retrans mode */ + if (p_ccb->peer_cfg.fcr.mode == L2CAP_FCR_ERTM_MODE) + l2c_fcr_proc_tout (p_ccb); + break; + + case L2CEVT_ACK_TIMEOUT: + l2c_fcr_proc_ack_tout (p_ccb); + break; + } +} + + +/******************************************************************************* +** +** Function l2c_csm_w4_l2cap_disconnect_rsp +** +** Description This function handles events when the channel is in +** CST_W4_L2CAP_DISCONNECT_RSP state. +** +** Returns void +** +*******************************************************************************/ +static void l2c_csm_w4_l2cap_disconnect_rsp (tL2C_CCB *p_ccb, UINT16 event, void *p_data) +{ + tL2CA_DISCONNECT_CFM_CB *disconnect_cfm = p_ccb->p_rcb->api.pL2CA_DisconnectCfm_Cb; + UINT16 local_cid = p_ccb->local_cid; + +#if (BT_TRACE_VERBOSE == TRUE) + L2CAP_TRACE_EVENT ("L2CAP - LCID: 0x%04x st: W4_L2CAP_DISC_RSP evt: %s", p_ccb->local_cid, l2c_csm_get_event_name (event)); +#else + L2CAP_TRACE_EVENT ("L2CAP - st: W4_L2CAP_DISC_RSP evt: %d", event); +#endif + + switch (event) + { + case L2CEVT_L2CAP_DISCONNECT_RSP: /* Peer disconnect response */ + l2cu_release_ccb (p_ccb); + if (disconnect_cfm) + { + L2CAP_TRACE_API ("L2CAP - Calling DisconnectCfm_Cb(), CID: 0x%04x", local_cid); + (*disconnect_cfm)(local_cid, L2CAP_DISC_OK); + } + break; + + case L2CEVT_L2CAP_DISCONNECT_REQ: /* Peer disconnect request */ + l2cu_send_peer_disc_rsp (p_ccb->p_lcb, p_ccb->remote_id, p_ccb->local_cid, p_ccb->remote_cid); + l2cu_release_ccb (p_ccb); + if (disconnect_cfm) + { + L2CAP_TRACE_API ("L2CAP - Calling DisconnectCfm_Cb(), CID: 0x%04x", local_cid); + (*disconnect_cfm)(local_cid, L2CAP_DISC_OK); + } + break; + + case L2CEVT_LP_DISCONNECT_IND: /* Link was disconnected */ + case L2CEVT_TIMEOUT: /* Timeout */ + l2cu_release_ccb (p_ccb); + if (disconnect_cfm) + { + L2CAP_TRACE_API ("L2CAP - Calling DisconnectCfm_Cb(), CID: 0x%04x", local_cid); + (*disconnect_cfm)(local_cid, L2CAP_DISC_TIMEOUT); + } + break; + + case L2CEVT_L2CAP_DATA: /* Peer data packet rcvd */ + case L2CEVT_L2CA_DATA_WRITE: /* Upper layer data to send */ + GKI_freebuf (p_data); + break; + } +} + + +/******************************************************************************* +** +** Function l2c_csm_w4_l2ca_disconnect_rsp +** +** Description This function handles events when the channel is in +** CST_W4_L2CA_DISCONNECT_RSP state. +** +** Returns void +** +*******************************************************************************/ +static void l2c_csm_w4_l2ca_disconnect_rsp (tL2C_CCB *p_ccb, UINT16 event, void *p_data) +{ + tL2CA_DISCONNECT_IND_CB *disconnect_ind = p_ccb->p_rcb->api.pL2CA_DisconnectInd_Cb; + UINT16 local_cid = p_ccb->local_cid; + +#if (BT_TRACE_VERBOSE == TRUE) + L2CAP_TRACE_EVENT ("L2CAP - LCID: 0x%04x st: W4_L2CA_DISC_RSP evt: %s", p_ccb->local_cid, l2c_csm_get_event_name (event)); +#else + L2CAP_TRACE_EVENT ("L2CAP - st: W4_L2CA_DISC_RSP evt: %d", event); +#endif + + switch (event) + { + case L2CEVT_LP_DISCONNECT_IND: /* Link was disconnected */ + L2CAP_TRACE_API ("L2CAP - Calling Disconnect_Ind_Cb(), CID: 0x%04x No Conf Needed", p_ccb->local_cid); + l2cu_release_ccb (p_ccb); + (*disconnect_ind)(local_cid, FALSE); + break; + + case L2CEVT_TIMEOUT: + l2cu_send_peer_disc_rsp (p_ccb->p_lcb, p_ccb->remote_id, p_ccb->local_cid, p_ccb->remote_cid); + L2CAP_TRACE_API ("L2CAP - Calling Disconnect_Ind_Cb(), CID: 0x%04x No Conf Needed", p_ccb->local_cid); + l2cu_release_ccb (p_ccb); + (*disconnect_ind)(local_cid, FALSE); + break; + + case L2CEVT_L2CA_DISCONNECT_REQ: /* Upper disconnect request */ + case L2CEVT_L2CA_DISCONNECT_RSP: /* Upper disconnect response */ + l2cu_send_peer_disc_rsp (p_ccb->p_lcb, p_ccb->remote_id, p_ccb->local_cid, p_ccb->remote_cid); + l2cu_release_ccb (p_ccb); + break; + + case L2CEVT_L2CAP_DATA: /* Peer data packet rcvd */ + case L2CEVT_L2CA_DATA_WRITE: /* Upper layer data to send */ + GKI_freebuf (p_data); + break; + } +} + + +#if (BT_TRACE_VERBOSE == TRUE) +/******************************************************************************* +** +** Function l2c_csm_get_event_name +** +** Description This function returns the event name. +** +** NOTE conditionally compiled to save memory. +** +** Returns pointer to the name +** +*******************************************************************************/ +static char *l2c_csm_get_event_name (UINT16 event) +{ + switch (event) + { + case L2CEVT_LP_CONNECT_CFM: /* Lower layer connect confirm */ + return ("LOWER_LAYER_CONNECT_CFM"); + case L2CEVT_LP_CONNECT_CFM_NEG: /* Lower layer connect confirm (failed) */ + return ("LOWER_LAYER_CONNECT_CFM_NEG"); + case L2CEVT_LP_CONNECT_IND: /* Lower layer connect indication */ + return ("LOWER_LAYER_CONNECT_IND"); + case L2CEVT_LP_DISCONNECT_IND: /* Lower layer disconnect indication */ + return ("LOWER_LAYER_DISCONNECT_IND"); + case L2CEVT_LP_QOS_CFM: /* Lower layer QOS confirmation */ + return ("LOWER_LAYER_QOS_CFM"); + case L2CEVT_LP_QOS_CFM_NEG: /* Lower layer QOS confirmation (failed)*/ + return ("LOWER_LAYER_QOS_CFM_NEG"); + case L2CEVT_LP_QOS_VIOLATION_IND: /* Lower layer QOS violation indication */ + return ("LOWER_LAYER_QOS_VIOLATION_IND"); + + case L2CEVT_SEC_COMP: /* Security cleared successfully */ + return ("SECURITY_COMPLETE"); + case L2CEVT_SEC_COMP_NEG: /* Security procedure failed */ + return ("SECURITY_COMPLETE_NEG"); + + case L2CEVT_L2CAP_CONNECT_REQ: /* Peer connection request */ + return ("PEER_CONNECT_REQ"); + case L2CEVT_L2CAP_CONNECT_RSP: /* Peer connection response */ + return ("PEER_CONNECT_RSP"); + case L2CEVT_L2CAP_CONNECT_RSP_PND: /* Peer connection response pending */ + return ("PEER_CONNECT_RSP_PND"); + case L2CEVT_L2CAP_CONNECT_RSP_NEG: /* Peer connection response (failed) */ + return ("PEER_CONNECT_RSP_NEG"); + case L2CEVT_L2CAP_CONFIG_REQ: /* Peer configuration request */ + return ("PEER_CONFIG_REQ"); + case L2CEVT_L2CAP_CONFIG_RSP: /* Peer configuration response */ + return ("PEER_CONFIG_RSP"); + case L2CEVT_L2CAP_CONFIG_RSP_NEG: /* Peer configuration response (failed) */ + return ("PEER_CONFIG_RSP_NEG"); + case L2CEVT_L2CAP_DISCONNECT_REQ: /* Peer disconnect request */ + return ("PEER_DISCONNECT_REQ"); + case L2CEVT_L2CAP_DISCONNECT_RSP: /* Peer disconnect response */ + return ("PEER_DISCONNECT_RSP"); + case L2CEVT_L2CAP_DATA: /* Peer data */ + return ("PEER_DATA"); + + case L2CEVT_L2CA_CONNECT_REQ: /* Upper layer connect request */ + return ("UPPER_LAYER_CONNECT_REQ"); + case L2CEVT_L2CA_CONNECT_RSP: /* Upper layer connect response */ + return ("UPPER_LAYER_CONNECT_RSP"); + case L2CEVT_L2CA_CONNECT_RSP_NEG: /* Upper layer connect response (failed)*/ + return ("UPPER_LAYER_CONNECT_RSP_NEG"); + case L2CEVT_L2CA_CONFIG_REQ: /* Upper layer config request */ + return ("UPPER_LAYER_CONFIG_REQ"); + case L2CEVT_L2CA_CONFIG_RSP: /* Upper layer config response */ + return ("UPPER_LAYER_CONFIG_RSP"); + case L2CEVT_L2CA_CONFIG_RSP_NEG: /* Upper layer config response (failed) */ + return ("UPPER_LAYER_CONFIG_RSP_NEG"); + case L2CEVT_L2CA_DISCONNECT_REQ: /* Upper layer disconnect request */ + return ("UPPER_LAYER_DISCONNECT_REQ"); + case L2CEVT_L2CA_DISCONNECT_RSP: /* Upper layer disconnect response */ + return ("UPPER_LAYER_DISCONNECT_RSP"); + case L2CEVT_L2CA_DATA_READ: /* Upper layer data read */ + return ("UPPER_LAYER_DATA_READ"); + case L2CEVT_L2CA_DATA_WRITE: /* Upper layer data write */ + return ("UPPER_LAYER_DATA_WRITE"); + case L2CEVT_TIMEOUT: /* Timeout */ + return ("TIMEOUT"); + case L2CEVT_SEC_RE_SEND_CMD: + return ("SEC_RE_SEND_CMD"); + case L2CEVT_L2CAP_INFO_RSP: /* Peer information response */ + return ("L2CEVT_L2CAP_INFO_RSP"); + case L2CEVT_ACK_TIMEOUT: + return ("L2CEVT_ACK_TIMEOUT"); + + default: + return ("???? UNKNOWN EVENT"); + } +} +#endif /* (BT_TRACE_VERBOSE == TRUE) */ + + +/******************************************************************************* +** +** Function l2c_enqueue_peer_data +** +** Description Enqueues data destined for the peer in the ccb. Handles +** FCR segmentation and checks for congestion. +** +** Returns void +** +*******************************************************************************/ +void l2c_enqueue_peer_data (tL2C_CCB *p_ccb, BT_HDR *p_buf) +{ + UINT8 *p; + + if (p_ccb->peer_cfg.fcr.mode != L2CAP_FCR_BASIC_MODE) + { + p_buf->event = 0; + } + else + { + /* Save the channel ID for faster counting */ + p_buf->event = p_ccb->local_cid; + + /* Step back to add the L2CAP header */ + p_buf->offset -= L2CAP_PKT_OVERHEAD; + p_buf->len += L2CAP_PKT_OVERHEAD; + + /* Set the pointer to the beginning of the data */ + p = (UINT8 *)(p_buf + 1) + p_buf->offset; + + /* Now the L2CAP header */ + UINT16_TO_STREAM (p, p_buf->len - L2CAP_PKT_OVERHEAD); + UINT16_TO_STREAM (p, p_ccb->remote_cid); + } + + GKI_enqueue (&p_ccb->xmit_hold_q, p_buf); + + l2cu_check_channel_congestion (p_ccb); + +#if (L2CAP_ROUND_ROBIN_CHANNEL_SERVICE == TRUE) + /* if new packet is higher priority than serving ccb and it is not overrun */ + if (( p_ccb->p_lcb->rr_pri > p_ccb->ccb_priority ) + &&( p_ccb->p_lcb->rr_serv[p_ccb->ccb_priority].quota > 0)) + { + /* send out higher priority packet */ + p_ccb->p_lcb->rr_pri = p_ccb->ccb_priority; + } +#endif + + /* if we are doing a round robin scheduling, set the flag */ + if (p_ccb->p_lcb->link_xmit_quota == 0) + l2cb.check_round_robin = TRUE; +} + + diff --git a/components/bt/bluedroid/stack/l2cap/l2c_fcr.c b/components/bt/bluedroid/stack/l2cap/l2c_fcr.c new file mode 100755 index 0000000000..5e5f0f45d4 --- /dev/null +++ b/components/bt/bluedroid/stack/l2cap/l2c_fcr.c @@ -0,0 +1,2356 @@ +/****************************************************************************** + * + * Copyright (C) 2004-2012 Broadcom Corporation + * + * 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 L2CAP 1.2 Flow Control and retransmissions + * functions + * + ******************************************************************************/ + +#include +#include +#include +#include "bt_trace.h" +#include "bt_types.h" +#include "gki.h" +#include "hcimsgs.h" +#include "l2c_api.h" +#include "l2c_int.h" +#include "l2cdefs.h" +#include "btm_api.h" +#include "btm_int.h" +#include "btu.h" + +/* Flag passed to retransmit_i_frames() when all packets should be retransmitted */ +#define L2C_FCR_RETX_ALL_PKTS 0xFF + +#if BT_TRACE_VERBOSE == TRUE +static char *SAR_types[] = { "Unsegmented", "Start", "End", "Continuation" }; +static char *SUP_types[] = { "RR", "REJ", "RNR", "SREJ" }; +#endif + +/* Look-up table for the CRC calculation */ +static const unsigned short crctab[256] = { + 0x0000, 0xc0c1, 0xc181, 0x0140, 0xc301, 0x03c0, 0x0280, 0xc241, + 0xc601, 0x06c0, 0x0780, 0xc741, 0x0500, 0xc5c1, 0xc481, 0x0440, + 0xcc01, 0x0cc0, 0x0d80, 0xcd41, 0x0f00, 0xcfc1, 0xce81, 0x0e40, + 0x0a00, 0xcac1, 0xcb81, 0x0b40, 0xc901, 0x09c0, 0x0880, 0xc841, + 0xd801, 0x18c0, 0x1980, 0xd941, 0x1b00, 0xdbc1, 0xda81, 0x1a40, + 0x1e00, 0xdec1, 0xdf81, 0x1f40, 0xdd01, 0x1dc0, 0x1c80, 0xdc41, + 0x1400, 0xd4c1, 0xd581, 0x1540, 0xd701, 0x17c0, 0x1680, 0xd641, + 0xd201, 0x12c0, 0x1380, 0xd341, 0x1100, 0xd1c1, 0xd081, 0x1040, + 0xf001, 0x30c0, 0x3180, 0xf141, 0x3300, 0xf3c1, 0xf281, 0x3240, + 0x3600, 0xf6c1, 0xf781, 0x3740, 0xf501, 0x35c0, 0x3480, 0xf441, + 0x3c00, 0xfcc1, 0xfd81, 0x3d40, 0xff01, 0x3fc0, 0x3e80, 0xfe41, + 0xfa01, 0x3ac0, 0x3b80, 0xfb41, 0x3900, 0xf9c1, 0xf881, 0x3840, + 0x2800, 0xe8c1, 0xe981, 0x2940, 0xeb01, 0x2bc0, 0x2a80, 0xea41, + 0xee01, 0x2ec0, 0x2f80, 0xef41, 0x2d00, 0xedc1, 0xec81, 0x2c40, + 0xe401, 0x24c0, 0x2580, 0xe541, 0x2700, 0xe7c1, 0xe681, 0x2640, + 0x2200, 0xe2c1, 0xe381, 0x2340, 0xe101, 0x21c0, 0x2080, 0xe041, + 0xa001, 0x60c0, 0x6180, 0xa141, 0x6300, 0xa3c1, 0xa281, 0x6240, + 0x6600, 0xa6c1, 0xa781, 0x6740, 0xa501, 0x65c0, 0x6480, 0xa441, + 0x6c00, 0xacc1, 0xad81, 0x6d40, 0xaf01, 0x6fc0, 0x6e80, 0xae41, + 0xaa01, 0x6ac0, 0x6b80, 0xab41, 0x6900, 0xa9c1, 0xa881, 0x6840, + 0x7800, 0xb8c1, 0xb981, 0x7940, 0xbb01, 0x7bc0, 0x7a80, 0xba41, + 0xbe01, 0x7ec0, 0x7f80, 0xbf41, 0x7d00, 0xbdc1, 0xbc81, 0x7c40, + 0xb401, 0x74c0, 0x7580, 0xb541, 0x7700, 0xb7c1, 0xb681, 0x7640, + 0x7200, 0xb2c1, 0xb381, 0x7340, 0xb101, 0x71c0, 0x7080, 0xb041, + 0x5000, 0x90c1, 0x9181, 0x5140, 0x9301, 0x53c0, 0x5280, 0x9241, + 0x9601, 0x56c0, 0x5780, 0x9741, 0x5500, 0x95c1, 0x9481, 0x5440, + 0x9c01, 0x5cc0, 0x5d80, 0x9d41, 0x5f00, 0x9fc1, 0x9e81, 0x5e40, + 0x5a00, 0x9ac1, 0x9b81, 0x5b40, 0x9901, 0x59c0, 0x5880, 0x9841, + 0x8801, 0x48c0, 0x4980, 0x8941, 0x4b00, 0x8bc1, 0x8a81, 0x4a40, + 0x4e00, 0x8ec1, 0x8f81, 0x4f40, 0x8d01, 0x4dc0, 0x4c80, 0x8c41, + 0x4400, 0x84c1, 0x8581, 0x4540, 0x8701, 0x47c0, 0x4680, 0x8641, + 0x8201, 0x42c0, 0x4380, 0x8341, 0x4100, 0x81c1, 0x8081, 0x4040, +}; + + +/******************************************************************************* +** Static local functions +*/ +static BOOLEAN process_reqseq (tL2C_CCB *p_ccb, UINT16 ctrl_word); +static void process_s_frame (tL2C_CCB *p_ccb, BT_HDR *p_buf, UINT16 ctrl_word); +static void process_i_frame (tL2C_CCB *p_ccb, BT_HDR *p_buf, UINT16 ctrl_word, BOOLEAN delay_ack); +static BOOLEAN retransmit_i_frames (tL2C_CCB *p_ccb, UINT8 tx_seq); +static void prepare_I_frame (tL2C_CCB *p_ccb, BT_HDR *p_buf, BOOLEAN is_retransmission); +static void process_stream_frame (tL2C_CCB *p_ccb, BT_HDR *p_buf); +static BOOLEAN do_sar_reassembly (tL2C_CCB *p_ccb, BT_HDR *p_buf, UINT16 ctrl_word); + +#if (L2CAP_ERTM_STATS == TRUE) +static void l2c_fcr_collect_ack_delay (tL2C_CCB *p_ccb, UINT8 num_bufs_acked); +#endif + +/******************************************************************************* +** +** Function l2c_fcr_updcrc +** +** Description This function computes the CRC using the look-up table. +** +** Returns CRC +** +*******************************************************************************/ +static unsigned short l2c_fcr_updcrc(unsigned short icrc, unsigned char *icp, int icnt) +{ + register unsigned short crc = icrc; + register unsigned char *cp = icp; + register int cnt = icnt; + + while (cnt--) + { + crc = ((crc >> 8) & 0xff) ^ crctab[(crc & 0xff) ^ *cp++]; + } + + return(crc); +} + + +/******************************************************************************* +** +** Function l2c_fcr_tx_get_fcs +** +** Description This function computes the CRC for a frame to be TXed. +** +** Returns CRC +** +*******************************************************************************/ +static UINT16 l2c_fcr_tx_get_fcs (BT_HDR *p_buf) +{ + UINT8 *p = ((UINT8 *) (p_buf + 1)) + p_buf->offset; + + return (l2c_fcr_updcrc (L2CAP_FCR_INIT_CRC, p, p_buf->len)); +} + +/******************************************************************************* +** +** Function l2c_fcr_rx_get_fcs +** +** Description This function computes the CRC for a received frame. +** +** Returns CRC +** +*******************************************************************************/ +static UINT16 l2c_fcr_rx_get_fcs (BT_HDR *p_buf) +{ + UINT8 *p = ((UINT8 *) (p_buf + 1)) + p_buf->offset; + + /* offset points past the L2CAP header, but the CRC check includes it */ + p -= L2CAP_PKT_OVERHEAD; + + return (l2c_fcr_updcrc (L2CAP_FCR_INIT_CRC, p, p_buf->len + L2CAP_PKT_OVERHEAD)); +} + +/******************************************************************************* +** +** Function l2c_fcr_start_timer +** +** Description This function starts the (monitor or retransmission) timer. +** +** Returns - +** +*******************************************************************************/ +void l2c_fcr_start_timer (tL2C_CCB *p_ccb) +{ + assert(p_ccb != NULL); + UINT32 tout; + + /* The timers which are in milliseconds */ + if (p_ccb->fcrb.wait_ack) + { + tout = (UINT32)p_ccb->our_cfg.fcr.mon_tout; + } + else + { + tout = (UINT32)p_ccb->our_cfg.fcr.rtrans_tout; + } + + /* Only start a timer that was not started */ + if (p_ccb->fcrb.mon_retrans_timer.in_use == 0) + btu_start_quick_timer (&p_ccb->fcrb.mon_retrans_timer, BTU_TTYPE_L2CAP_CHNL, tout*QUICK_TIMER_TICKS_PER_SEC/1000); +} + +/******************************************************************************* +** +** Function l2c_fcr_stop_timer +** +** Description This function stops the (monitor or transmission) timer. +** +** Returns - +** +*******************************************************************************/ +void l2c_fcr_stop_timer (tL2C_CCB *p_ccb) +{ + assert(p_ccb != NULL); + if (p_ccb->fcrb.mon_retrans_timer.in_use) + { + btu_stop_quick_timer (&p_ccb->fcrb.mon_retrans_timer); + } +} + +/******************************************************************************* +** +** Function l2c_fcr_cleanup +** +** Description This function cleans up the variable used for flow-control/retrans. +** +** Returns - +** +*******************************************************************************/ +void l2c_fcr_cleanup (tL2C_CCB *p_ccb) +{ + assert(p_ccb != NULL); + tL2C_FCRB *p_fcrb = &p_ccb->fcrb; + + l2c_fcr_stop_timer (p_ccb); + + if (p_fcrb->p_rx_sdu) + GKI_freebuf (p_fcrb->p_rx_sdu); + + while (!GKI_queue_is_empty(&p_fcrb->waiting_for_ack_q)) + GKI_freebuf (GKI_dequeue (&p_fcrb->waiting_for_ack_q)); + + while (!GKI_queue_is_empty(&p_fcrb->srej_rcv_hold_q)) + GKI_freebuf (GKI_dequeue (&p_fcrb->srej_rcv_hold_q)); + + while (!GKI_queue_is_empty(&p_fcrb->retrans_q)) + GKI_freebuf (GKI_dequeue (&p_fcrb->retrans_q)); + + btu_stop_quick_timer (&p_fcrb->ack_timer); + btu_stop_quick_timer (&p_ccb->fcrb.mon_retrans_timer); + +#if (L2CAP_ERTM_STATS == TRUE) + if ( (p_ccb->local_cid >= L2CAP_BASE_APPL_CID) && (p_ccb->peer_cfg.fcr.mode == L2CAP_FCR_ERTM_MODE) ) + { + UINT32 dur = GKI_get_os_tick_count() - p_ccb->fcrb.connect_tick_count; + char *p_str = (char *)GKI_getbuf(120); + UINT16 i; + UINT32 throughput_avg, ack_delay_avg, ack_q_count_avg; + + BT_TRACE(TRACE_CTRL_GENERAL | TRACE_LAYER_GKI | TRACE_ORG_GKI , TRACE_TYPE_GENERIC, + "--- L2CAP ERTM Stats for CID: 0x%04x Duration: %08ums", p_ccb->local_cid, dur); + BT_TRACE(TRACE_CTRL_GENERAL | TRACE_LAYER_GKI | TRACE_ORG_GKI , TRACE_TYPE_GENERIC, + "Retransmissions:%08u Times Flow Controlled:%08u Retrans Touts:%08u Ack Touts:%08u", + p_ccb->fcrb.pkts_retransmitted, p_ccb->fcrb.xmit_window_closed, p_ccb->fcrb.retrans_touts, p_ccb->fcrb.xmit_ack_touts); + BT_TRACE(TRACE_CTRL_GENERAL | TRACE_LAYER_GKI | TRACE_ORG_GKI , TRACE_TYPE_GENERIC, + "Times there is less than 2 packets in controller when flow controlled:%08u", p_ccb->fcrb.controller_idle); + BT_TRACE(TRACE_CTRL_GENERAL | TRACE_LAYER_GKI | TRACE_ORG_GKI , TRACE_TYPE_GENERIC, + "max_held_acks:%08u, in_cfg.fcr.tx_win_sz:%08u", p_ccb->fcrb.max_held_acks, p_ccb->peer_cfg.fcr.tx_win_sz ); + if (p_str) + { + sprintf(p_str, "Sent Pkts:%08u Bytes:%10u(%06u/sec) RR:%08u REJ:%08u RNR:%08u SREJ:%08u", + p_ccb->fcrb.ertm_pkt_counts[0], p_ccb->fcrb.ertm_byte_counts[0], + (dur >= 10 ? (p_ccb->fcrb.ertm_byte_counts[0] * 100) / (dur / 10) : 0), + p_ccb->fcrb.s_frames_sent[0], p_ccb->fcrb.s_frames_sent[1], p_ccb->fcrb.s_frames_sent[2], p_ccb->fcrb.s_frames_sent[3]); + + BT_TRACE(TRACE_CTRL_GENERAL | TRACE_LAYER_GKI | TRACE_ORG_GKI , TRACE_TYPE_GENERIC, "%s", p_str); + + sprintf(p_str, "Rcvd Pkts:%08u Bytes:%10u(%06u/sec) RR:%08u REJ:%08u RNR:%08u SREJ:%08u", + p_ccb->fcrb.ertm_pkt_counts[1], p_ccb->fcrb.ertm_byte_counts[1], + (dur >= 10 ? (p_ccb->fcrb.ertm_byte_counts[1] * 100) / (dur / 10) : 0), + p_ccb->fcrb.s_frames_rcvd[0], p_ccb->fcrb.s_frames_rcvd[1], p_ccb->fcrb.s_frames_rcvd[2], p_ccb->fcrb.s_frames_rcvd[3]); + + BT_TRACE(TRACE_CTRL_GENERAL | TRACE_LAYER_GKI | TRACE_ORG_GKI , TRACE_TYPE_GENERIC, "%s", p_str); + + throughput_avg = 0; + ack_delay_avg = 0; + ack_q_count_avg = 0; + + for (i = 0; i < L2CAP_ERTM_STATS_NUM_AVG; i++ ) + { + if (i == p_ccb->fcrb.ack_delay_avg_index ) + { + BT_TRACE(TRACE_CTRL_GENERAL | TRACE_LAYER_GKI | TRACE_ORG_GKI , TRACE_TYPE_GENERIC, + "[%02u] collecting data ...", i ); + continue; + } + + sprintf(p_str, "[%02u] throughput: %5u, ack_delay avg:%3u, min:%3u, max:%3u, ack_q_count avg:%3u, min:%3u, max:%3u", + i, p_ccb->fcrb.throughput[i], + p_ccb->fcrb.ack_delay_avg[i], p_ccb->fcrb.ack_delay_min[i], p_ccb->fcrb.ack_delay_max[i], + p_ccb->fcrb.ack_q_count_avg[i], p_ccb->fcrb.ack_q_count_min[i], p_ccb->fcrb.ack_q_count_max[i] ); + + BT_TRACE(TRACE_CTRL_GENERAL | TRACE_LAYER_GKI | TRACE_ORG_GKI , TRACE_TYPE_GENERIC, "%s", p_str); + + throughput_avg += p_ccb->fcrb.throughput[i]; + ack_delay_avg += p_ccb->fcrb.ack_delay_avg[i]; + ack_q_count_avg += p_ccb->fcrb.ack_q_count_avg[i]; + } + + throughput_avg /= (L2CAP_ERTM_STATS_NUM_AVG - 1); + ack_delay_avg /= (L2CAP_ERTM_STATS_NUM_AVG - 1); + ack_q_count_avg /= (L2CAP_ERTM_STATS_NUM_AVG - 1); + + BT_TRACE(TRACE_CTRL_GENERAL | TRACE_LAYER_GKI | TRACE_ORG_GKI , TRACE_TYPE_GENERIC, + "throughput_avg: %8u (kbytes/sec), ack_delay_avg: %8u ms, ack_q_count_avg: %8u", + throughput_avg, ack_delay_avg, ack_q_count_avg ); + + GKI_freebuf(p_str); + } + + BT_TRACE(TRACE_CTRL_GENERAL | TRACE_LAYER_GKI | TRACE_ORG_GKI , TRACE_TYPE_GENERIC, + "---"); + } +#endif + + memset (p_fcrb, 0, sizeof (tL2C_FCRB)); +} + +/******************************************************************************* +** +** Function l2c_fcr_clone_buf +** +** Description This function allocates and copies requested part of a buffer +** at a new-offset. +** +** Returns pointer to new buffer +** +*******************************************************************************/ +BT_HDR *l2c_fcr_clone_buf (BT_HDR *p_buf, UINT16 new_offset, UINT16 no_of_bytes, UINT8 pool) +{ + assert(p_buf != NULL); + BT_HDR *p_buf2; + + /* If using the common pool, should be at least 10% free. */ + if ( (pool == HCI_ACL_POOL_ID) && (GKI_poolutilization (pool) > 90) ) + { + L2CAP_TRACE_ERROR ("L2CAP - failed to clone buffer on HCI_ACL_POOL_ID Utilization: %u", GKI_poolutilization(pool)); + return (NULL); + } + + if ((p_buf2 = (BT_HDR *)GKI_getpoolbuf(pool)) != NULL) + { + UINT16 pool_buf_size = GKI_get_pool_bufsize (pool); + + /* Make sure buffer fits into buffer pool */ + if ((no_of_bytes + sizeof(BT_HDR) + new_offset) > pool_buf_size) + { + L2CAP_TRACE_ERROR("##### l2c_fcr_clone_buf (NumBytes %d) -> Exceeds poolsize %d [bytes %d + BT_HDR %d + offset %d]", + (no_of_bytes + sizeof(BT_HDR) + new_offset), + pool_buf_size, no_of_bytes, sizeof(BT_HDR), + new_offset); + + GKI_freebuf(p_buf2); + return (NULL); + } + + p_buf2->offset = new_offset; + p_buf2->len = no_of_bytes; + + memcpy (((UINT8 *)(p_buf2 + 1)) + p_buf2->offset, + ((UINT8 *)(p_buf + 1)) + p_buf->offset, + no_of_bytes); + } + else + { + L2CAP_TRACE_ERROR ("L2CAP - failed to clone buffer, Pool: %u Count: %u", pool, GKI_poolfreecount(pool)); + } + + return (p_buf2); +} + +/******************************************************************************* +** +** Function l2c_fcr_is_flow_controlled +** +** Description This function checks if the CCB is flow controlled by peer. +** +** Returns The control word +** +*******************************************************************************/ +BOOLEAN l2c_fcr_is_flow_controlled (tL2C_CCB *p_ccb) +{ + assert(p_ccb != NULL); + if (p_ccb->peer_cfg.fcr.mode == L2CAP_FCR_ERTM_MODE) + { + /* Check if remote side flowed us off or the transmit window is full */ + if ( (p_ccb->fcrb.remote_busy == TRUE) + || (GKI_queue_length(&p_ccb->fcrb.waiting_for_ack_q) >= p_ccb->peer_cfg.fcr.tx_win_sz) ) + { +#if (L2CAP_ERTM_STATS == TRUE) + if (!GKI_queue_is_empty(&p_ccb->xmit_hold_q)) + { + p_ccb->fcrb.xmit_window_closed++; + + if ((p_ccb->p_lcb->sent_not_acked < 2)&&(l2cb.controller_xmit_window > 0)) + p_ccb->fcrb.controller_idle++; + } +#endif + return (TRUE); + } + } + return (FALSE); +} + +/******************************************************************************* +** +** Function prepare_I_frame +** +** Description This function sets the FCR variables in an I-frame that is +** about to be sent to HCI for transmission. This may be the +** first time the I-frame is sent, or a retransmission +** +** Returns - +** +*******************************************************************************/ +static void prepare_I_frame (tL2C_CCB *p_ccb, BT_HDR *p_buf, BOOLEAN is_retransmission) +{ + assert(p_ccb != NULL); + assert(p_buf != NULL); + tL2C_FCRB *p_fcrb = &p_ccb->fcrb; + UINT8 *p; + UINT16 fcs; + UINT16 ctrl_word; + BOOLEAN set_f_bit = p_fcrb->send_f_rsp; + + p_fcrb->send_f_rsp = FALSE; + + if (is_retransmission) + { + /* Get the old control word and clear out the old req_seq and F bits */ + p = ((UINT8 *) (p_buf+1)) + p_buf->offset + L2CAP_PKT_OVERHEAD; + + STREAM_TO_UINT16 (ctrl_word, p); + + ctrl_word &= ~(L2CAP_FCR_REQ_SEQ_BITS + L2CAP_FCR_F_BIT); + } + else + { + ctrl_word = p_buf->layer_specific & L2CAP_FCR_SEG_BITS; /* SAR bits */ + ctrl_word |= (p_fcrb->next_tx_seq << L2CAP_FCR_TX_SEQ_BITS_SHIFT); /* Tx Seq */ + + p_fcrb->next_tx_seq = (p_fcrb->next_tx_seq + 1) & L2CAP_FCR_SEQ_MODULO; + } + + /* Set the F-bit and reqseq only if using re-transmission mode */ + if (p_ccb->peer_cfg.fcr.mode == L2CAP_FCR_ERTM_MODE) + { + if (set_f_bit) + ctrl_word |= L2CAP_FCR_F_BIT; + + ctrl_word |= (p_fcrb->next_seq_expected) << L2CAP_FCR_REQ_SEQ_BITS_SHIFT; + + p_fcrb->last_ack_sent = p_ccb->fcrb.next_seq_expected; + + if (p_ccb->fcrb.ack_timer.in_use) + btu_stop_quick_timer (&p_ccb->fcrb.ack_timer); + } + + /* Set the control word */ + p = ((UINT8 *) (p_buf+1)) + p_buf->offset + L2CAP_PKT_OVERHEAD; + + UINT16_TO_STREAM (p, ctrl_word); + + /* Compute the FCS and add to the end of the buffer if not bypassed */ + if (p_ccb->bypass_fcs != L2CAP_BYPASS_FCS) + { + /* length field in l2cap header has to include FCS length */ + p = ((UINT8 *) (p_buf+1)) + p_buf->offset; + UINT16_TO_STREAM (p, p_buf->len + L2CAP_FCS_LEN - L2CAP_PKT_OVERHEAD); + + /* Calculate the FCS */ + fcs = l2c_fcr_tx_get_fcs(p_buf); + + /* Point to the end of the buffer and put the FCS there */ + p = ((UINT8 *) (p_buf+1)) + p_buf->offset + p_buf->len; + + UINT16_TO_STREAM (p, fcs); + + p_buf->len += L2CAP_FCS_LEN; + } + +#if BT_TRACE_VERBOSE == TRUE + if (is_retransmission) + { + L2CAP_TRACE_EVENT ("L2CAP eRTM ReTx I-frame CID: 0x%04x Len: %u SAR: %s TxSeq: %u ReqSeq: %u F: %u", + p_ccb->local_cid, p_buf->len, + SAR_types[(ctrl_word & L2CAP_FCR_SAR_BITS) >> L2CAP_FCR_SAR_BITS_SHIFT], + (ctrl_word & L2CAP_FCR_TX_SEQ_BITS) >> L2CAP_FCR_TX_SEQ_BITS_SHIFT, + (ctrl_word & L2CAP_FCR_REQ_SEQ_BITS) >> L2CAP_FCR_REQ_SEQ_BITS_SHIFT, + (ctrl_word & L2CAP_FCR_F_BIT) >> L2CAP_FCR_F_BIT_SHIFT); + } + else + { + L2CAP_TRACE_EVENT ("L2CAP eRTM Tx I-frame CID: 0x%04x Len: %u SAR: %-12s TxSeq: %u ReqSeq: %u F: %u", + p_ccb->local_cid, p_buf->len, + SAR_types[(ctrl_word & L2CAP_FCR_SAR_BITS) >> L2CAP_FCR_SAR_BITS_SHIFT], + (ctrl_word & L2CAP_FCR_TX_SEQ_BITS) >> L2CAP_FCR_TX_SEQ_BITS_SHIFT, + (ctrl_word & L2CAP_FCR_REQ_SEQ_BITS) >> L2CAP_FCR_REQ_SEQ_BITS_SHIFT, + (ctrl_word & L2CAP_FCR_F_BIT) >> L2CAP_FCR_F_BIT_SHIFT); + } +#endif + + /* Start the retransmission timer if not already running */ + if (p_ccb->peer_cfg.fcr.mode == L2CAP_FCR_ERTM_MODE) + l2c_fcr_start_timer (p_ccb); +} + +/******************************************************************************* +** +** Function l2c_fcr_send_S_frame +** +** Description This function formats and sends an S-frame for transmission. +** +** Returns - +** +*******************************************************************************/ +void l2c_fcr_send_S_frame (tL2C_CCB *p_ccb, UINT16 function_code, UINT16 pf_bit) +{ + assert(p_ccb != NULL); + BT_HDR *p_buf; + UINT8 *p; + UINT16 ctrl_word; + UINT16 fcs; + + if ((!p_ccb->in_use) || (p_ccb->chnl_state != CST_OPEN)) + return; + +#if (L2CAP_ERTM_STATS == TRUE) + p_ccb->fcrb.s_frames_sent[function_code]++; +#endif + + if (pf_bit == L2CAP_FCR_P_BIT) + { + p_ccb->fcrb.wait_ack = TRUE; + + l2c_fcr_stop_timer (p_ccb); /* Restart the monitor timer */ + l2c_fcr_start_timer (p_ccb); + } + + /* Create the control word to use */ + ctrl_word = (function_code << L2CAP_FCR_SUP_SHIFT) | L2CAP_FCR_S_FRAME_BIT; + ctrl_word |= (p_ccb->fcrb.next_seq_expected << L2CAP_FCR_REQ_SEQ_BITS_SHIFT); + ctrl_word |= pf_bit; + + if ((p_buf = (BT_HDR *)GKI_getpoolbuf (L2CAP_CMD_POOL_ID)) != NULL) + { + p_buf->offset = HCI_DATA_PREAMBLE_SIZE; + p_buf->len = L2CAP_PKT_OVERHEAD + L2CAP_FCR_OVERHEAD; + + /* Set the pointer to the beginning of the data */ + p = (UINT8 *)(p_buf + 1) + p_buf->offset; + + /* Put in the L2CAP header */ + UINT16_TO_STREAM (p, L2CAP_FCR_OVERHEAD + L2CAP_FCS_LEN); + UINT16_TO_STREAM (p, p_ccb->remote_cid); + UINT16_TO_STREAM (p, ctrl_word); + + /* Compute the FCS and add to the end of the buffer if not bypassed */ + if (p_ccb->bypass_fcs != L2CAP_BYPASS_FCS) + { + fcs = l2c_fcr_tx_get_fcs (p_buf); + + UINT16_TO_STREAM (p, fcs); + p_buf->len += L2CAP_FCS_LEN; + } + else /* rewrite the length without FCS length */ + { + p -= 6; + UINT16_TO_STREAM (p, L2CAP_FCR_OVERHEAD); + } + + /* Now, the HCI transport header */ + p_buf->layer_specific = L2CAP_NON_FLUSHABLE_PKT; + l2cu_set_acl_hci_header (p_buf, p_ccb); + +#if BT_TRACE_VERBOSE == TRUE + if ((((ctrl_word & L2CAP_FCR_SUP_BITS) >> L2CAP_FCR_SUP_SHIFT) == 1) + || (((ctrl_word & L2CAP_FCR_SUP_BITS) >> L2CAP_FCR_SUP_SHIFT) == 3)) + { + L2CAP_TRACE_WARNING ("L2CAP eRTM Tx S-frame CID: 0x%04x ctrlword: 0x%04x Type: %s ReqSeq: %u P: %u F: %u", + p_ccb->local_cid, ctrl_word, + SUP_types[(ctrl_word & L2CAP_FCR_SUP_BITS) >> L2CAP_FCR_SUP_SHIFT], + (ctrl_word & L2CAP_FCR_REQ_SEQ_BITS) >> L2CAP_FCR_REQ_SEQ_BITS_SHIFT, + (ctrl_word & L2CAP_FCR_P_BIT) >> L2CAP_FCR_P_BIT_SHIFT, + (ctrl_word & L2CAP_FCR_F_BIT) >> L2CAP_FCR_F_BIT_SHIFT); + L2CAP_TRACE_WARNING (" Buf Len: %u", p_buf->len); + } + else + { + L2CAP_TRACE_EVENT ("L2CAP eRTM Tx S-frame CID: 0x%04x ctrlword: 0x%04x Type: %s ReqSeq: %u P: %u F: %u", + p_ccb->local_cid, ctrl_word, + SUP_types[(ctrl_word & L2CAP_FCR_SUP_BITS) >> L2CAP_FCR_SUP_SHIFT], + (ctrl_word & L2CAP_FCR_REQ_SEQ_BITS) >> L2CAP_FCR_REQ_SEQ_BITS_SHIFT, + (ctrl_word & L2CAP_FCR_P_BIT) >> L2CAP_FCR_P_BIT_SHIFT, + (ctrl_word & L2CAP_FCR_F_BIT) >> L2CAP_FCR_F_BIT_SHIFT); + L2CAP_TRACE_EVENT (" Buf Len: %u", p_buf->len); + } +#endif /* BT_TRACE_VERBOSE */ + + l2c_link_check_send_pkts (p_ccb->p_lcb, NULL, p_buf); + + p_ccb->fcrb.last_ack_sent = p_ccb->fcrb.next_seq_expected; + + if (p_ccb->fcrb.ack_timer.in_use) + btu_stop_quick_timer (&p_ccb->fcrb.ack_timer); + } + else + { + L2CAP_TRACE_ERROR ("l2c_fcr_send_S_frame(No Resources) cid 0x%04x, Type: 0x%4x", + p_ccb->local_cid, function_code); + } +} + + +/******************************************************************************* +** +** Function l2c_fcr_proc_pdu +** +** Description This function is the entry point for processing of a +** received PDU when in flow control and/or retransmission modes. +** +** Returns - +** +*******************************************************************************/ +void l2c_fcr_proc_pdu (tL2C_CCB *p_ccb, BT_HDR *p_buf) +{ + assert(p_ccb != NULL); + assert(p_buf != NULL); + UINT8 *p; + UINT16 fcs; + UINT16 min_pdu_len; + UINT16 ctrl_word; + + /* Check the length */ + min_pdu_len = (p_ccb->bypass_fcs == L2CAP_BYPASS_FCS) ? + (UINT16)L2CAP_FCR_OVERHEAD : (UINT16)(L2CAP_FCS_LEN + L2CAP_FCR_OVERHEAD); + + if (p_buf->len < min_pdu_len) + { + L2CAP_TRACE_WARNING ("Rx L2CAP PDU: CID: 0x%04x Len too short: %u", p_ccb->local_cid, p_buf->len); + GKI_freebuf (p_buf); + return; + } + + if (p_ccb->peer_cfg.fcr.mode == L2CAP_FCR_STREAM_MODE) + { + process_stream_frame (p_ccb, p_buf); + return; + } + +#if BT_TRACE_VERBOSE == TRUE + /* Get the control word */ + p = ((UINT8 *)(p_buf+1)) + p_buf->offset; + STREAM_TO_UINT16 (ctrl_word, p); + + if (ctrl_word & L2CAP_FCR_S_FRAME_BIT) + { + if ((((ctrl_word & L2CAP_FCR_SUP_BITS) >> L2CAP_FCR_SUP_SHIFT) == 1) + || (((ctrl_word & L2CAP_FCR_SUP_BITS) >> L2CAP_FCR_SUP_SHIFT) == 3)) + { + /* REJ or SREJ */ + L2CAP_TRACE_WARNING ("L2CAP eRTM Rx S-frame: cid: 0x%04x Len: %u Type: %s ReqSeq: %u P: %u F: %u", + p_ccb->local_cid, p_buf->len, + SUP_types[(ctrl_word & L2CAP_FCR_SUP_BITS) >> L2CAP_FCR_SUP_SHIFT], + (ctrl_word & L2CAP_FCR_REQ_SEQ_BITS) >> L2CAP_FCR_REQ_SEQ_BITS_SHIFT, + (ctrl_word & L2CAP_FCR_P_BIT) >> L2CAP_FCR_P_BIT_SHIFT, + (ctrl_word & L2CAP_FCR_F_BIT) >> L2CAP_FCR_F_BIT_SHIFT); + } + else + { + L2CAP_TRACE_EVENT ("L2CAP eRTM Rx S-frame: cid: 0x%04x Len: %u Type: %s ReqSeq: %u P: %u F: %u", + p_ccb->local_cid, p_buf->len, + SUP_types[(ctrl_word & L2CAP_FCR_SUP_BITS) >> L2CAP_FCR_SUP_SHIFT], + (ctrl_word & L2CAP_FCR_REQ_SEQ_BITS) >> L2CAP_FCR_REQ_SEQ_BITS_SHIFT, + (ctrl_word & L2CAP_FCR_P_BIT) >> L2CAP_FCR_P_BIT_SHIFT, + (ctrl_word & L2CAP_FCR_F_BIT) >> L2CAP_FCR_F_BIT_SHIFT); + } + } + else + { + L2CAP_TRACE_EVENT ("L2CAP eRTM Rx I-frame: cid: 0x%04x Len: %u SAR: %-12s TxSeq: %u ReqSeq: %u F: %u", + p_ccb->local_cid, p_buf->len, + SAR_types[(ctrl_word & L2CAP_FCR_SAR_BITS) >> L2CAP_FCR_SAR_BITS_SHIFT], + (ctrl_word & L2CAP_FCR_TX_SEQ_BITS) >> L2CAP_FCR_TX_SEQ_BITS_SHIFT, + (ctrl_word & L2CAP_FCR_REQ_SEQ_BITS) >> L2CAP_FCR_REQ_SEQ_BITS_SHIFT, + (ctrl_word & L2CAP_FCR_F_BIT) >> L2CAP_FCR_F_BIT_SHIFT); + } + + L2CAP_TRACE_EVENT (" eRTM Rx Nxt_tx_seq %u, Lst_rx_ack %u, Nxt_seq_exp %u, Lst_ack_snt %u, wt_q.cnt %u, tries %u", + p_ccb->fcrb.next_tx_seq, p_ccb->fcrb.last_rx_ack, p_ccb->fcrb.next_seq_expected, + p_ccb->fcrb.last_ack_sent, GKI_queue_length(&p_ccb->fcrb.waiting_for_ack_q), p_ccb->fcrb.num_tries); + +#endif /* BT_TRACE_VERBOSE */ + + /* Verify FCS if using */ + if (p_ccb->bypass_fcs != L2CAP_BYPASS_FCS) + { + p = ((UINT8 *)(p_buf+1)) + p_buf->offset + p_buf->len - L2CAP_FCS_LEN; + + /* Extract and drop the FCS from the packet */ + STREAM_TO_UINT16 (fcs, p); + p_buf->len -= L2CAP_FCS_LEN; + + if (l2c_fcr_rx_get_fcs(p_buf) != fcs) + { + L2CAP_TRACE_WARNING ("Rx L2CAP PDU: CID: 0x%04x BAD FCS", p_ccb->local_cid); + GKI_freebuf(p_buf); + return; + } + } + + /* Get the control word */ + p = ((UINT8 *)(p_buf+1)) + p_buf->offset; + + STREAM_TO_UINT16 (ctrl_word, p); + + p_buf->len -= L2CAP_FCR_OVERHEAD; + p_buf->offset += L2CAP_FCR_OVERHEAD; + + /* If we had a poll bit outstanding, check if we got a final response */ + if (p_ccb->fcrb.wait_ack) + { + /* If final bit not set, ignore the frame unless it is a polled S-frame */ + if ( !(ctrl_word & L2CAP_FCR_F_BIT) ) + { + if ( (ctrl_word & L2CAP_FCR_P_BIT) && (ctrl_word & L2CAP_FCR_S_FRAME_BIT) ) + { + if (p_ccb->fcrb.srej_sent) + l2c_fcr_send_S_frame (p_ccb, L2CAP_FCR_SUP_SREJ, L2CAP_FCR_F_BIT); + else if (p_ccb->fcrb.local_busy) + l2c_fcr_send_S_frame (p_ccb, L2CAP_FCR_SUP_RNR, L2CAP_FCR_F_BIT); + else + l2c_fcr_send_S_frame (p_ccb, L2CAP_FCR_SUP_RR, L2CAP_FCR_F_BIT); + + /* Got a poll while in wait_ack state, so re-start our timer with 1-second */ + /* This is a small optimization... the monitor timer is 12 secs, but we saw */ + /* that if the other side sends us a poll when we are waiting for a final, */ + /* then it speeds up recovery significantly if we poll him back soon after his poll. */ + btu_start_quick_timer (&p_ccb->fcrb.mon_retrans_timer, BTU_TTYPE_L2CAP_CHNL, QUICK_TIMER_TICKS_PER_SEC); + } + GKI_freebuf (p_buf); + return; + } + + p_ccb->fcrb.wait_ack = FALSE; + + /* P and F are mutually exclusive */ + if (ctrl_word & L2CAP_FCR_S_FRAME_BIT) + ctrl_word &= ~L2CAP_FCR_P_BIT; + + if (GKI_queue_is_empty(&p_ccb->fcrb.waiting_for_ack_q)) + p_ccb->fcrb.num_tries = 0; + + l2c_fcr_stop_timer (p_ccb); + } + else + { + /* Otherwise, ensure the final bit is ignored */ + ctrl_word &= ~L2CAP_FCR_F_BIT; + } + + /* Process receive sequence number */ + if (!process_reqseq (p_ccb, ctrl_word)) + { + GKI_freebuf (p_buf); + return; + } + + /* Process based on whether it is an S-frame or an I-frame */ + if (ctrl_word & L2CAP_FCR_S_FRAME_BIT) + process_s_frame (p_ccb, p_buf, ctrl_word); + else + process_i_frame (p_ccb, p_buf, ctrl_word, FALSE); + + /* Return if the channel got disconnected by a bad packet or max retransmissions */ + if ( (!p_ccb->in_use) || (p_ccb->chnl_state != CST_OPEN) ) + return; + + /* If we have some buffers held while doing SREJ, and SREJ has cleared, process them now */ + if ( (!p_ccb->fcrb.local_busy) && (!p_ccb->fcrb.srej_sent) && (!GKI_queue_is_empty(&p_ccb->fcrb.srej_rcv_hold_q))) + { + BUFFER_Q temp_q = p_ccb->fcrb.srej_rcv_hold_q; + + GKI_init_q (&p_ccb->fcrb.srej_rcv_hold_q); + + while ((p_buf = (BT_HDR *)GKI_dequeue (&temp_q)) != NULL) + { + if (p_ccb->in_use && (p_ccb->chnl_state == CST_OPEN)) + { + /* Get the control word */ + p = ((UINT8 *)(p_buf+1)) + p_buf->offset - L2CAP_FCR_OVERHEAD; + + STREAM_TO_UINT16 (ctrl_word, p); + + L2CAP_TRACE_DEBUG ("l2c_fcr_proc_pdu() CID: 0x%04x Process Buffer from SREJ_Hold_Q TxSeq: %u Expected_Seq: %u", + p_ccb->local_cid, (ctrl_word & L2CAP_FCR_TX_SEQ_BITS) >> L2CAP_FCR_TX_SEQ_BITS_SHIFT, + p_ccb->fcrb.next_seq_expected); + + /* Process the SREJ held I-frame, but do not send an RR for each individual frame */ + process_i_frame (p_ccb, p_buf, ctrl_word, TRUE); + } + else + GKI_freebuf (p_buf); + + /* If more frames were lost during SREJ, send a REJ */ + if (p_ccb->fcrb.rej_after_srej) + { + p_ccb->fcrb.rej_after_srej = FALSE; + p_ccb->fcrb.rej_sent = TRUE; + + l2c_fcr_send_S_frame (p_ccb, L2CAP_FCR_SUP_REJ, 0); + } + } + + /* Now, if needed, send one RR for the whole held queue */ + if ( (!p_ccb->fcrb.local_busy) && (!p_ccb->fcrb.rej_sent) && (!p_ccb->fcrb.srej_sent) + && (p_ccb->fcrb.next_seq_expected != p_ccb->fcrb.last_ack_sent) ) + l2c_fcr_send_S_frame (p_ccb, L2CAP_FCR_SUP_RR, 0); + else + { + L2CAP_TRACE_DEBUG ("l2c_fcr_proc_pdu() not sending RR CID: 0x%04x local_busy:%d rej_sent:%d srej_sent:%d Expected_Seq:%u Last_Ack:%u", + p_ccb->local_cid, p_ccb->fcrb.local_busy, p_ccb->fcrb.rej_sent, p_ccb->fcrb.srej_sent, p_ccb->fcrb.next_seq_expected, + p_ccb->fcrb.last_ack_sent); + } + } + + /* If a window has opened, check if we can send any more packets */ + if ( (!GKI_queue_is_empty(&p_ccb->fcrb.retrans_q) || !GKI_queue_is_empty(&p_ccb->xmit_hold_q)) + && (p_ccb->fcrb.wait_ack == FALSE) + && (l2c_fcr_is_flow_controlled (p_ccb) == FALSE) ) + { + l2c_link_check_send_pkts (p_ccb->p_lcb, NULL, NULL); + } +} + +/******************************************************************************* +** +** Function l2c_fcr_proc_tout +** +** Description Handle a timeout. We should be in error recovery state. +** +** Returns - +** +*******************************************************************************/ +void l2c_fcr_proc_tout (tL2C_CCB *p_ccb) +{ + assert(p_ccb != NULL); + L2CAP_TRACE_DEBUG ("l2c_fcr_proc_tout: CID: 0x%04x num_tries: %u (max: %u) wait_ack: %u ack_q_count: %u", + p_ccb->local_cid, p_ccb->fcrb.num_tries, p_ccb->peer_cfg.fcr.max_transmit, + p_ccb->fcrb.wait_ack, GKI_queue_length(&p_ccb->fcrb.waiting_for_ack_q)); + +#if (L2CAP_ERTM_STATS == TRUE) + p_ccb->fcrb.retrans_touts++; +#endif + + if ( (p_ccb->peer_cfg.fcr.max_transmit != 0) && (++p_ccb->fcrb.num_tries > p_ccb->peer_cfg.fcr.max_transmit) ) + { + l2cu_disconnect_chnl (p_ccb); + } + else + { + if (!p_ccb->fcrb.srej_sent && !p_ccb->fcrb.rej_sent) + { + if (p_ccb->fcrb.local_busy) + l2c_fcr_send_S_frame (p_ccb, L2CAP_FCR_SUP_RNR, L2CAP_FCR_P_BIT); + else + l2c_fcr_send_S_frame (p_ccb, L2CAP_FCR_SUP_RR, L2CAP_FCR_P_BIT); + } + } +} + + +/******************************************************************************* +** +** Function l2c_fcr_proc_ack_tout +** +** Description Send RR/RNR if we have not acked I frame +** +** Returns - +** +*******************************************************************************/ +void l2c_fcr_proc_ack_tout (tL2C_CCB *p_ccb) +{ + assert(p_ccb != NULL); + L2CAP_TRACE_DEBUG ("l2c_fcr_proc_ack_tout: CID: 0x%04x State: %u Wack:%u Rq:%d Acked:%d", p_ccb->local_cid, + p_ccb->chnl_state, p_ccb->fcrb.wait_ack, p_ccb->fcrb.next_seq_expected, p_ccb->fcrb.last_ack_sent); + + if ( (p_ccb->chnl_state == CST_OPEN) && (!p_ccb->fcrb.wait_ack) + && (p_ccb->fcrb.last_ack_sent != p_ccb->fcrb.next_seq_expected) ) + { +#if (L2CAP_ERTM_STATS == TRUE) + p_ccb->fcrb.xmit_ack_touts++; +#endif + if (p_ccb->fcrb.local_busy) + l2c_fcr_send_S_frame (p_ccb, L2CAP_FCR_SUP_RNR, 0); + else + l2c_fcr_send_S_frame (p_ccb, L2CAP_FCR_SUP_RR, 0); + } +} + + +/******************************************************************************* +** +** Function process_reqseq +** +** Description Handle receive sequence number +** +** Returns - +** +*******************************************************************************/ +static BOOLEAN process_reqseq (tL2C_CCB *p_ccb, UINT16 ctrl_word) +{ + assert(p_ccb != NULL); + tL2C_FCRB *p_fcrb = &p_ccb->fcrb; + UINT8 req_seq, num_bufs_acked, xx; + UINT16 ls; + UINT16 full_sdus_xmitted; + + /* Receive sequence number does not ack anything for SREJ with P-bit set to zero */ + if ( (ctrl_word & L2CAP_FCR_S_FRAME_BIT) + && ((ctrl_word & L2CAP_FCR_SUP_BITS) == (L2CAP_FCR_SUP_SREJ << L2CAP_FCR_SUP_SHIFT)) + && ((ctrl_word & L2CAP_FCR_P_BIT) == 0) ) + { + /* If anything still waiting for ack, restart the timer if it was stopped */ + if (!GKI_queue_is_empty(&p_fcrb->waiting_for_ack_q)) + l2c_fcr_start_timer (p_ccb); + + return (TRUE); + } + + /* Extract the receive sequence number from the control word */ + req_seq = (ctrl_word & L2CAP_FCR_REQ_SEQ_BITS) >> L2CAP_FCR_REQ_SEQ_BITS_SHIFT; + + num_bufs_acked = (req_seq - p_fcrb->last_rx_ack) & L2CAP_FCR_SEQ_MODULO; + + /* Verify the request sequence is in range before proceeding */ + if (num_bufs_acked > GKI_queue_length(&p_fcrb->waiting_for_ack_q)) + { + /* The channel is closed if ReqSeq is not in range */ + L2CAP_TRACE_WARNING ("L2CAP eRTM Frame BAD Req_Seq - ctrl_word: 0x%04x req_seq 0x%02x last_rx_ack: 0x%02x QCount: %u", + ctrl_word, req_seq, p_fcrb->last_rx_ack, GKI_queue_length(&p_fcrb->waiting_for_ack_q)); + + l2cu_disconnect_chnl (p_ccb); + return (FALSE); + } + + p_fcrb->last_rx_ack = req_seq; + + /* Now we can release all acknowledged frames, and restart the retransmission timer if needed */ + if (num_bufs_acked != 0) + { + p_fcrb->num_tries = 0; + full_sdus_xmitted = 0; + +#if (L2CAP_ERTM_STATS == TRUE) + l2c_fcr_collect_ack_delay (p_ccb, num_bufs_acked); +#endif + + for (xx = 0; xx < num_bufs_acked; xx++) + { + ls = ((BT_HDR *)(GKI_getfirst(&p_fcrb->waiting_for_ack_q)))->layer_specific & L2CAP_FCR_SAR_BITS; + + if ( (ls == L2CAP_FCR_UNSEG_SDU) || (ls == L2CAP_FCR_END_SDU) ) + full_sdus_xmitted++; + + GKI_freebuf (GKI_dequeue (&p_fcrb->waiting_for_ack_q)); + } + + /* If we are still in a wait_ack state, do not mess with the timer */ + if (!p_ccb->fcrb.wait_ack) + l2c_fcr_stop_timer (p_ccb); + + /* Check if we need to call the "packet_sent" callback */ + if ( (p_ccb->p_rcb) && (p_ccb->p_rcb->api.pL2CA_TxComplete_Cb) && (full_sdus_xmitted) ) + { + /* Special case for eRTM, if all packets sent, send 0xFFFF */ + if (GKI_queue_is_empty(&p_fcrb->waiting_for_ack_q) && (GKI_queue_is_empty(&p_ccb->xmit_hold_q))) + full_sdus_xmitted = 0xFFFF; + + (*p_ccb->p_rcb->api.pL2CA_TxComplete_Cb)(p_ccb->local_cid, full_sdus_xmitted); + } + } + + /* If anything still waiting for ack, restart the timer if it was stopped */ + if (!GKI_queue_is_empty(&p_fcrb->waiting_for_ack_q)) + l2c_fcr_start_timer (p_ccb); + + return (TRUE); +} + + +/******************************************************************************* +** +** Function process_s_frame +** +** Description Process an S frame +** +** Returns - +** +*******************************************************************************/ +static void process_s_frame (tL2C_CCB *p_ccb, BT_HDR *p_buf, UINT16 ctrl_word) +{ + assert(p_ccb != NULL); + assert(p_buf != NULL); + + tL2C_FCRB *p_fcrb = &p_ccb->fcrb; + UINT16 s_frame_type = (ctrl_word & L2CAP_FCR_SUP_BITS) >> L2CAP_FCR_SUP_SHIFT; + BOOLEAN remote_was_busy; + BOOLEAN all_ok = TRUE; + + if (p_buf->len != 0) + { + L2CAP_TRACE_WARNING ("Incorrect S-frame Length (%d)", p_buf->len); + } + + L2CAP_TRACE_DEBUG ("process_s_frame ctrl_word 0x%04x fcrb_remote_busy:%d", ctrl_word, p_fcrb->remote_busy); + +#if (L2CAP_ERTM_STATS == TRUE) + p_ccb->fcrb.s_frames_rcvd[s_frame_type]++; +#endif + + if (ctrl_word & L2CAP_FCR_P_BIT) + { + p_fcrb->rej_sent = FALSE; /* After checkpoint, we can send anoher REJ */ + p_fcrb->send_f_rsp = TRUE; /* Set a flag in case an I-frame is pending */ + } + + switch (s_frame_type) + { + case L2CAP_FCR_SUP_RR: + remote_was_busy = p_fcrb->remote_busy; + p_fcrb->remote_busy = FALSE; + + if ( (ctrl_word & L2CAP_FCR_F_BIT) || (remote_was_busy) ) + all_ok = retransmit_i_frames (p_ccb, L2C_FCR_RETX_ALL_PKTS); + break; + + case L2CAP_FCR_SUP_REJ: + p_fcrb->remote_busy = FALSE; + all_ok = retransmit_i_frames (p_ccb, L2C_FCR_RETX_ALL_PKTS); + break; + + case L2CAP_FCR_SUP_RNR: + p_fcrb->remote_busy = TRUE; + l2c_fcr_stop_timer (p_ccb); + break; + + case L2CAP_FCR_SUP_SREJ: + p_fcrb->remote_busy = FALSE; + all_ok = retransmit_i_frames (p_ccb, (UINT8)((ctrl_word & L2CAP_FCR_REQ_SEQ_BITS) >> L2CAP_FCR_REQ_SEQ_BITS_SHIFT)); + break; + } + + if (all_ok) + { + /* If polled, we need to respond with F-bit. Note, we may have sent a I-frame with the F-bit */ + if (p_fcrb->send_f_rsp) + { + if (p_fcrb->srej_sent) + l2c_fcr_send_S_frame (p_ccb, L2CAP_FCR_SUP_SREJ, L2CAP_FCR_F_BIT); + else if (p_fcrb->local_busy) + l2c_fcr_send_S_frame (p_ccb, L2CAP_FCR_SUP_RNR, L2CAP_FCR_F_BIT); + else + l2c_fcr_send_S_frame (p_ccb, L2CAP_FCR_SUP_RR, L2CAP_FCR_F_BIT); + + p_fcrb->send_f_rsp = FALSE; + } + } + else + { + L2CAP_TRACE_DEBUG ("process_s_frame hit_max_retries"); + } + + GKI_freebuf (p_buf); +} + + +/******************************************************************************* +** +** Function process_i_frame +** +** Description Process an I frame +** +** Returns - +** +*******************************************************************************/ +static void process_i_frame (tL2C_CCB *p_ccb, BT_HDR *p_buf, UINT16 ctrl_word, BOOLEAN delay_ack) +{ + assert(p_ccb != NULL); + assert(p_buf != NULL); + + tL2C_FCRB *p_fcrb = &p_ccb->fcrb; + UINT8 tx_seq, num_lost, num_to_ack, next_srej; + + /* If we were doing checkpoint recovery, first retransmit all unacked I-frames */ + if (ctrl_word & L2CAP_FCR_F_BIT) + { + if (!retransmit_i_frames (p_ccb, L2C_FCR_RETX_ALL_PKTS)) + { + GKI_freebuf(p_buf); + return; + } + } + +#if (L2CAP_ERTM_STATS == TRUE) + p_ccb->fcrb.ertm_pkt_counts[1]++; + p_ccb->fcrb.ertm_byte_counts[1] += p_buf->len; +#endif + + /* Extract the sequence number */ + tx_seq = (ctrl_word & L2CAP_FCR_TX_SEQ_BITS) >> L2CAP_FCR_TX_SEQ_BITS_SHIFT; + + /* If we have flow controlled the peer, ignore any bad I-frames from him */ + if ( (tx_seq != p_fcrb->next_seq_expected) && (p_fcrb->local_busy) ) + { + L2CAP_TRACE_WARNING ("Dropping bad I-Frame since we flowed off, tx_seq:%u", tx_seq); + l2c_fcr_send_S_frame (p_ccb, L2CAP_FCR_SUP_RNR, 0); + GKI_freebuf(p_buf); + return; + } + + /* If there are no free buffers in the user Rx queue, drop the */ + /* received buffer now before we update any sequence numbers */ + if (GKI_poolfreecount (p_ccb->ertm_info.user_rx_pool_id) == 0) + { + L2CAP_TRACE_WARNING ("L2CAP CID: 0x%04x Dropping I-Frame seq: %u User RX Pool: %u (Size: %u) has no free buffers!!", + p_ccb->local_cid, tx_seq, p_ccb->ertm_info.user_rx_pool_id, + GKI_poolcount (p_ccb->ertm_info.user_rx_pool_id)); + GKI_freebuf(p_buf); + return; + } + + /* Check if tx-sequence is the expected one */ + if (tx_seq != p_fcrb->next_seq_expected) + { + num_lost = (tx_seq - p_fcrb->next_seq_expected) & L2CAP_FCR_SEQ_MODULO; + + /* Is the frame a duplicate ? If so, just drop it */ + if (num_lost >= p_ccb->our_cfg.fcr.tx_win_sz) + { + /* Duplicate - simply drop it */ + L2CAP_TRACE_WARNING ("process_i_frame() Dropping Duplicate Frame tx_seq:%u ExpectedTxSeq %u", tx_seq, p_fcrb->next_seq_expected); + GKI_freebuf(p_buf); + } + else + { + L2CAP_TRACE_WARNING ("process_i_frame() CID: 0x%04x Lost: %u tx_seq:%u ExpTxSeq %u Rej: %u SRej: %u", + p_ccb->local_cid, num_lost, tx_seq, p_fcrb->next_seq_expected, p_fcrb->rej_sent, p_fcrb->srej_sent); + + if (p_fcrb->srej_sent) + { + /* If SREJ sent, save the frame for later processing as long as it is in sequence */ + next_srej = (((BT_HDR *)GKI_getlast(&p_fcrb->srej_rcv_hold_q))->layer_specific + 1) & L2CAP_FCR_SEQ_MODULO; + + if ( (tx_seq == next_srej) && (GKI_queue_length(&p_fcrb->srej_rcv_hold_q) < p_ccb->our_cfg.fcr.tx_win_sz) ) + { + /* If user gave us a pool for held rx buffers, use that */ + if (p_ccb->ertm_info.fcr_rx_pool_id != HCI_ACL_POOL_ID) + { + BT_HDR *p_buf2; + + /* Adjust offset and len so that control word is copied */ + p_buf->offset -= L2CAP_FCR_OVERHEAD; + p_buf->len += L2CAP_FCR_OVERHEAD; + + p_buf2 = l2c_fcr_clone_buf (p_buf, p_buf->offset, p_buf->len, p_ccb->ertm_info.fcr_rx_pool_id); + + if (p_buf2) + { + GKI_freebuf (p_buf); + p_buf = p_buf2; + } + p_buf->offset += L2CAP_FCR_OVERHEAD; + p_buf->len -= L2CAP_FCR_OVERHEAD; + } + L2CAP_TRACE_DEBUG ("process_i_frame() Lost: %u tx_seq:%u ExpTxSeq %u Rej: %u SRej1", + num_lost, tx_seq, p_fcrb->next_seq_expected, p_fcrb->rej_sent); + + p_buf->layer_specific = tx_seq; + GKI_enqueue (&p_fcrb->srej_rcv_hold_q, p_buf); + } + else + { + L2CAP_TRACE_WARNING ("process_i_frame() CID: 0x%04x frame dropped in Srej Sent next_srej:%u hold_q.count:%u win_sz:%u", + p_ccb->local_cid, next_srej, GKI_queue_length(&p_fcrb->srej_rcv_hold_q), p_ccb->our_cfg.fcr.tx_win_sz); + + p_fcrb->rej_after_srej = TRUE; + GKI_freebuf (p_buf); + } + } + else if (p_fcrb->rej_sent) + { + L2CAP_TRACE_WARNING ("process_i_frame() CID: 0x%04x Lost: %u tx_seq:%u ExpTxSeq %u Rej: 1 SRej: %u", + p_ccb->local_cid, num_lost, tx_seq, p_fcrb->next_seq_expected, p_fcrb->srej_sent); + + /* If REJ sent, just drop the frame */ + GKI_freebuf (p_buf); + } + else + { + L2CAP_TRACE_DEBUG ("process_i_frame() CID: 0x%04x tx_seq:%u ExpTxSeq %u Rej: %u", + p_ccb->local_cid, tx_seq, p_fcrb->next_seq_expected, p_fcrb->rej_sent); + + /* If only one lost, we will send SREJ, otherwise we will send REJ */ + if (num_lost > 1) + { + GKI_freebuf (p_buf); + p_fcrb->rej_sent = TRUE; + l2c_fcr_send_S_frame (p_ccb, L2CAP_FCR_SUP_REJ, 0); + } + else + { + if (!GKI_queue_is_empty(&p_fcrb->srej_rcv_hold_q)) + { + L2CAP_TRACE_ERROR ("process_i_frame() CID: 0x%04x sending SREJ tx_seq:%d hold_q.count:%u", + p_ccb->local_cid, tx_seq, GKI_queue_length(&p_fcrb->srej_rcv_hold_q)); + } + p_buf->layer_specific = tx_seq; + GKI_enqueue (&p_fcrb->srej_rcv_hold_q, p_buf); + p_fcrb->srej_sent = TRUE; + l2c_fcr_send_S_frame (p_ccb, L2CAP_FCR_SUP_SREJ, 0); + } + btu_stop_quick_timer (&p_ccb->fcrb.ack_timer); + } + } + return; + } + + /* Seq number is the next expected. Clear possible reject exception in case it occured */ + p_fcrb->rej_sent = p_fcrb->srej_sent = FALSE; + + /* Adjust the next_seq, so that if the upper layer sends more data in the callback + context, the received frame is acked by an I-frame. */ + p_fcrb->next_seq_expected = (tx_seq + 1) & L2CAP_FCR_SEQ_MODULO; + + /* If any SAR problem in eRTM mode, spec says disconnect. */ + if (!do_sar_reassembly (p_ccb, p_buf, ctrl_word)) + { + L2CAP_TRACE_WARNING ("process_i_frame() CID: 0x%04x reassembly failed", p_ccb->local_cid); + l2cu_disconnect_chnl (p_ccb); + return; + } + + /* RR optimization - if peer can still send us more, then start an ACK timer */ + num_to_ack = (p_fcrb->next_seq_expected - p_fcrb->last_ack_sent) & L2CAP_FCR_SEQ_MODULO; + + if ( (num_to_ack < p_ccb->fcrb.max_held_acks) && (!p_fcrb->local_busy) ) + delay_ack = TRUE; + + /* We should neve never ack frame if we are not in OPEN state */ + if ((num_to_ack != 0) && p_ccb->in_use && (p_ccb->chnl_state == CST_OPEN)) + { + /* If no frames are awaiting transmission or are held, send an RR or RNR S-frame for ack */ + if (delay_ack) + { + /* If it is the first I frame we did not ack, start ack timer */ + if (!p_ccb->fcrb.ack_timer.in_use) + { + btu_start_quick_timer (&p_ccb->fcrb.ack_timer, BTU_TTYPE_L2CAP_FCR_ACK, + (L2CAP_FCR_ACK_TOUT*QUICK_TIMER_TICKS_PER_SEC)/1000); + } + } + else if ( ((GKI_queue_is_empty(&p_ccb->xmit_hold_q)) || (l2c_fcr_is_flow_controlled (p_ccb))) + && (GKI_queue_is_empty(&p_ccb->fcrb.srej_rcv_hold_q))) + { + if (p_fcrb->local_busy) + l2c_fcr_send_S_frame (p_ccb, L2CAP_FCR_SUP_RNR, 0); + else + l2c_fcr_send_S_frame (p_ccb, L2CAP_FCR_SUP_RR, 0); + } + } +} + + +/******************************************************************************* +** +** Function process_stream_frame +** +** Description This function processes frames in streaming mode +** +** Returns - +** +*******************************************************************************/ +static void process_stream_frame (tL2C_CCB *p_ccb, BT_HDR *p_buf) +{ + assert(p_ccb != NULL); + assert(p_buf != NULL); + + UINT16 ctrl_word; + UINT16 fcs; + UINT8 *p; + UINT8 tx_seq; + + /* Verify FCS if using */ + if (p_ccb->bypass_fcs != L2CAP_BYPASS_FCS) + { + p = ((UINT8 *)(p_buf+1)) + p_buf->offset + p_buf->len - L2CAP_FCS_LEN; + + /* Extract and drop the FCS from the packet */ + STREAM_TO_UINT16 (fcs, p); + p_buf->len -= L2CAP_FCS_LEN; + + if (l2c_fcr_rx_get_fcs(p_buf) != fcs) + { + L2CAP_TRACE_WARNING ("Rx L2CAP PDU: CID: 0x%04x BAD FCS", p_ccb->local_cid); + GKI_freebuf(p_buf); + return; + } + } + + /* Get the control word */ + p = ((UINT8 *)(p_buf+1)) + p_buf->offset; + + STREAM_TO_UINT16 (ctrl_word, p); + + p_buf->len -= L2CAP_FCR_OVERHEAD; + p_buf->offset += L2CAP_FCR_OVERHEAD; + + /* Make sure it is an I-frame */ + if (ctrl_word & L2CAP_FCR_S_FRAME_BIT) + { + L2CAP_TRACE_WARNING ("Rx L2CAP PDU: CID: 0x%04x BAD S-frame in streaming mode ctrl_word: 0x%04x", p_ccb->local_cid, ctrl_word); + GKI_freebuf (p_buf); + return; + } + +#if BT_TRACE_VERBOSE == TRUE + L2CAP_TRACE_EVENT ("L2CAP eRTM Rx I-frame: cid: 0x%04x Len: %u SAR: %-12s TxSeq: %u ReqSeq: %u F: %u", + p_ccb->local_cid, p_buf->len, + SAR_types[(ctrl_word & L2CAP_FCR_SAR_BITS) >> L2CAP_FCR_SAR_BITS_SHIFT], + (ctrl_word & L2CAP_FCR_TX_SEQ_BITS) >> L2CAP_FCR_TX_SEQ_BITS_SHIFT, + (ctrl_word & L2CAP_FCR_REQ_SEQ_BITS) >> L2CAP_FCR_REQ_SEQ_BITS_SHIFT, + (ctrl_word & L2CAP_FCR_F_BIT) >> L2CAP_FCR_F_BIT_SHIFT); +#endif + + /* Extract the sequence number */ + tx_seq = (ctrl_word & L2CAP_FCR_TX_SEQ_BITS) >> L2CAP_FCR_TX_SEQ_BITS_SHIFT; + + /* Check if tx-sequence is the expected one */ + if (tx_seq != p_ccb->fcrb.next_seq_expected) + { + L2CAP_TRACE_WARNING ("Rx L2CAP PDU: CID: 0x%04x Lost frames Exp: %u Got: %u p_rx_sdu: 0x%08x", + p_ccb->local_cid, p_ccb->fcrb.next_seq_expected, tx_seq, p_ccb->fcrb.p_rx_sdu); + + /* Lost one or more packets, so flush the SAR queue */ + if (p_ccb->fcrb.p_rx_sdu != NULL) + { + GKI_freebuf (p_ccb->fcrb.p_rx_sdu); + p_ccb->fcrb.p_rx_sdu = NULL; + } + } + + p_ccb->fcrb.next_seq_expected = (tx_seq + 1) & L2CAP_FCR_SEQ_MODULO; + + if (!do_sar_reassembly (p_ccb, p_buf, ctrl_word)) + { + /* Some sort of SAR error, so flush the SAR queue */ + if (p_ccb->fcrb.p_rx_sdu != NULL) + { + GKI_freebuf (p_ccb->fcrb.p_rx_sdu); + p_ccb->fcrb.p_rx_sdu = NULL; + } + } +} + + +/******************************************************************************* +** +** Function do_sar_reassembly +** +** Description Process SAR bits and re-assemble frame +** +** Returns TRUE if all OK, else FALSE +** +*******************************************************************************/ +static BOOLEAN do_sar_reassembly (tL2C_CCB *p_ccb, BT_HDR *p_buf, UINT16 ctrl_word) +{ + assert(p_ccb != NULL); + assert(p_buf != NULL); + + tL2C_FCRB *p_fcrb = &p_ccb->fcrb; + UINT16 sar_type = ctrl_word & L2CAP_FCR_SEG_BITS; + BOOLEAN packet_ok = TRUE; + UINT8 *p; + + /* Check if the SAR state is correct */ + if ((sar_type == L2CAP_FCR_UNSEG_SDU) || (sar_type == L2CAP_FCR_START_SDU)) + { + if (p_fcrb->p_rx_sdu != NULL) + { + L2CAP_TRACE_WARNING ("SAR - got unexpected unsegmented or start SDU Expected len: %u Got so far: %u", + p_fcrb->rx_sdu_len, p_fcrb->p_rx_sdu->len); + + packet_ok = FALSE; + } + /* Check the length of the packet */ + if ( (sar_type == L2CAP_FCR_START_SDU) && (p_buf->len < L2CAP_SDU_LEN_OVERHEAD) ) + { + L2CAP_TRACE_WARNING ("SAR start packet too short: %u", p_buf->len); + packet_ok = FALSE; + } + } + else + { + if (p_fcrb->p_rx_sdu == NULL) + { + L2CAP_TRACE_WARNING ("SAR - got unexpected cont or end SDU"); + packet_ok = FALSE; + } + } + + if ( (packet_ok) && (sar_type != L2CAP_FCR_UNSEG_SDU) ) + { + p = ((UINT8 *)(p_buf + 1)) + p_buf->offset; + + /* For start SDU packet, extract the SDU length */ + if (sar_type == L2CAP_FCR_START_SDU) + { + /* Get the SDU length */ + STREAM_TO_UINT16 (p_fcrb->rx_sdu_len, p); + p_buf->offset += 2; + p_buf->len -= 2; + + if (p_fcrb->rx_sdu_len > p_ccb->max_rx_mtu) + { + L2CAP_TRACE_WARNING ("SAR - SDU len: %u larger than MTU: %u", p_fcrb->rx_sdu_len, p_fcrb->rx_sdu_len); + packet_ok = FALSE; + } + else if ((p_fcrb->p_rx_sdu = (BT_HDR *)GKI_getpoolbuf (p_ccb->ertm_info.user_rx_pool_id)) == NULL) + { + L2CAP_TRACE_ERROR ("SAR - no buffer for SDU start user_rx_pool_id:%d", p_ccb->ertm_info.user_rx_pool_id); + packet_ok = FALSE; + } + else + { + p_fcrb->p_rx_sdu->offset = 4; /* this is the minimal offset required by OBX to process incoming packets */ + p_fcrb->p_rx_sdu->len = 0; + } + } + + if (packet_ok) + { + if ((p_fcrb->p_rx_sdu->len + p_buf->len) > p_fcrb->rx_sdu_len) + { + L2CAP_TRACE_ERROR ("SAR - SDU len exceeded Type: %u Lengths: %u %u %u", + sar_type, p_fcrb->p_rx_sdu->len, p_buf->len, p_fcrb->rx_sdu_len); + packet_ok = FALSE; + } + else if ( (sar_type == L2CAP_FCR_END_SDU) && ((p_fcrb->p_rx_sdu->len + p_buf->len) != p_fcrb->rx_sdu_len) ) + { + L2CAP_TRACE_WARNING ("SAR - SDU end rcvd but SDU incomplete: %u %u %u", + p_fcrb->p_rx_sdu->len, p_buf->len, p_fcrb->rx_sdu_len); + packet_ok = FALSE; + } + else + { + memcpy (((UINT8 *) (p_fcrb->p_rx_sdu + 1)) + p_fcrb->p_rx_sdu->offset + p_fcrb->p_rx_sdu->len, p, p_buf->len); + + p_fcrb->p_rx_sdu->len += p_buf->len; + + GKI_freebuf (p_buf); + p_buf = NULL; + + if (sar_type == L2CAP_FCR_END_SDU) + { + p_buf = p_fcrb->p_rx_sdu; + p_fcrb->p_rx_sdu = NULL; + } + } + } + } + + if (packet_ok == FALSE) + { + GKI_freebuf (p_buf); + } + else if (p_buf != NULL) + { +#if (L2CAP_NUM_FIXED_CHNLS > 0) + if (p_ccb->local_cid < L2CAP_BASE_APPL_CID && + (p_ccb->local_cid >= L2CAP_FIRST_FIXED_CHNL && p_ccb->local_cid <= L2CAP_LAST_FIXED_CHNL)) + { + if (l2cb.fixed_reg[p_ccb->local_cid - L2CAP_FIRST_FIXED_CHNL].pL2CA_FixedData_Cb) + (*l2cb.fixed_reg[p_ccb->local_cid - L2CAP_FIRST_FIXED_CHNL].pL2CA_FixedData_Cb) + (p_ccb->local_cid, p_ccb->p_lcb->remote_bd_addr, p_buf); + } + else +#endif + l2c_csm_execute (p_ccb, L2CEVT_L2CAP_DATA, p_buf); + } + + return (packet_ok); +} + + +/******************************************************************************* +** +** Function retransmit_i_frames +** +** Description This function retransmits i-frames awaiting acks. +** +** Returns BOOLEAN - TRUE if retransmitted +** +*******************************************************************************/ +static BOOLEAN retransmit_i_frames (tL2C_CCB *p_ccb, UINT8 tx_seq) +{ + assert(p_ccb != NULL); + + BT_HDR *p_buf, *p_buf2; + UINT8 *p; + UINT8 buf_seq; + UINT16 ctrl_word; + + if ( (GKI_getfirst(&p_ccb->fcrb.waiting_for_ack_q)) + && (p_ccb->peer_cfg.fcr.max_transmit != 0) + && (p_ccb->fcrb.num_tries >= p_ccb->peer_cfg.fcr.max_transmit) ) + { + L2CAP_TRACE_EVENT ("Max Tries Exceeded: (last_acq: %d CID: 0x%04x num_tries: %u (max: %u) ack_q_count: %u", + p_ccb->fcrb.last_rx_ack, p_ccb->local_cid, p_ccb->fcrb.num_tries, p_ccb->peer_cfg.fcr.max_transmit, + GKI_queue_length(&p_ccb->fcrb.waiting_for_ack_q)); + + l2cu_disconnect_chnl (p_ccb); + return (FALSE); + } + + /* tx_seq indicates whether to retransmit a specific sequence or all (if == L2C_FCR_RETX_ALL_PKTS) */ + if (tx_seq != L2C_FCR_RETX_ALL_PKTS) + { + /* If sending only one, the sequence number tells us which one. Look for it. + */ + for (p_buf = (BT_HDR *)GKI_getfirst(&p_ccb->fcrb.waiting_for_ack_q); p_buf; p_buf = (BT_HDR *)GKI_getnext (p_buf)) + { + /* Get the old control word */ + p = ((UINT8 *) (p_buf+1)) + p_buf->offset + L2CAP_PKT_OVERHEAD; + + STREAM_TO_UINT16 (ctrl_word, p); + + buf_seq = (ctrl_word & L2CAP_FCR_TX_SEQ_BITS) >> L2CAP_FCR_TX_SEQ_BITS_SHIFT; + + L2CAP_TRACE_DEBUG ("retransmit_i_frames() cur seq: %u looking for: %u", buf_seq, tx_seq); + + if (tx_seq == buf_seq) + break; + } + + if (!p_buf) + { + L2CAP_TRACE_ERROR ("retransmit_i_frames() UNKNOWN seq: %u q_count: %u", tx_seq, GKI_queue_length(&p_ccb->fcrb.waiting_for_ack_q)); + return (TRUE); + } + } + else + { + // Iterate though list and flush the amount requested from + // the transmit data queue that satisfy the layer and event conditions. + for (const list_node_t *node = list_begin(p_ccb->p_lcb->link_xmit_data_q); + node != list_end(p_ccb->p_lcb->link_xmit_data_q);) { + BT_HDR *p_buf = (BT_HDR *)list_node(node); + node = list_next(node); + + /* Do not flush other CIDs or partial segments */ + if ((p_buf->layer_specific == 0) && (p_buf->event == p_ccb->local_cid)) { + list_remove(p_ccb->p_lcb->link_xmit_data_q, p_buf); + GKI_freebuf(p_buf); + } + } + + /* Also flush our retransmission queue */ + while (!GKI_queue_is_empty(&p_ccb->fcrb.retrans_q)) + GKI_freebuf (GKI_dequeue (&p_ccb->fcrb.retrans_q)); + + p_buf = (BT_HDR *)GKI_getfirst(&p_ccb->fcrb.waiting_for_ack_q); + } + + while (p_buf != NULL) + { + p_buf2 = l2c_fcr_clone_buf (p_buf, p_buf->offset, p_buf->len, p_ccb->ertm_info.fcr_tx_pool_id); + + if (p_buf2) + { + p_buf2->layer_specific = p_buf->layer_specific; + + GKI_enqueue (&p_ccb->fcrb.retrans_q, p_buf2); + } + + if ( (tx_seq != L2C_FCR_RETX_ALL_PKTS) || (p_buf2 == NULL) ) + break; + else + p_buf = (BT_HDR *)GKI_getnext (p_buf); + } + + l2c_link_check_send_pkts (p_ccb->p_lcb, NULL, NULL); + + if (GKI_queue_length(&p_ccb->fcrb.waiting_for_ack_q)) + { + p_ccb->fcrb.num_tries++; + l2c_fcr_start_timer (p_ccb); + } + + return (TRUE); +} + + +/******************************************************************************* +** +** Function l2c_fcr_get_next_xmit_sdu_seg +** +** Description Get the next SDU segment to transmit. +** +** Returns pointer to buffer with segment or NULL +** +*******************************************************************************/ +BT_HDR *l2c_fcr_get_next_xmit_sdu_seg (tL2C_CCB *p_ccb, UINT16 max_packet_length) +{ + assert(p_ccb != NULL); + + BOOLEAN first_seg = FALSE, /* The segment is the first part of data */ + mid_seg = FALSE, /* The segment is the middle part of data */ + last_seg = FALSE; /* The segment is the last part of data */ + UINT16 sdu_len = 0; + BT_HDR *p_buf, *p_xmit; + UINT8 *p; + UINT16 max_pdu = p_ccb->tx_mps /* Needed? - L2CAP_MAX_HEADER_FCS*/; + + /* If there is anything in the retransmit queue, that goes first + */ + if (GKI_getfirst(&p_ccb->fcrb.retrans_q)) + { + p_buf = (BT_HDR *)GKI_dequeue (&p_ccb->fcrb.retrans_q); + + /* Update Rx Seq and FCS if we acked some packets while this one was queued */ + prepare_I_frame (p_ccb, p_buf, TRUE); + + p_buf->event = p_ccb->local_cid; + +#if (L2CAP_ERTM_STATS == TRUE) + p_ccb->fcrb.pkts_retransmitted++; + p_ccb->fcrb.ertm_pkt_counts[0]++; + p_ccb->fcrb.ertm_byte_counts[0] += (p_buf->len - 8); +#endif + return (p_buf); + } + + /* For BD/EDR controller, max_packet_length is set to 0 */ + /* For AMP controller, max_packet_length is set by available blocks */ + if ( (max_packet_length > L2CAP_MAX_HEADER_FCS) + && (max_pdu + L2CAP_MAX_HEADER_FCS > max_packet_length) ) + { + max_pdu = max_packet_length - L2CAP_MAX_HEADER_FCS; + } + + p_buf = (BT_HDR *)GKI_getfirst(&p_ccb->xmit_hold_q); + + /* If there is more data than the MPS, it requires segmentation */ + if (p_buf->len > max_pdu) + { + /* We are using the "event" field to tell is if we already started segmentation */ + if (p_buf->event == 0) + { + first_seg = TRUE; + sdu_len = p_buf->len; + } + else + mid_seg = TRUE; + + /* Get a new buffer and copy the data that can be sent in a PDU */ + p_xmit = l2c_fcr_clone_buf (p_buf, L2CAP_MIN_OFFSET + L2CAP_SDU_LEN_OFFSET, + max_pdu, p_ccb->ertm_info.fcr_tx_pool_id); + + if (p_xmit != NULL) + { + p_buf->event = p_ccb->local_cid; + p_xmit->event = p_ccb->local_cid; + + p_buf->len -= max_pdu; + p_buf->offset += max_pdu; + + /* copy PBF setting */ + p_xmit->layer_specific = p_buf->layer_specific; + } + else /* Should never happen if the application has configured buffers correctly */ + { + L2CAP_TRACE_ERROR ("L2CAP - cannot get buffer, for segmentation, pool: %u", p_ccb->ertm_info.fcr_tx_pool_id); + return (NULL); + } + } + else /* Use the original buffer if no segmentation, or the last segment */ + { + p_xmit = (BT_HDR *)GKI_dequeue (&p_ccb->xmit_hold_q); + + if (p_xmit->event != 0) + last_seg = TRUE; + + p_xmit->event = p_ccb->local_cid; + } + + /* Step back to add the L2CAP headers */ + p_xmit->offset -= (L2CAP_PKT_OVERHEAD + L2CAP_FCR_OVERHEAD); + p_xmit->len += L2CAP_PKT_OVERHEAD + L2CAP_FCR_OVERHEAD; + + if (first_seg) + { + p_xmit->offset -= L2CAP_SDU_LEN_OVERHEAD; + p_xmit->len += L2CAP_SDU_LEN_OVERHEAD; + } + + /* Set the pointer to the beginning of the data */ + p = (UINT8 *)(p_xmit + 1) + p_xmit->offset; + + /* Now the L2CAP header */ + + /* Note: if FCS has to be included then the length is recalculated later */ + UINT16_TO_STREAM (p, p_xmit->len - L2CAP_PKT_OVERHEAD); + + UINT16_TO_STREAM (p, p_ccb->remote_cid); + + if (first_seg) + { + /* Skip control word and add SDU length */ + p += 2; + UINT16_TO_STREAM (p, sdu_len); + + /* We will store the SAR type in layer-specific */ + /* layer_specific is shared with flushable flag(bits 0-1), don't clear it */ + p_xmit->layer_specific |= L2CAP_FCR_START_SDU; + + first_seg = FALSE; + } + else if (mid_seg) + p_xmit->layer_specific |= L2CAP_FCR_CONT_SDU; + else if (last_seg) + p_xmit->layer_specific |= L2CAP_FCR_END_SDU; + else + p_xmit->layer_specific |= L2CAP_FCR_UNSEG_SDU; + + prepare_I_frame (p_ccb, p_xmit, FALSE); + + if (p_ccb->peer_cfg.fcr.mode == L2CAP_FCR_ERTM_MODE) + { + BT_HDR *p_wack = l2c_fcr_clone_buf (p_xmit, HCI_DATA_PREAMBLE_SIZE, p_xmit->len, p_ccb->ertm_info.fcr_tx_pool_id); + + if (!p_wack) + { + L2CAP_TRACE_ERROR ("L2CAP - no buffer for xmit cloning, CID: 0x%04x Pool: %u Count: %u", + p_ccb->local_cid, p_ccb->ertm_info.fcr_tx_pool_id, GKI_poolfreecount(p_ccb->ertm_info.fcr_tx_pool_id)); + + /* We will not save the FCS in case we reconfigure and change options */ + if (p_ccb->bypass_fcs != L2CAP_BYPASS_FCS) + p_xmit->len -= L2CAP_FCS_LEN; + + /* Pretend we sent it and it got lost */ + GKI_enqueue (&p_ccb->fcrb.waiting_for_ack_q, p_xmit); + return (NULL); + } + else + { +#if (L2CAP_ERTM_STATS == TRUE) + /* set timestamp at the end of tx I-frame to get acking delay */ + p = ((UINT8 *) (p_wack+1)) + p_wack->offset + p_wack->len; + UINT32_TO_STREAM (p, GKI_get_os_tick_count()); +#endif + /* We will not save the FCS in case we reconfigure and change options */ + if (p_ccb->bypass_fcs != L2CAP_BYPASS_FCS) + p_wack->len -= L2CAP_FCS_LEN; + + p_wack->layer_specific = p_xmit->layer_specific; + GKI_enqueue (&p_ccb->fcrb.waiting_for_ack_q, p_wack); + } + +#if (L2CAP_ERTM_STATS == TRUE) + p_ccb->fcrb.ertm_pkt_counts[0]++; + p_ccb->fcrb.ertm_byte_counts[0] += (p_xmit->len - 8); +#endif + + } + + return (p_xmit); +} + + +/******************************************************************************* +** Configuration negotiation functions +** +** The following functions are used in negotiating channel modes during +** configuration +********************************************************************************/ + +/******************************************************************************* +** +** Function l2c_fcr_chk_chan_modes +** +** Description Validates and adjusts if necessary, the FCR options +** based on remote EXT features. +** +** Note: This assumes peer EXT Features have been received. +** Basic mode is used if FCR Options have not been received +** +** Returns UINT8 - nonzero if can continue, '0' if no compatible channels +** +*******************************************************************************/ +UINT8 l2c_fcr_chk_chan_modes (tL2C_CCB *p_ccb) +{ + assert(p_ccb != NULL); + + /* Remove nonbasic options that the peer does not support */ + if (!(p_ccb->p_lcb->peer_ext_fea & L2CAP_EXTFEA_ENH_RETRANS)) + p_ccb->ertm_info.allowed_modes &= ~L2CAP_FCR_CHAN_OPT_ERTM; + + if (!(p_ccb->p_lcb->peer_ext_fea & L2CAP_EXTFEA_STREAM_MODE)) + p_ccb->ertm_info.allowed_modes &= ~L2CAP_FCR_CHAN_OPT_STREAM; + + /* At least one type needs to be set (Basic, ERTM, STM) to continue */ + if (!p_ccb->ertm_info.allowed_modes) + { + L2CAP_TRACE_WARNING ("L2CAP - Peer does not support our desired channel types"); + } + + return (p_ccb->ertm_info.allowed_modes); +} + +/******************************************************************************* +** +** Function l2c_fcr_adj_our_req_options +** +** Description Validates and sets up the FCR options passed in from +** L2CA_ConfigReq based on remote device's features. +** +** Returns TRUE if no errors, Otherwise FALSE +** +*******************************************************************************/ +BOOLEAN l2c_fcr_adj_our_req_options (tL2C_CCB *p_ccb, tL2CAP_CFG_INFO *p_cfg) +{ + assert(p_ccb != NULL); + assert(p_cfg != NULL); + + tL2CAP_FCR_OPTS *p_fcr = &p_cfg->fcr; + + if (p_fcr->mode != p_ccb->ertm_info.preferred_mode) + { + L2CAP_TRACE_WARNING ("l2c_fcr_adj_our_req_options - preferred_mode (%d), does not match mode (%d)", + p_ccb->ertm_info.preferred_mode, p_fcr->mode); + + /* The preferred mode is passed in through tL2CAP_ERTM_INFO, so override this one */ + p_fcr->mode = p_ccb->ertm_info.preferred_mode; + } + + /* If upper layer did not request eRTM mode, BASIC must be used */ + if (p_ccb->ertm_info.allowed_modes == L2CAP_FCR_CHAN_OPT_BASIC) + { + if (p_cfg->fcr_present && p_fcr->mode != L2CAP_FCR_BASIC_MODE) + { + L2CAP_TRACE_WARNING ("l2c_fcr_adj_our_req_options (mode %d): ERROR: No FCR options set using BASIC mode", p_fcr->mode); + } + p_fcr->mode = L2CAP_FCR_BASIC_MODE; + } + + /* Process the FCR options if initial channel bring-up (not a reconfig request) + ** Determine initial channel mode to try based on our options and remote's features + */ + if (p_cfg->fcr_present && !(p_ccb->config_done & RECONFIG_FLAG)) + { + /* We need to have at least one mode type common with the peer */ + if (!l2c_fcr_chk_chan_modes(p_ccb)) + { + /* Two channels have incompatible supported types */ + l2cu_disconnect_chnl (p_ccb); + return (FALSE); + } + + /* Basic is the only common channel mode between the two devices */ + else if (p_ccb->ertm_info.allowed_modes == L2CAP_FCR_CHAN_OPT_BASIC) + { + /* We only want to try Basic, so bypass sending the FCR options entirely */ + p_cfg->fcr_present = FALSE; + p_cfg->fcs_present = FALSE; /* Illegal to use FCS option in basic mode */ + p_cfg->ext_flow_spec_present = FALSE; /* Illegal to use extended flow spec in basic mode */ + } + + /* We have at least one non-basic mode available + * Override mode from available mode options based on preference, if needed + */ + else + { + /* If peer does not support STREAMING, try ERTM */ + if (p_fcr->mode == L2CAP_FCR_STREAM_MODE && !(p_ccb->ertm_info.allowed_modes & L2CAP_FCR_CHAN_OPT_STREAM)) + { + L2CAP_TRACE_DEBUG ("L2C CFG: mode is STREAM, but peer does not support; Try ERTM"); + p_fcr->mode = L2CAP_FCR_ERTM_MODE; + } + + /* If peer does not support ERTM, try BASIC (will support this if made it here in the code) */ + if (p_fcr->mode == L2CAP_FCR_ERTM_MODE && !(p_ccb->ertm_info.allowed_modes & L2CAP_FCR_CHAN_OPT_ERTM)) + { + L2CAP_TRACE_DEBUG ("L2C CFG: mode is ERTM, but peer does not support; Try BASIC"); + p_fcr->mode = L2CAP_FCR_BASIC_MODE; + } + } + + if (p_fcr->mode != L2CAP_FCR_BASIC_MODE) + { + /* MTU must be smaller than buffer size */ + if ( (p_cfg->mtu_present) && (p_cfg->mtu > p_ccb->max_rx_mtu) ) + { + L2CAP_TRACE_WARNING ("L2CAP - MTU: %u larger than buf size: %u", p_cfg->mtu, p_ccb->max_rx_mtu); + return (FALSE); + } + + /* application want to use the default MPS */ + if (p_fcr->mps == L2CAP_DEFAULT_ERM_MPS) + { + p_fcr->mps = L2CAP_MPS_OVER_BR_EDR; + } + /* MPS must be less than MTU */ + else if (p_fcr->mps > p_ccb->max_rx_mtu) + { + L2CAP_TRACE_WARNING ("L2CAP - MPS %u invalid MTU: %u", p_fcr->mps, p_ccb->max_rx_mtu); + return (FALSE); + } + + /* We always initially read into the HCI buffer pool, so make sure it fits */ + if (p_fcr->mps > (L2CAP_MTU_SIZE - L2CAP_MAX_HEADER_FCS)) + p_fcr->mps = L2CAP_MTU_SIZE - L2CAP_MAX_HEADER_FCS; + } + else + { + p_cfg->fcs_present = FALSE; /* Illegal to use FCS option in basic mode */ + p_cfg->ext_flow_spec_present = FALSE; /* Illegal to use extended flow spec in basic mode */ + } + + p_ccb->our_cfg.fcr = *p_fcr; + } + else /* Not sure how to send a reconfiguration(??) should fcr be included? */ + { + p_ccb->our_cfg.fcr_present = FALSE; + } + + return (TRUE); +} + + +/******************************************************************************* +** +** Function l2c_fcr_adj_monitor_retran_timeout +** +** Description Overrides monitor/retrans timer value based on controller +** +** Returns None +** +*******************************************************************************/ +void l2c_fcr_adj_monitor_retran_timeout (tL2C_CCB *p_ccb) +{ + assert(p_ccb != NULL); + + /* adjust our monitor/retran timeout */ + if (p_ccb->out_cfg_fcr_present) + { + /* + ** if we requestd ERTM or accepted ERTM + ** We may accept ERTM even if we didn't request ERTM, in case of requesting STREAM + */ + if ((p_ccb->our_cfg.fcr.mode == L2CAP_FCR_ERTM_MODE) + ||(p_ccb->peer_cfg.fcr.mode == L2CAP_FCR_ERTM_MODE)) + { + /* upper layer setting is ignored */ + p_ccb->our_cfg.fcr.mon_tout = L2CAP_MIN_MONITOR_TOUT; + p_ccb->our_cfg.fcr.rtrans_tout = L2CAP_MIN_RETRANS_TOUT; + } + else + { + p_ccb->our_cfg.fcr.mon_tout = 0; + p_ccb->our_cfg.fcr.rtrans_tout = 0; + } + + L2CAP_TRACE_DEBUG ("l2c_fcr_adj_monitor_retran_timeout: mon_tout:%d, rtrans_tout:%d", + p_ccb->our_cfg.fcr.mon_tout, p_ccb->our_cfg.fcr.rtrans_tout); + } +} +/******************************************************************************* +** +** Function l2c_fcr_adj_our_rsp_options +** +** Description Overrides any neccesary FCR options passed in from +** L2CA_ConfigRsp based on our FCR options. +** Only makes adjustments if channel is in ERTM mode. +** +** Returns None +** +*******************************************************************************/ +void l2c_fcr_adj_our_rsp_options (tL2C_CCB *p_ccb, tL2CAP_CFG_INFO *p_cfg) +{ + assert(p_ccb != NULL); + assert(p_cfg != NULL); + + /* adjust our monitor/retran timeout */ + l2c_fcr_adj_monitor_retran_timeout(p_ccb); + + p_cfg->fcr_present = p_ccb->out_cfg_fcr_present; + + if (p_cfg->fcr_present) + { +// btla-specific ++ + /* Temporary - until a better algorithm is implemented */ + /* If peer's tx_wnd_sz requires too many buffers for us to support, then adjust it. For now, respond with our own tx_wnd_sz. */ + /* Note: peer is not guaranteed to obey our adjustment */ + if (p_ccb->peer_cfg.fcr.tx_win_sz > p_ccb->our_cfg.fcr.tx_win_sz) + { + L2CAP_TRACE_DEBUG ("%s: adjusting requested tx_win_sz from %i to %i", __FUNCTION__, p_ccb->peer_cfg.fcr.tx_win_sz, p_ccb->our_cfg.fcr.tx_win_sz); + p_ccb->peer_cfg.fcr.tx_win_sz = p_ccb->our_cfg.fcr.tx_win_sz; + } +// btla-specific -- + + p_cfg->fcr.mode = p_ccb->peer_cfg.fcr.mode; + p_cfg->fcr.tx_win_sz = p_ccb->peer_cfg.fcr.tx_win_sz; + p_cfg->fcr.max_transmit = p_ccb->peer_cfg.fcr.max_transmit; + p_cfg->fcr.mps = p_ccb->peer_cfg.fcr.mps; + p_cfg->fcr.rtrans_tout = p_ccb->our_cfg.fcr.rtrans_tout; + p_cfg->fcr.mon_tout = p_ccb->our_cfg.fcr.mon_tout; + } +} + +/******************************************************************************* +** +** Function l2c_fcr_renegotiate_chan +** +** Description Called upon unsuccessful peer response to config request. +** If the error is because of the channel mode, it will try +** to resend using another supported optional channel. +** +** Returns TRUE if resent configuration, False if channel matches or +** cannot match. +** +*******************************************************************************/ +BOOLEAN l2c_fcr_renegotiate_chan(tL2C_CCB *p_ccb, tL2CAP_CFG_INFO *p_cfg) +{ + assert(p_ccb != NULL); + assert(p_cfg != NULL); + + UINT8 peer_mode = p_ccb->our_cfg.fcr.mode; + BOOLEAN can_renegotiate; + + /* Skip if this is a reconfiguration from OPEN STATE or if FCR is not returned */ + if (!p_cfg->fcr_present || (p_ccb->config_done & RECONFIG_FLAG)) + return (FALSE); + + /* Only retry if there are more channel options to try */ + if (p_cfg->result == L2CAP_CFG_UNACCEPTABLE_PARAMS) + { + peer_mode = (p_cfg->fcr_present) ? p_cfg->fcr.mode : L2CAP_FCR_BASIC_MODE; + + if (p_ccb->our_cfg.fcr.mode != peer_mode) + { + + if ((--p_ccb->fcr_cfg_tries) == 0) + { + p_cfg->result = L2CAP_CFG_FAILED_NO_REASON; + L2CAP_TRACE_WARNING ("l2c_fcr_renegotiate_chan (Max retries exceeded)"); + } + + can_renegotiate = FALSE; + + /* Try another supported mode if available based on our last attempted channel */ + switch (p_ccb->our_cfg.fcr.mode) + { + /* Our Streaming mode request was unnacceptable; try ERTM or Basic */ + case L2CAP_FCR_STREAM_MODE: + /* Peer wants ERTM and we support it */ + if ( (peer_mode == L2CAP_FCR_ERTM_MODE) && (p_ccb->ertm_info.allowed_modes & L2CAP_FCR_CHAN_OPT_ERTM) ) + { + L2CAP_TRACE_DEBUG ("l2c_fcr_renegotiate_chan(Trying ERTM)"); + p_ccb->our_cfg.fcr.mode = L2CAP_FCR_ERTM_MODE; + can_renegotiate = TRUE; + } + else /* Falls through */ + + case L2CAP_FCR_ERTM_MODE: + { + /* We can try basic for any other peer mode if we support it */ + if (p_ccb->ertm_info.allowed_modes & L2CAP_FCR_CHAN_OPT_BASIC) + { + L2CAP_TRACE_DEBUG ("l2c_fcr_renegotiate_chan(Trying Basic)"); + can_renegotiate = TRUE; + p_ccb->our_cfg.fcr.mode = L2CAP_FCR_BASIC_MODE; + } + } + break; + + default: + /* All other scenarios cannot be renegotiated */ + break; + } + + if (can_renegotiate) + { + p_ccb->our_cfg.fcr_present = TRUE; + + if (p_ccb->our_cfg.fcr.mode == L2CAP_FCR_BASIC_MODE) + { + p_ccb->our_cfg.fcs_present = FALSE; + p_ccb->our_cfg.ext_flow_spec_present = FALSE; + + /* Basic Mode uses ACL Data Pool, make sure the MTU fits */ + if ( (p_cfg->mtu_present) && (p_cfg->mtu > L2CAP_MTU_SIZE) ) + { + L2CAP_TRACE_WARNING ("L2CAP - adjust MTU: %u too large", p_cfg->mtu); + p_cfg->mtu = L2CAP_MTU_SIZE; + } + } + + l2cu_process_our_cfg_req (p_ccb, &p_ccb->our_cfg); + l2cu_send_peer_config_req (p_ccb, &p_ccb->our_cfg); + btu_start_timer (&p_ccb->timer_entry, BTU_TTYPE_L2CAP_CHNL, L2CAP_CHNL_CFG_TIMEOUT); + return (TRUE); + } + } + } + + /* Disconnect if the channels do not match */ + if (p_ccb->our_cfg.fcr.mode != peer_mode) + { + L2CAP_TRACE_WARNING ("L2C CFG: Channels incompatible (local %d, peer %d)", + p_ccb->our_cfg.fcr.mode, peer_mode); + l2cu_disconnect_chnl (p_ccb); + } + + return (FALSE); +} + + +/******************************************************************************* +** +** Function l2c_fcr_process_peer_cfg_req +** +** Description This function is called to process the FCR options passed +** in the peer's configuration request. +** +** Returns UINT8 - L2CAP_PEER_CFG_OK, L2CAP_PEER_CFG_UNACCEPTABLE, +** or L2CAP_PEER_CFG_DISCONNECT. +** +*******************************************************************************/ +UINT8 l2c_fcr_process_peer_cfg_req(tL2C_CCB *p_ccb, tL2CAP_CFG_INFO *p_cfg) +{ + assert(p_ccb != NULL); + assert(p_cfg != NULL); + + UINT16 max_retrans_size; + UINT8 fcr_ok = L2CAP_PEER_CFG_OK; + + p_ccb->p_lcb->w4_info_rsp = FALSE; /* Handles T61x SonyEricsson Bug in Info Request */ + + L2CAP_TRACE_EVENT ("l2c_fcr_process_peer_cfg_req() CFG fcr_present:%d fcr.mode:%d CCB FCR mode:%d preferred: %u allowed:%u", + p_cfg->fcr_present, p_cfg->fcr.mode, p_ccb->our_cfg.fcr.mode, p_ccb->ertm_info.preferred_mode, + p_ccb->ertm_info.allowed_modes); + + /* If Peer wants basic, we are done (accept it or disconnect) */ + if (p_cfg->fcr.mode == L2CAP_FCR_BASIC_MODE) + { + /* If we do not allow basic, disconnect */ + if ( !(p_ccb->ertm_info.allowed_modes & L2CAP_FCR_CHAN_OPT_BASIC) ) + fcr_ok = L2CAP_PEER_CFG_DISCONNECT; + } + + /* Need to negotiate if our modes are not the same */ + else if (p_cfg->fcr.mode != p_ccb->ertm_info.preferred_mode) + { + /* If peer wants a mode that we don't support then retry our mode (ex. rtx/flc), OR + ** If we want ERTM and they wanted streaming retry our mode. + ** Note: If we have already determined they support our mode previously + ** from their EXF mask. + */ + if ( (((1 << p_cfg->fcr.mode) & L2CAP_FCR_CHAN_OPT_ALL_MASK) == 0) + || (p_ccb->ertm_info.preferred_mode == L2CAP_FCR_ERTM_MODE) ) + { + p_cfg->fcr.mode = p_ccb->our_cfg.fcr.mode; + p_cfg->fcr.tx_win_sz = p_ccb->our_cfg.fcr.tx_win_sz; + p_cfg->fcr.max_transmit = p_ccb->our_cfg.fcr.max_transmit; + fcr_ok = L2CAP_PEER_CFG_UNACCEPTABLE; + } + + /* If we wanted basic, then try to renegotiate it */ + else if (p_ccb->ertm_info.preferred_mode == L2CAP_FCR_BASIC_MODE) + { + p_cfg->fcr.mode = L2CAP_FCR_BASIC_MODE; + p_cfg->fcr.max_transmit = p_cfg->fcr.tx_win_sz = 0; + p_cfg->fcr.rtrans_tout = p_cfg->fcr.mon_tout = p_cfg->fcr.mps = 0; + p_ccb->our_cfg.fcr.rtrans_tout = p_ccb->our_cfg.fcr.mon_tout = p_ccb->our_cfg.fcr.mps = 0; + fcr_ok = L2CAP_PEER_CFG_UNACCEPTABLE; + } + + /* Only other valid case is if they want ERTM and we wanted STM which should be + accepted if we support it; otherwise the channel should be disconnected */ + else if ( (p_cfg->fcr.mode != L2CAP_FCR_ERTM_MODE) + || !(p_ccb->ertm_info.allowed_modes & L2CAP_FCR_CHAN_OPT_ERTM) ) + { + fcr_ok = L2CAP_PEER_CFG_DISCONNECT; + } + } + + /* Configuration for FCR channels so make any adjustments and fwd to upper layer */ + if (fcr_ok == L2CAP_PEER_CFG_OK) + { + /* by default don't need to send params in the response */ + p_ccb->out_cfg_fcr_present = FALSE; + + /* Make any needed adjustments for the response to the peer */ + if (p_cfg->fcr_present && p_cfg->fcr.mode != L2CAP_FCR_BASIC_MODE) + { + /* Peer desires to bypass FCS check, and streaming or ERTM mode */ + if (p_cfg->fcs_present) + { + p_ccb->peer_cfg.fcs = p_cfg->fcs; + p_ccb->peer_cfg_bits |= L2CAP_CH_CFG_MASK_FCS; + if( p_cfg->fcs == L2CAP_CFG_FCS_BYPASS) + p_ccb->bypass_fcs |= L2CAP_CFG_FCS_PEER; + } + + max_retrans_size = GKI_get_pool_bufsize (p_ccb->ertm_info.fcr_tx_pool_id) - sizeof(BT_HDR) + - L2CAP_MIN_OFFSET - L2CAP_SDU_LEN_OFFSET - L2CAP_FCS_LEN; + + /* Ensure the MPS is not bigger than the MTU */ + if ( (p_cfg->fcr.mps == 0) || (p_cfg->fcr.mps > p_ccb->peer_cfg.mtu) ) + { + p_cfg->fcr.mps = p_ccb->peer_cfg.mtu; + p_ccb->out_cfg_fcr_present = TRUE; + } + + /* Ensure the MPS is not bigger than our retransmission buffer */ + if (p_cfg->fcr.mps > max_retrans_size) + { + L2CAP_TRACE_DEBUG("CFG: Overriding MPS to %d (orig %d)", max_retrans_size, p_cfg->fcr.mps); + + p_cfg->fcr.mps = max_retrans_size; + p_ccb->out_cfg_fcr_present = TRUE; + } + + if (p_cfg->fcr.mode == L2CAP_FCR_ERTM_MODE || p_cfg->fcr.mode == L2CAP_FCR_STREAM_MODE) + { + /* Always respond with FCR ERTM parameters */ + p_ccb->out_cfg_fcr_present = TRUE; + } + } + + /* Everything ok, so save the peer's adjusted fcr options */ + p_ccb->peer_cfg.fcr = p_cfg->fcr; + + if (p_cfg->fcr_present) + p_ccb->peer_cfg_bits |= L2CAP_CH_CFG_MASK_FCR; + } + else if (fcr_ok == L2CAP_PEER_CFG_UNACCEPTABLE) + { + /* Allow peer only one retry for mode */ + if (p_ccb->peer_cfg_already_rejected) + fcr_ok = L2CAP_PEER_CFG_DISCONNECT; + else + p_ccb->peer_cfg_already_rejected = TRUE; + } + + return (fcr_ok); +} + +#if (L2CAP_ERTM_STATS == TRUE) +/******************************************************************************* +** +** Function l2c_fcr_collect_ack_delay +** +** Description collect throughput, delay, queue size of waiting ack +** +** Parameters +** tL2C_CCB +** +** Returns void +** +*******************************************************************************/ +static void l2c_fcr_collect_ack_delay (tL2C_CCB *p_ccb, UINT8 num_bufs_acked) +{ + UINT32 index; + BT_HDR *p_buf; + UINT8 *p; + UINT32 timestamp, delay; + UINT8 xx; + UINT8 str[120]; + + index = p_ccb->fcrb.ack_delay_avg_index; + + /* update sum, max and min of waiting for ack queue size */ + p_ccb->fcrb.ack_q_count_avg[index] += p_ccb->fcrb.waiting_for_ack_q.count; + + if ( p_ccb->fcrb.waiting_for_ack_q.count > p_ccb->fcrb.ack_q_count_max[index] ) + p_ccb->fcrb.ack_q_count_max[index] = p_ccb->fcrb.waiting_for_ack_q.count; + + if ( p_ccb->fcrb.waiting_for_ack_q.count < p_ccb->fcrb.ack_q_count_min[index] ) + p_ccb->fcrb.ack_q_count_min[index] = p_ccb->fcrb.waiting_for_ack_q.count; + + /* update sum, max and min of round trip delay of acking */ + p_buf = (BT_HDR *)(p_ccb->fcrb.waiting_for_ack_q.p_first); + for (xx = 0; (xx < num_bufs_acked)&&(p_buf); xx++) + { + /* adding up length of acked I-frames to get throughput */ + p_ccb->fcrb.throughput[index] += p_buf->len - 8; + + if ( xx == num_bufs_acked - 1 ) + { + /* get timestamp from tx I-frame that receiver is acking */ + p = ((UINT8 *) (p_buf+1)) + p_buf->offset + p_buf->len; + if (p_ccb->bypass_fcs != L2CAP_BYPASS_FCS) + { + p += L2CAP_FCS_LEN; + } + + STREAM_TO_UINT32 (timestamp, p); + delay = GKI_get_os_tick_count() - timestamp; + + p_ccb->fcrb.ack_delay_avg[index] += delay; + if ( delay > p_ccb->fcrb.ack_delay_max[index] ) + p_ccb->fcrb.ack_delay_max[index] = delay; + if ( delay < p_ccb->fcrb.ack_delay_min[index] ) + p_ccb->fcrb.ack_delay_min[index] = delay; + } + + p_buf = GKI_getnext(p_buf); + } + + p_ccb->fcrb.ack_delay_avg_count++; + + /* calculate average and initialize next avg, min and max */ + if (p_ccb->fcrb.ack_delay_avg_count > L2CAP_ERTM_STATS_AVG_NUM_SAMPLES) + { + p_ccb->fcrb.ack_delay_avg_count = 0; + + p_ccb->fcrb.ack_q_count_avg[index] /= L2CAP_ERTM_STATS_AVG_NUM_SAMPLES; + p_ccb->fcrb.ack_delay_avg[index] /= L2CAP_ERTM_STATS_AVG_NUM_SAMPLES; + + /* calculate throughput */ + timestamp = GKI_get_os_tick_count(); + if (timestamp - p_ccb->fcrb.throughput_start > 0 ) + p_ccb->fcrb.throughput[index] /= (timestamp - p_ccb->fcrb.throughput_start); + + p_ccb->fcrb.throughput_start = timestamp; + + sprintf(str, "[%02u] throughput: %5u, ack_delay avg:%3u, min:%3u, max:%3u, ack_q_count avg:%3u, min:%3u, max:%3u", + index, p_ccb->fcrb.throughput[index], + p_ccb->fcrb.ack_delay_avg[index], p_ccb->fcrb.ack_delay_min[index], p_ccb->fcrb.ack_delay_max[index], + p_ccb->fcrb.ack_q_count_avg[index], p_ccb->fcrb.ack_q_count_min[index], p_ccb->fcrb.ack_q_count_max[index] ); + + BT_TRACE(TRACE_CTRL_GENERAL | TRACE_LAYER_GKI | TRACE_ORG_GKI , TRACE_TYPE_GENERIC, "%s", str); + + index = (index + 1) % L2CAP_ERTM_STATS_NUM_AVG; + p_ccb->fcrb.ack_delay_avg_index = index; + + p_ccb->fcrb.ack_q_count_max[index] = 0; + p_ccb->fcrb.ack_q_count_min[index] = 0xFFFFFFFF; + p_ccb->fcrb.ack_q_count_avg[index] = 0; + + + p_ccb->fcrb.ack_delay_max[index] = 0; + p_ccb->fcrb.ack_delay_min[index] = 0xFFFFFFFF; + p_ccb->fcrb.ack_delay_avg[index] = 0; + + p_ccb->fcrb.throughput[index] = 0; + } +} +#endif diff --git a/components/bt/bluedroid/stack/l2cap/l2c_link.c b/components/bt/bluedroid/stack/l2cap/l2c_link.c new file mode 100755 index 0000000000..40696ad202 --- /dev/null +++ b/components/bt/bluedroid/stack/l2cap/l2c_link.c @@ -0,0 +1,1592 @@ +/****************************************************************************** + * + * Copyright (C) 1999-2012 Broadcom Corporation + * + * 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 functions relating to link management. A "link" + * is a connection between this device and another device. Only ACL links + * are managed. + * + ******************************************************************************/ + +#include +#include +//#include + +#include "controller.h" +//#include "btcore/include/counter.h" +#include "gki.h" +#include "bt_types.h" +//#include "bt_utils.h" +#include "hcimsgs.h" +#include "l2cdefs.h" +#include "l2c_int.h" +#include "l2c_api.h" +#include "btu.h" +#include "btm_api.h" +#include "btm_int.h" + +static BOOLEAN l2c_link_send_to_lower (tL2C_LCB *p_lcb, BT_HDR *p_buf); + +/******************************************************************************* +** +** Function l2c_link_hci_conn_req +** +** Description This function is called when an HCI Connection Request +** event is received. +** +** Returns TRUE, if accept conn +** +*******************************************************************************/ +BOOLEAN l2c_link_hci_conn_req (BD_ADDR bd_addr) +{ + tL2C_LCB *p_lcb; + tL2C_LCB *p_lcb_cur; + int xx; + BOOLEAN no_links; + + /* See if we have a link control block for the remote device */ + p_lcb = l2cu_find_lcb_by_bd_addr (bd_addr, BT_TRANSPORT_BR_EDR); + + /* If we don't have one, create one and accept the connection. */ + if (!p_lcb) + { + p_lcb = l2cu_allocate_lcb (bd_addr, FALSE, BT_TRANSPORT_BR_EDR); + if (!p_lcb) + { + btsnd_hcic_reject_conn (bd_addr, HCI_ERR_HOST_REJECT_RESOURCES); + L2CAP_TRACE_ERROR ("L2CAP failed to allocate LCB"); + return FALSE; + } + + no_links = TRUE; + + /* If we already have connection, accept as a master */ + for (xx = 0, p_lcb_cur = &l2cb.lcb_pool[0]; xx < MAX_L2CAP_LINKS; xx++, p_lcb_cur++) + { + if (p_lcb_cur == p_lcb) + continue; + + if (p_lcb_cur->in_use) + { + no_links = FALSE; + p_lcb->link_role = HCI_ROLE_MASTER; + break; + } + } + + if (no_links) + { + if (!btm_dev_support_switch (bd_addr)) + p_lcb->link_role = HCI_ROLE_SLAVE; + else + p_lcb->link_role = l2cu_get_conn_role(p_lcb); + } + + //counter_add("l2cap.conn.accept", 1); + + /* Tell the other side we accept the connection */ + btsnd_hcic_accept_conn (bd_addr, p_lcb->link_role); + + p_lcb->link_state = LST_CONNECTING; + + /* Start a timer waiting for connect complete */ + btu_start_timer (&p_lcb->timer_entry, BTU_TTYPE_L2CAP_LINK, L2CAP_LINK_CONNECT_TOUT); + return (TRUE); + } + + /* We already had a link control block to the guy. Check what state it is in */ + if ((p_lcb->link_state == LST_CONNECTING) || (p_lcb->link_state == LST_CONNECT_HOLDING)) + { + /* Connection collision. Accept the connection anyways. */ + + if (!btm_dev_support_switch (bd_addr)) + p_lcb->link_role = HCI_ROLE_SLAVE; + else + p_lcb->link_role = l2cu_get_conn_role(p_lcb); + + //counter_add("l2cap.conn.accept", 1); + btsnd_hcic_accept_conn (bd_addr, p_lcb->link_role); + + p_lcb->link_state = LST_CONNECTING; + return (TRUE); + } + else if (p_lcb->link_state == LST_DISCONNECTING) + { + /* In disconnecting state, reject the connection. */ + //counter_add("l2cap.conn.reject.disconn", 1); + btsnd_hcic_reject_conn (bd_addr, HCI_ERR_HOST_REJECT_DEVICE); + } + else + { + L2CAP_TRACE_ERROR("L2CAP got conn_req while connected (state:%d). Reject it", + p_lcb->link_state); + /* Reject the connection with ACL Connection Already exist reason */ + //counter_add("l2cap.conn.reject.exists", 1); + btsnd_hcic_reject_conn (bd_addr, HCI_ERR_CONNECTION_EXISTS); + } + return (FALSE); +} + +/******************************************************************************* +** +** Function l2c_link_hci_conn_comp +** +** Description This function is called when an HCI Connection Complete +** event is received. +** +** Returns void +** +*******************************************************************************/ +BOOLEAN l2c_link_hci_conn_comp (UINT8 status, UINT16 handle, BD_ADDR p_bda) +{ + tL2C_CONN_INFO ci; + tL2C_LCB *p_lcb; + tL2C_CCB *p_ccb; + tBTM_SEC_DEV_REC *p_dev_info = NULL; + + btm_acl_update_busy_level (BTM_BLI_PAGE_DONE_EVT); + + /* Save the parameters */ + ci.status = status; + memcpy (ci.bd_addr, p_bda, BD_ADDR_LEN); + + /* See if we have a link control block for the remote device */ + p_lcb = l2cu_find_lcb_by_bd_addr (ci.bd_addr, BT_TRANSPORT_BR_EDR); + + /* If we don't have one, this is an error */ + if (!p_lcb) + { + L2CAP_TRACE_WARNING ("L2CAP got conn_comp for unknown BD_ADDR"); + return (FALSE); + } + + if (p_lcb->link_state != LST_CONNECTING) + { + L2CAP_TRACE_ERROR ("L2CAP got conn_comp in bad state: %d status: 0x%d", p_lcb->link_state, status); + + if (status != HCI_SUCCESS) + l2c_link_hci_disc_comp (p_lcb->handle, status); + + return (FALSE); + } + + /* Save the handle */ + p_lcb->handle = handle; + + if (ci.status == HCI_SUCCESS) + { + /* Connected OK. Change state to connected */ + p_lcb->link_state = LST_CONNECTED; + //counter_add("l2cap.conn.ok", 1); + + /* Get the peer information if the l2cap flow-control/rtrans is supported */ + l2cu_send_peer_info_req (p_lcb, L2CAP_EXTENDED_FEATURES_INFO_TYPE); + + /* Tell BTM Acl management about the link */ + if ((p_dev_info = btm_find_dev (p_bda)) != NULL) + btm_acl_created (ci.bd_addr, p_dev_info->dev_class, + p_dev_info->sec_bd_name, handle, + p_lcb->link_role, BT_TRANSPORT_BR_EDR); + else + btm_acl_created (ci.bd_addr, NULL, NULL, handle, p_lcb->link_role, BT_TRANSPORT_BR_EDR); + + BTM_SetLinkSuperTout (ci.bd_addr, btm_cb.btm_def_link_super_tout); + + /* If dedicated bonding do not process any further */ + if (p_lcb->is_bonding) + { + if (l2cu_start_post_bond_timer(handle)) + return (TRUE); + } + + /* Update the timeouts in the hold queue */ + l2c_process_held_packets(FALSE); + + btu_stop_timer (&p_lcb->timer_entry); + + /* For all channels, send the event through their FSMs */ + for (p_ccb = p_lcb->ccb_queue.p_first_ccb; p_ccb; p_ccb = p_ccb->p_next_ccb) + { + l2c_csm_execute (p_ccb, L2CEVT_LP_CONNECT_CFM, &ci); + } + + if (p_lcb->p_echo_rsp_cb) + { + l2cu_send_peer_echo_req (p_lcb, NULL, 0); + btu_start_timer (&p_lcb->timer_entry, BTU_TTYPE_L2CAP_LINK, L2CAP_ECHO_RSP_TOUT); + } + else if (!p_lcb->ccb_queue.p_first_ccb) + { + btu_start_timer (&p_lcb->timer_entry, BTU_TTYPE_L2CAP_LINK, L2CAP_LINK_STARTUP_TOUT); + } + } + /* Max number of acl connections. */ + /* If there's an lcb disconnecting set this one to holding */ + else if ((ci.status == HCI_ERR_MAX_NUM_OF_CONNECTIONS) && l2cu_lcb_disconnecting()) + { + p_lcb->link_state = LST_CONNECT_HOLDING; + p_lcb->handle = HCI_INVALID_HANDLE; + } + else + { + /* Just in case app decides to try again in the callback context */ + p_lcb->link_state = LST_DISCONNECTING; + + /* Connection failed. For all channels, send the event through */ + /* their FSMs. The CCBs should remove themselves from the LCB */ + for (p_ccb = p_lcb->ccb_queue.p_first_ccb; p_ccb; ) + { + tL2C_CCB *pn = p_ccb->p_next_ccb; + + l2c_csm_execute (p_ccb, L2CEVT_LP_CONNECT_CFM_NEG, &ci); + + p_ccb = pn; + } + + p_lcb->disc_reason = status; + /* Release the LCB */ + if (p_lcb->ccb_queue.p_first_ccb == NULL) + l2cu_release_lcb (p_lcb); + else /* there are any CCBs remaining */ + { + if (ci.status == HCI_ERR_CONNECTION_EXISTS) + { + /* we are in collision situation, wait for connecttion request from controller */ + p_lcb->link_state = LST_CONNECTING; + } + else + { + l2cu_create_conn(p_lcb, BT_TRANSPORT_BR_EDR); + } + } + } + return (TRUE); +} + + +/******************************************************************************* +** +** Function l2c_link_sec_comp +** +** Description This function is called when required security procedures +** are completed. +** +** Returns void +** +*******************************************************************************/ +void l2c_link_sec_comp (BD_ADDR p_bda, tBT_TRANSPORT transport, void *p_ref_data, UINT8 status) +{ + tL2C_CONN_INFO ci; + tL2C_LCB *p_lcb; + tL2C_CCB *p_ccb; + tL2C_CCB *p_next_ccb; + UINT8 event; + + UNUSED(transport); + + L2CAP_TRACE_DEBUG ("l2c_link_sec_comp: %d, 0x%x", status, p_ref_data); + + if (status == BTM_SUCCESS_NO_SECURITY) + status = BTM_SUCCESS; + + /* Save the parameters */ + ci.status = status; + memcpy (ci.bd_addr, p_bda, BD_ADDR_LEN); + + p_lcb = l2cu_find_lcb_by_bd_addr (p_bda, BT_TRANSPORT_BR_EDR); + + /* If we don't have one, this is an error */ + if (!p_lcb) + { + L2CAP_TRACE_WARNING ("L2CAP got sec_comp for unknown BD_ADDR"); + return; + } + + /* Match p_ccb with p_ref_data returned by sec manager */ + for (p_ccb = p_lcb->ccb_queue.p_first_ccb; p_ccb; p_ccb = p_next_ccb) + { + p_next_ccb = p_ccb->p_next_ccb; + + if (p_ccb == p_ref_data) + { + switch(status) + { + case BTM_SUCCESS: + L2CAP_TRACE_DEBUG ("ccb timer ticks: %u", p_ccb->timer_entry.ticks); + event = L2CEVT_SEC_COMP; + break; + + case BTM_DELAY_CHECK: + /* start a timer - encryption change not received before L2CAP connect req */ + btu_start_timer (&p_ccb->timer_entry, BTU_TTYPE_L2CAP_CHNL, L2CAP_DELAY_CHECK_SM4); + return; + + default: + event = L2CEVT_SEC_COMP_NEG; + } + l2c_csm_execute (p_ccb, event, &ci); + break; + } + } +} + + +/******************************************************************************* +** +** Function l2c_link_hci_disc_comp +** +** Description This function is called when an HCI Disconnect Complete +** event is received. +** +** Returns TRUE if the link is known about, else FALSE +** +*******************************************************************************/ +BOOLEAN l2c_link_hci_disc_comp (UINT16 handle, UINT8 reason) +{ + tL2C_LCB *p_lcb; + tL2C_CCB *p_ccb; + BOOLEAN status = TRUE; + BOOLEAN lcb_is_free = TRUE; + tBT_TRANSPORT transport = BT_TRANSPORT_BR_EDR; + + /* See if we have a link control block for the connection */ + p_lcb = l2cu_find_lcb_by_handle (handle); + + /* If we don't have one, maybe an SCO link. Send to MM */ + if (!p_lcb) + { + status = FALSE; + } + else + { + /* There can be a case when we rejected PIN code authentication */ + /* otherwise save a new reason */ + if (btm_cb.acl_disc_reason != HCI_ERR_HOST_REJECT_SECURITY) + btm_cb.acl_disc_reason = reason; + + p_lcb->disc_reason = btm_cb.acl_disc_reason; + + /* Just in case app decides to try again in the callback context */ + p_lcb->link_state = LST_DISCONNECTING; + +#if (BLE_INCLUDED == TRUE) + /* Check for BLE and handle that differently */ + if (p_lcb->transport == BT_TRANSPORT_LE) + btm_ble_update_link_topology_mask(p_lcb->link_role, FALSE); +#endif + /* Link is disconnected. For all channels, send the event through */ + /* their FSMs. The CCBs should remove themselves from the LCB */ + for (p_ccb = p_lcb->ccb_queue.p_first_ccb; p_ccb; ) + { + tL2C_CCB *pn = p_ccb->p_next_ccb; + + /* Keep connect pending control block (if exists) + * Possible Race condition when a reconnect occurs + * on the channel during a disconnect of link. This + * ccb will be automatically retried after link disconnect + * arrives + */ + if (p_ccb != p_lcb->p_pending_ccb) + { + l2c_csm_execute (p_ccb, L2CEVT_LP_DISCONNECT_IND, &reason); + } + p_ccb = pn; + } + +#if (BTM_SCO_INCLUDED == TRUE) +#if (BLE_INCLUDED == TRUE) + if (p_lcb->transport == BT_TRANSPORT_BR_EDR) +#endif + /* Tell SCO management to drop any SCOs on this ACL */ + btm_sco_acl_removed (p_lcb->remote_bd_addr); +#endif + + /* If waiting for disconnect and reconnect is pending start the reconnect now + race condition where layer above issued connect request on link that was + disconnecting + */ + if (p_lcb->ccb_queue.p_first_ccb != NULL || p_lcb->p_pending_ccb) + { + L2CAP_TRACE_DEBUG("l2c_link_hci_disc_comp: Restarting pending ACL request"); + transport = p_lcb->transport; +#if BLE_INCLUDED == TRUE + /* for LE link, always drop and re-open to ensure to get LE remote feature */ + if (p_lcb->transport == BT_TRANSPORT_LE) + { + l2cb.is_ble_connecting = FALSE; + btm_acl_removed (p_lcb->remote_bd_addr, p_lcb->transport); + /* Release any held buffers */ + BT_HDR *p_buf; + while (!list_is_empty(p_lcb->link_xmit_data_q)) + { + p_buf = list_front(p_lcb->link_xmit_data_q); + list_remove(p_lcb->link_xmit_data_q, p_buf); + GKI_freebuf(p_buf); + } + } + else +#endif + { + #if (L2CAP_NUM_FIXED_CHNLS > 0) + /* If we are going to re-use the LCB without dropping it, release all fixed channels + here */ + int xx; + for (xx = 0; xx < L2CAP_NUM_FIXED_CHNLS; xx++) + { + if (p_lcb->p_fixed_ccbs[xx] && p_lcb->p_fixed_ccbs[xx] != p_lcb->p_pending_ccb) + { +#if BLE_INCLUDED == TRUE + (*l2cb.fixed_reg[xx].pL2CA_FixedConn_Cb)(xx + L2CAP_FIRST_FIXED_CHNL, + p_lcb->remote_bd_addr, FALSE, p_lcb->disc_reason, p_lcb->transport); +#else + (*l2cb.fixed_reg[xx].pL2CA_FixedConn_Cb)(xx + L2CAP_FIRST_FIXED_CHNL, + p_lcb->remote_bd_addr, FALSE, p_lcb->disc_reason, BT_TRANSPORT_BR_EDR); +#endif + l2cu_release_ccb (p_lcb->p_fixed_ccbs[xx]); + + p_lcb->p_fixed_ccbs[xx] = NULL; + } + } +#endif + } + if (l2cu_create_conn(p_lcb, transport)) + lcb_is_free = FALSE; /* still using this lcb */ + } + + p_lcb->p_pending_ccb = NULL; + + /* Release the LCB */ + if (lcb_is_free) + l2cu_release_lcb (p_lcb); + } + + /* Now that we have a free acl connection, see if any lcbs are pending */ + if (lcb_is_free && ((p_lcb = l2cu_find_lcb_by_state(LST_CONNECT_HOLDING)) != NULL)) + { + /* we found one-- create a connection */ + l2cu_create_conn(p_lcb, BT_TRANSPORT_BR_EDR); + } + + return status; +} + + +/******************************************************************************* +** +** Function l2c_link_hci_qos_violation +** +** Description This function is called when an HCI QOS Violation +** event is received. +** +** Returns TRUE if the link is known about, else FALSE +** +*******************************************************************************/ +BOOLEAN l2c_link_hci_qos_violation (UINT16 handle) +{ + tL2C_LCB *p_lcb; + tL2C_CCB *p_ccb; + + /* See if we have a link control block for the connection */ + p_lcb = l2cu_find_lcb_by_handle (handle); + + /* If we don't have one, maybe an SCO link. */ + if (!p_lcb) + return (FALSE); + + /* For all channels, tell the upper layer about it */ + for (p_ccb = p_lcb->ccb_queue.p_first_ccb; p_ccb; p_ccb = p_ccb->p_next_ccb) + { + if (p_ccb->p_rcb->api.pL2CA_QoSViolationInd_Cb) + l2c_csm_execute (p_ccb, L2CEVT_LP_QOS_VIOLATION_IND, NULL); + } + + return (TRUE); +} + + + +/******************************************************************************* +** +** Function l2c_link_timeout +** +** Description This function is called when a link timer expires +** +** Returns void +** +*******************************************************************************/ +void l2c_link_timeout (tL2C_LCB *p_lcb) +{ + tL2C_CCB *p_ccb; + UINT16 timeout; + tBTM_STATUS rc; + + L2CAP_TRACE_EVENT ("L2CAP - l2c_link_timeout() link state %d first CCB %p is_bonding:%d", + p_lcb->link_state, p_lcb->ccb_queue.p_first_ccb, p_lcb->is_bonding); + + /* If link was connecting or disconnecting, clear all channels and drop the LCB */ + if ((p_lcb->link_state == LST_CONNECTING_WAIT_SWITCH) || + (p_lcb->link_state == LST_CONNECTING) || + (p_lcb->link_state == LST_CONNECT_HOLDING) || + (p_lcb->link_state == LST_DISCONNECTING)) + { + p_lcb->p_pending_ccb = NULL; + + /* For all channels, send a disconnect indication event through */ + /* their FSMs. The CCBs should remove themselves from the LCB */ + for (p_ccb = p_lcb->ccb_queue.p_first_ccb; p_ccb; ) + { + tL2C_CCB *pn = p_ccb->p_next_ccb; + + l2c_csm_execute (p_ccb, L2CEVT_LP_DISCONNECT_IND, NULL); + + p_ccb = pn; + } +#if (BLE_INCLUDED == TRUE) + if (p_lcb->link_state == LST_CONNECTING && + l2cb.is_ble_connecting == TRUE) + { + L2CA_CancelBleConnectReq(l2cb.ble_connecting_bda); + } +#endif + /* Release the LCB */ + l2cu_release_lcb (p_lcb); + } + + /* If link is connected, check for inactivity timeout */ + if (p_lcb->link_state == LST_CONNECTED) + { + /* Check for ping outstanding */ + if (p_lcb->p_echo_rsp_cb) + { + tL2CA_ECHO_RSP_CB *p_cb = p_lcb->p_echo_rsp_cb; + + /* Zero out the callback in case app immediately calls us again */ + p_lcb->p_echo_rsp_cb = NULL; + + (*p_cb) (L2CAP_PING_RESULT_NO_RESP); + + L2CAP_TRACE_WARNING ("L2CAP - ping timeout"); + + /* For all channels, send a disconnect indication event through */ + /* their FSMs. The CCBs should remove themselves from the LCB */ + for (p_ccb = p_lcb->ccb_queue.p_first_ccb; p_ccb; ) + { + tL2C_CCB *pn = p_ccb->p_next_ccb; + + l2c_csm_execute (p_ccb, L2CEVT_LP_DISCONNECT_IND, NULL); + + p_ccb = pn; + } + } + + /* If no channels in use, drop the link. */ + if (!p_lcb->ccb_queue.p_first_ccb) + { + rc = btm_sec_disconnect (p_lcb->handle, HCI_ERR_PEER_USER); + + if (rc == BTM_CMD_STORED) + { + /* Security Manager will take care of disconnecting, state will be updated at that time */ + timeout = 0xFFFF; + } + else if (rc == BTM_CMD_STARTED) + { + p_lcb->link_state = LST_DISCONNECTING; + timeout = L2CAP_LINK_DISCONNECT_TOUT; + } + else if (rc == BTM_SUCCESS) + { + l2cu_process_fixed_disc_cback(p_lcb); + /* BTM SEC will make sure that link is release (probably after pairing is done) */ + p_lcb->link_state = LST_DISCONNECTING; + timeout = 0xFFFF; + } + else if (rc == BTM_BUSY) + { + /* BTM is still executing security process. Let lcb stay as connected */ + timeout = 0xFFFF; + } + else if ((p_lcb->is_bonding) + && (btsnd_hcic_disconnect (p_lcb->handle, HCI_ERR_PEER_USER))) + { + l2cu_process_fixed_disc_cback(p_lcb); + p_lcb->link_state = LST_DISCONNECTING; + timeout = L2CAP_LINK_DISCONNECT_TOUT; + } + else + { + /* probably no buffer to send disconnect */ + timeout = BT_1SEC_TIMEOUT; + } + + if (timeout != 0xFFFF) + { + btu_start_timer (&p_lcb->timer_entry, BTU_TTYPE_L2CAP_LINK, timeout); + } + } + else + { + /* Check in case we were flow controlled */ + l2c_link_check_send_pkts (p_lcb, NULL, NULL); + } + } +} + +/******************************************************************************* +** +** Function l2c_info_timeout +** +** Description This function is called when an info request times out +** +** Returns void +** +*******************************************************************************/ +void l2c_info_timeout (tL2C_LCB *p_lcb) +{ + tL2C_CCB *p_ccb; + tL2C_CONN_INFO ci; + + /* If we timed out waiting for info response, just continue using basic if allowed */ + if (p_lcb->w4_info_rsp) + { + /* If waiting for security complete, restart the info response timer */ + for (p_ccb = p_lcb->ccb_queue.p_first_ccb; p_ccb; p_ccb = p_ccb->p_next_ccb) + { + if ( (p_ccb->chnl_state == CST_ORIG_W4_SEC_COMP) || (p_ccb->chnl_state == CST_TERM_W4_SEC_COMP) ) + { + btu_start_timer (&p_lcb->info_timer_entry, BTU_TTYPE_L2CAP_INFO, L2CAP_WAIT_INFO_RSP_TOUT); + return; + } + } + + p_lcb->w4_info_rsp = FALSE; + + /* If link is in process of being brought up */ + if ((p_lcb->link_state != LST_DISCONNECTED) && + (p_lcb->link_state != LST_DISCONNECTING)) + { + /* Notify active channels that peer info is finished */ + if (p_lcb->ccb_queue.p_first_ccb) + { + ci.status = HCI_SUCCESS; + memcpy (ci.bd_addr, p_lcb->remote_bd_addr, sizeof(BD_ADDR)); + + for (p_ccb = p_lcb->ccb_queue.p_first_ccb; p_ccb; p_ccb = p_ccb->p_next_ccb) + { + l2c_csm_execute (p_ccb, L2CEVT_L2CAP_INFO_RSP, &ci); + } + } + } + } +} + +/******************************************************************************* +** +** Function l2c_link_adjust_allocation +** +** Description This function is called when a link is created or removed +** to calculate the amount of packets each link may send to +** the HCI without an ack coming back. +** +** Currently, this is a simple allocation, dividing the +** number of Controller Packets by the number of links. In +** the future, QOS configuration should be examined. +** +** Returns void +** +*******************************************************************************/ +void l2c_link_adjust_allocation (void) +{ + UINT16 qq, yy, qq_remainder; + tL2C_LCB *p_lcb; + UINT16 hi_quota, low_quota; + UINT16 num_lowpri_links = 0; + UINT16 num_hipri_links = 0; + UINT16 controller_xmit_quota = l2cb.num_lm_acl_bufs; + UINT16 high_pri_link_quota = L2CAP_HIGH_PRI_MIN_XMIT_QUOTA_A; + + /* If no links active, reset buffer quotas and controller buffers */ + if (l2cb.num_links_active == 0) + { + l2cb.controller_xmit_window = l2cb.num_lm_acl_bufs; + l2cb.round_robin_quota = l2cb.round_robin_unacked = 0; + return; + } + + /* First, count the links */ + for (yy = 0, p_lcb = &l2cb.lcb_pool[0]; yy < MAX_L2CAP_LINKS; yy++, p_lcb++) + { + if (p_lcb->in_use) + { + if (p_lcb->acl_priority == L2CAP_PRIORITY_HIGH) + num_hipri_links++; + else + num_lowpri_links++; + } + } + + /* now adjust high priority link quota */ + low_quota = num_lowpri_links ? 1 : 0; + while ( (num_hipri_links * high_pri_link_quota + low_quota) > controller_xmit_quota ) + high_pri_link_quota--; + + /* Work out the xmit quota and buffer quota high and low priorities */ + hi_quota = num_hipri_links * high_pri_link_quota; + low_quota = (hi_quota < controller_xmit_quota) ? controller_xmit_quota - hi_quota : 1; + + /* Work out and save the HCI xmit quota for each low priority link */ + + /* If each low priority link cannot have at least one buffer */ + if (num_lowpri_links > low_quota) + { + l2cb.round_robin_quota = low_quota; + qq = qq_remainder = 1; + } + /* If each low priority link can have at least one buffer */ + else if (num_lowpri_links > 0) + { + l2cb.round_robin_quota = 0; + l2cb.round_robin_unacked = 0; + qq = low_quota / num_lowpri_links; + qq_remainder = low_quota % num_lowpri_links; + } + /* If no low priority link */ + else + { + l2cb.round_robin_quota = 0; + l2cb.round_robin_unacked = 0; + qq = qq_remainder = 1; + } + + L2CAP_TRACE_EVENT ("l2c_link_adjust_allocation num_hipri: %u num_lowpri: %u low_quota: %u round_robin_quota: %u qq: %u", + num_hipri_links, num_lowpri_links, low_quota, + l2cb.round_robin_quota, qq); + + /* Now, assign the quotas to each link */ + for (yy = 0, p_lcb = &l2cb.lcb_pool[0]; yy < MAX_L2CAP_LINKS; yy++, p_lcb++) + { + if (p_lcb->in_use) + { + if (p_lcb->acl_priority == L2CAP_PRIORITY_HIGH) + { + p_lcb->link_xmit_quota = high_pri_link_quota; + } + else + { + /* Safety check in case we switched to round-robin with something outstanding */ + /* if sent_not_acked is added into round_robin_unacked then don't add it again */ + /* l2cap keeps updating sent_not_acked for exiting from round robin */ + if (( p_lcb->link_xmit_quota > 0 )&&( qq == 0 )) + l2cb.round_robin_unacked += p_lcb->sent_not_acked; + + p_lcb->link_xmit_quota = qq; + if (qq_remainder > 0) + { + p_lcb->link_xmit_quota++; + qq_remainder--; + } + } + + L2CAP_TRACE_EVENT ("l2c_link_adjust_allocation LCB %d Priority: %d XmitQuota: %d", + yy, p_lcb->acl_priority, p_lcb->link_xmit_quota); + + L2CAP_TRACE_EVENT (" SentNotAcked: %d RRUnacked: %d", + p_lcb->sent_not_acked, l2cb.round_robin_unacked); + + /* There is a special case where we have readjusted the link quotas and */ + /* this link may have sent anything but some other link sent packets so */ + /* so we may need a timer to kick off this link's transmissions. */ + if ( (p_lcb->link_state == LST_CONNECTED) + && (!list_is_empty(p_lcb->link_xmit_data_q)) + && (p_lcb->sent_not_acked < p_lcb->link_xmit_quota) ) + btu_start_timer (&p_lcb->timer_entry, BTU_TTYPE_L2CAP_LINK, L2CAP_LINK_FLOW_CONTROL_TOUT); + } + } + +} + +/******************************************************************************* +** +** Function l2c_link_adjust_chnl_allocation +** +** Description This function is called to calculate the amount of packets each +** non-F&EC channel may have outstanding. +** +** Currently, this is a simple allocation, dividing the number +** of packets allocated to the link by the number of channels. In +** the future, QOS configuration should be examined. +** +** Returns void +** +*******************************************************************************/ +void l2c_link_adjust_chnl_allocation (void) +{ + tL2C_CCB *p_ccb; + UINT8 xx; + + UINT16 weighted_chnls[GKI_NUM_TOTAL_BUF_POOLS]; + UINT16 quota_per_weighted_chnls[GKI_NUM_TOTAL_BUF_POOLS]; + UINT16 reserved_buff[GKI_NUM_TOTAL_BUF_POOLS]; + + L2CAP_TRACE_DEBUG ("l2c_link_adjust_chnl_allocation"); + + /* initialize variables */ + for (xx = 0; xx < GKI_NUM_TOTAL_BUF_POOLS; xx++ ) + { + weighted_chnls[xx] = 0; + reserved_buff[xx] = 0; + } + + /* add up all of tx and rx data rate requirement */ + /* channel required higher data rate will get more buffer quota */ + for (xx = 0; xx < MAX_L2CAP_CHANNELS; xx++) + { + p_ccb = l2cb.ccb_pool + xx; + + if (!p_ccb->in_use) + continue; + + if (p_ccb->peer_cfg.fcr.mode != L2CAP_FCR_BASIC_MODE) + { + weighted_chnls[p_ccb->ertm_info.user_tx_pool_id] += p_ccb->tx_data_rate; + weighted_chnls[p_ccb->ertm_info.user_rx_pool_id] += p_ccb->rx_data_rate; + + if (p_ccb->ertm_info.fcr_tx_pool_id == HCI_ACL_POOL_ID) + { + /* reserve buffers only for wait_for_ack_q to maximize throughput */ + /* retrans_q will work based on buffer status */ + reserved_buff[HCI_ACL_POOL_ID] += p_ccb->peer_cfg.fcr.tx_win_sz; + } + + if (p_ccb->ertm_info.fcr_rx_pool_id == HCI_ACL_POOL_ID) + { + /* reserve buffers for srej_rcv_hold_q */ + reserved_buff[HCI_ACL_POOL_ID] += p_ccb->peer_cfg.fcr.tx_win_sz; + } + } + else + { + /* low data rate is 1, medium is 2, high is 3 and no traffic is 0 */ + weighted_chnls[HCI_ACL_POOL_ID] += p_ccb->tx_data_rate + p_ccb->rx_data_rate; + } + } + + + /* get unit quota per pool */ + for (xx = 0; xx < GKI_NUM_TOTAL_BUF_POOLS; xx++ ) + { + if ( weighted_chnls[xx] > 0 ) + { + if (GKI_poolcount(xx) > reserved_buff[xx]) + quota_per_weighted_chnls[xx] = ((GKI_poolcount(xx) - reserved_buff[xx])/weighted_chnls[xx]) + 1; + else + quota_per_weighted_chnls[xx] = 1; + + L2CAP_TRACE_DEBUG ("POOL ID:%d, GKI_poolcount = %d, reserved_buff = %d, weighted_chnls = %d, quota_per_weighted_chnls = %d", + xx, GKI_poolcount(xx), reserved_buff[xx], weighted_chnls[xx], quota_per_weighted_chnls[xx] ); + } + else + quota_per_weighted_chnls[xx] = 0; + } + + + /* assign buffer quota to each channel based on its data rate requirement */ + for (xx = 0; xx < MAX_L2CAP_CHANNELS; xx++) + { + p_ccb = l2cb.ccb_pool + xx; + + if (!p_ccb->in_use) + continue; + + if (p_ccb->peer_cfg.fcr.mode != L2CAP_FCR_BASIC_MODE) + { + p_ccb->buff_quota = quota_per_weighted_chnls[p_ccb->ertm_info.user_tx_pool_id] * p_ccb->tx_data_rate; + + L2CAP_TRACE_EVENT ("CID:0x%04x FCR Mode:%u UserTxPool:%u Priority:%u TxDataRate:%u Quota:%u", + p_ccb->local_cid, p_ccb->peer_cfg.fcr.mode, p_ccb->ertm_info.user_tx_pool_id, + p_ccb->ccb_priority, p_ccb->tx_data_rate, p_ccb->buff_quota); + + } + else + { + p_ccb->buff_quota = quota_per_weighted_chnls[HCI_ACL_POOL_ID] * p_ccb->tx_data_rate; + + L2CAP_TRACE_EVENT ("CID:0x%04x Priority:%u TxDataRate:%u Quota:%u", + p_ccb->local_cid, + p_ccb->ccb_priority, p_ccb->tx_data_rate, p_ccb->buff_quota); + } + + /* quota may be change so check congestion */ + l2cu_check_channel_congestion (p_ccb); + } +} + +/******************************************************************************* +** +** Function l2c_link_processs_num_bufs +** +** Description This function is called when a "controller buffer size" +** event is first received from the controller. It updates +** the L2CAP values. +** +** Returns void +** +*******************************************************************************/ +void l2c_link_processs_num_bufs (UINT16 num_lm_acl_bufs) +{ + l2cb.num_lm_acl_bufs = l2cb.controller_xmit_window = num_lm_acl_bufs; + +} + +/******************************************************************************* +** +** Function l2c_link_pkts_rcvd +** +** Description This function is called from the HCI transport when it is time +** tto send a "Host ready for packets" command. This is only when +** host to controller flow control is used. If fills in the arrays +** of numbers of packets and handles. +** +** Returns count of number of entries filled in +** +*******************************************************************************/ +UINT8 l2c_link_pkts_rcvd (UINT16 *num_pkts, UINT16 *handles) +{ + UINT8 num_found = 0; + + UNUSED(num_pkts); + UNUSED(handles); + + return (num_found); +} + +/******************************************************************************* +** +** Function l2c_link_role_changed +** +** Description This function is called whan a link's master/slave role change +** event is received. It simply updates the link control block. +** +** Returns void +** +*******************************************************************************/ +void l2c_link_role_changed (BD_ADDR bd_addr, UINT8 new_role, UINT8 hci_status) +{ + tL2C_LCB *p_lcb; + int xx; + + /* Make sure not called from HCI Command Status (bd_addr and new_role are invalid) */ + if (bd_addr) + { + /* If here came form hci role change event */ + p_lcb = l2cu_find_lcb_by_bd_addr (bd_addr, BT_TRANSPORT_BR_EDR); + if (p_lcb) + { + p_lcb->link_role = new_role; + + /* Reset high priority link if needed */ + if (hci_status == HCI_SUCCESS) + l2cu_set_acl_priority(bd_addr, p_lcb->acl_priority, TRUE); + } + } + + /* Check if any LCB was waiting for switch to be completed */ + for (xx = 0, p_lcb = &l2cb.lcb_pool[0]; xx < MAX_L2CAP_LINKS; xx++, p_lcb++) + { + if ((p_lcb->in_use) && (p_lcb->link_state == LST_CONNECTING_WAIT_SWITCH)) + { + l2cu_create_conn_after_switch (p_lcb); + } + } +} + +/******************************************************************************* +** +** Function l2c_pin_code_request +** +** Description This function is called whan a pin-code request is received +** on a connection. If there are no channels active yet on the +** link, it extends the link first connection timer. Make sure +** that inactivity timer is not extended if PIN code happens +** to be after last ccb released. +** +** Returns void +** +*******************************************************************************/ +void l2c_pin_code_request (BD_ADDR bd_addr) +{ + tL2C_LCB *p_lcb = l2cu_find_lcb_by_bd_addr (bd_addr, BT_TRANSPORT_BR_EDR); + + if ( (p_lcb) && (!p_lcb->ccb_queue.p_first_ccb) ) + { + btu_start_timer (&p_lcb->timer_entry, BTU_TTYPE_L2CAP_LINK, L2CAP_LINK_CONNECT_TOUT_EXT); + } +} + +#if L2CAP_WAKE_PARKED_LINK == TRUE +/******************************************************************************* +** +** Function l2c_link_check_power_mode +** +** Description This function is called to check power mode. +** +** Returns TRUE if link is going to be active from park +** FALSE if nothing to send or not in park mode +** +*******************************************************************************/ +BOOLEAN l2c_link_check_power_mode (tL2C_LCB *p_lcb) +{ + tBTM_PM_MODE mode; + tL2C_CCB *p_ccb; + BOOLEAN need_to_active = FALSE; + + /* + * We only switch park to active only if we have unsent packets + */ + if (list_is_empty(p_lcb->link_xmit_data_q)) + { + for (p_ccb = p_lcb->ccb_queue.p_first_ccb; p_ccb; p_ccb = p_ccb->p_next_ccb) + { + if (!GKI_queue_is_empty(&p_ccb->xmit_hold_q)) + { + need_to_active = TRUE; + break; + } + } + } + else + need_to_active = TRUE; + + /* if we have packets to send */ + if ( need_to_active ) + { + /* check power mode */ + if (BTM_ReadPowerMode(p_lcb->remote_bd_addr, &mode) == BTM_SUCCESS) + { + if ( mode == BTM_PM_STS_PENDING ) + { + L2CAP_TRACE_DEBUG ("LCB(0x%x) is in PM pending state", p_lcb->handle); + + return TRUE; + } + } + } + return FALSE; +} +#endif /* L2CAP_WAKE_PARKED_LINK == TRUE) */ + +/******************************************************************************* +** +** Function l2c_link_check_send_pkts +** +** Description This function is called to check if it can send packets +** to the Host Controller. It may be passed the address of +** a packet to send. +** +** Returns void +** +*******************************************************************************/ +void l2c_link_check_send_pkts (tL2C_LCB *p_lcb, tL2C_CCB *p_ccb, BT_HDR *p_buf) +{ + int xx; + BOOLEAN single_write = FALSE; + + /* Save the channel ID for faster counting */ + if (p_buf) + { + if (p_ccb != NULL) + { + p_buf->event = p_ccb->local_cid; + single_write = TRUE; + } + else + p_buf->event = 0; + + p_buf->layer_specific = 0; + list_append(p_lcb->link_xmit_data_q, p_buf); + + if (p_lcb->link_xmit_quota == 0) + { +#if BLE_INCLUDED == TRUE + if (p_lcb->transport == BT_TRANSPORT_LE) + l2cb.ble_check_round_robin = TRUE; + else +#endif + l2cb.check_round_robin = TRUE; + } + } + + /* If this is called from uncongested callback context break recursive calling. + ** This LCB will be served when receiving number of completed packet event. + */ + if (l2cb.is_cong_cback_context) + return; + + /* If we are in a scenario where there are not enough buffers for each link to + ** have at least 1, then do a round-robin for all the LCBs + */ + if ( (p_lcb == NULL) || (p_lcb->link_xmit_quota == 0) ) + { + if (p_lcb == NULL) + p_lcb = l2cb.lcb_pool; + else if (!single_write) + p_lcb++; + + /* Loop through, starting at the next */ + for (xx = 0; xx < MAX_L2CAP_LINKS; xx++, p_lcb++) + { + /* If controller window is full, nothing to do */ + if (((l2cb.controller_xmit_window == 0 || + (l2cb.round_robin_unacked >= l2cb.round_robin_quota)) +#if (BLE_INCLUDED == TRUE) + && (p_lcb->transport == BT_TRANSPORT_BR_EDR) + ) + || (p_lcb->transport == BT_TRANSPORT_LE && + (l2cb.ble_round_robin_unacked >= l2cb.ble_round_robin_quota || + l2cb.controller_le_xmit_window == 0 ))) +#else + )) +#endif + break; + + + /* Check for wraparound */ + if (p_lcb == &l2cb.lcb_pool[MAX_L2CAP_LINKS]) + p_lcb = &l2cb.lcb_pool[0]; + + if ( (!p_lcb->in_use) + || (p_lcb->partial_segment_being_sent) + || (p_lcb->link_state != LST_CONNECTED) + || (p_lcb->link_xmit_quota != 0) + || (L2C_LINK_CHECK_POWER_MODE (p_lcb)) ) + continue; + + /* See if we can send anything from the Link Queue */ + if (!list_is_empty(p_lcb->link_xmit_data_q)) { + p_buf = (BT_HDR *)list_front(p_lcb->link_xmit_data_q); + list_remove(p_lcb->link_xmit_data_q, p_buf); + l2c_link_send_to_lower (p_lcb, p_buf); + } + else if (single_write) + { + /* If only doing one write, break out */ + break; + } + /* If nothing on the link queue, check the channel queue */ + else if ((p_buf = l2cu_get_next_buffer_to_send (p_lcb)) != NULL) + { + l2c_link_send_to_lower (p_lcb, p_buf); + } + } + + /* If we finished without using up our quota, no need for a safety check */ + if ( (l2cb.controller_xmit_window > 0) + && (l2cb.round_robin_unacked < l2cb.round_robin_quota) +#if (BLE_INCLUDED == TRUE) + && (p_lcb->transport == BT_TRANSPORT_BR_EDR) +#endif + ) + l2cb.check_round_robin = FALSE; + +#if (BLE_INCLUDED == TRUE) + if ( (l2cb.controller_le_xmit_window > 0) + && (l2cb.ble_round_robin_unacked < l2cb.ble_round_robin_quota) + && (p_lcb->transport == BT_TRANSPORT_LE)) + l2cb.ble_check_round_robin = FALSE; +#endif + } + else /* if this is not round-robin service */ + { + /* If a partial segment is being sent, can't send anything else */ + if ( (p_lcb->partial_segment_being_sent) + || (p_lcb->link_state != LST_CONNECTED) + || (L2C_LINK_CHECK_POWER_MODE (p_lcb)) ) + return; + + /* See if we can send anything from the link queue */ +#if (BLE_INCLUDED == TRUE) + while ( ((l2cb.controller_xmit_window != 0 && (p_lcb->transport == BT_TRANSPORT_BR_EDR)) || + (l2cb.controller_le_xmit_window != 0 && (p_lcb->transport == BT_TRANSPORT_LE))) + && (p_lcb->sent_not_acked < p_lcb->link_xmit_quota)) +#else + while ( (l2cb.controller_xmit_window != 0) + && (p_lcb->sent_not_acked < p_lcb->link_xmit_quota)) +#endif + { + if (list_is_empty(p_lcb->link_xmit_data_q)) + break; + + p_buf = (BT_HDR *)list_front(p_lcb->link_xmit_data_q); + list_remove(p_lcb->link_xmit_data_q, p_buf); + if (!l2c_link_send_to_lower (p_lcb, p_buf)) + break; + } + + if (!single_write) + { + /* See if we can send anything for any channel */ +#if (BLE_INCLUDED == TRUE) + while ( ((l2cb.controller_xmit_window != 0 && (p_lcb->transport == BT_TRANSPORT_BR_EDR)) || + (l2cb.controller_le_xmit_window != 0 && (p_lcb->transport == BT_TRANSPORT_LE))) + && (p_lcb->sent_not_acked < p_lcb->link_xmit_quota)) +#else + while ((l2cb.controller_xmit_window != 0) && (p_lcb->sent_not_acked < p_lcb->link_xmit_quota)) +#endif + { + if ((p_buf = l2cu_get_next_buffer_to_send (p_lcb)) == NULL) + break; + + if (!l2c_link_send_to_lower (p_lcb, p_buf)) + break; + } + } + + /* There is a special case where we have readjusted the link quotas and */ + /* this link may have sent anything but some other link sent packets so */ + /* so we may need a timer to kick off this link's transmissions. */ + if ( (!list_is_empty(p_lcb->link_xmit_data_q)) && (p_lcb->sent_not_acked < p_lcb->link_xmit_quota) ) + btu_start_timer (&p_lcb->timer_entry, BTU_TTYPE_L2CAP_LINK, L2CAP_LINK_FLOW_CONTROL_TOUT); + } + +} + +/******************************************************************************* +** +** Function l2c_link_send_to_lower +** +** Description This function queues the buffer for HCI transmission +** +** Returns TRUE for success, FALSE for fail +** +*******************************************************************************/ +static BOOLEAN l2c_link_send_to_lower (tL2C_LCB *p_lcb, BT_HDR *p_buf) +{ + UINT16 num_segs; + UINT16 xmit_window, acl_data_size; + const controller_t *controller = controller_get_interface(); + + if ((p_buf->len <= controller->get_acl_packet_size_classic() +#if (BLE_INCLUDED == TRUE) + && (p_lcb->transport == BT_TRANSPORT_BR_EDR)) || + ((p_lcb->transport == BT_TRANSPORT_LE) && (p_buf->len <= controller->get_acl_packet_size_ble())) +#else + ) +#endif + ) + { + if (p_lcb->link_xmit_quota == 0) + { +#if (BLE_INCLUDED == TRUE) + if (p_lcb->transport == BT_TRANSPORT_LE) + l2cb.ble_round_robin_unacked++; + else +#endif + l2cb.round_robin_unacked++; + } + p_lcb->sent_not_acked++; + p_buf->layer_specific = 0; + +#if (BLE_INCLUDED == TRUE) + if (p_lcb->transport == BT_TRANSPORT_LE) + { + l2cb.controller_le_xmit_window--; + bte_main_hci_send(p_buf, (UINT16)(BT_EVT_TO_LM_HCI_ACL|LOCAL_BLE_CONTROLLER_ID)); + } + else +#endif + { + l2cb.controller_xmit_window--; + bte_main_hci_send(p_buf, BT_EVT_TO_LM_HCI_ACL); + } + } + else + { +#if BLE_INCLUDED == TRUE + if (p_lcb->transport == BT_TRANSPORT_LE) + { + acl_data_size = controller->get_acl_data_size_ble(); + xmit_window = l2cb.controller_le_xmit_window; + + } + else +#endif + { + acl_data_size = controller->get_acl_data_size_classic(); + xmit_window = l2cb.controller_xmit_window; + } + num_segs = (p_buf->len - HCI_DATA_PREAMBLE_SIZE + acl_data_size - 1) / acl_data_size; + + + /* If doing round-robin, then only 1 segment each time */ + if (p_lcb->link_xmit_quota == 0) + { + num_segs = 1; + p_lcb->partial_segment_being_sent = TRUE; + } + else + { + /* Multi-segment packet. Make sure it can fit */ + if (num_segs > xmit_window) + { + num_segs = xmit_window; + p_lcb->partial_segment_being_sent = TRUE; + } + + if (num_segs > (p_lcb->link_xmit_quota - p_lcb->sent_not_acked)) + { + num_segs = (p_lcb->link_xmit_quota - p_lcb->sent_not_acked); + p_lcb->partial_segment_being_sent = TRUE; + } + } + + p_buf->layer_specific = num_segs; +#if BLE_INCLUDED == TRUE + if (p_lcb->transport == BT_TRANSPORT_LE) + { + l2cb.controller_le_xmit_window -= num_segs; + if (p_lcb->link_xmit_quota == 0) + l2cb.ble_round_robin_unacked += num_segs; + } + else +#endif + { + l2cb.controller_xmit_window -= num_segs; + + if (p_lcb->link_xmit_quota == 0) + l2cb.round_robin_unacked += num_segs; + } + + p_lcb->sent_not_acked += num_segs; +#if BLE_INCLUDED == TRUE + if (p_lcb->transport == BT_TRANSPORT_LE) + { + bte_main_hci_send(p_buf, (UINT16)(BT_EVT_TO_LM_HCI_ACL|LOCAL_BLE_CONTROLLER_ID)); + } + else +#endif + { + bte_main_hci_send(p_buf, BT_EVT_TO_LM_HCI_ACL); + } + } + +#if (L2CAP_HCI_FLOW_CONTROL_DEBUG == TRUE) +#if (BLE_INCLUDED == TRUE) + if (p_lcb->transport == BT_TRANSPORT_LE) + { + L2CAP_TRACE_DEBUG ("TotalWin=%d,Hndl=0x%x,Quota=%d,Unack=%d,RRQuota=%d,RRUnack=%d", + l2cb.controller_le_xmit_window, + p_lcb->handle, + p_lcb->link_xmit_quota, p_lcb->sent_not_acked, + l2cb.ble_round_robin_quota, l2cb.ble_round_robin_unacked); + } + else +#endif + { + L2CAP_TRACE_DEBUG ("TotalWin=%d,Hndl=0x%x,Quota=%d,Unack=%d,RRQuota=%d,RRUnack=%d", + l2cb.controller_xmit_window, + p_lcb->handle, + p_lcb->link_xmit_quota, p_lcb->sent_not_acked, + l2cb.round_robin_quota, l2cb.round_robin_unacked); + } +#endif + + return TRUE; +} + +/******************************************************************************* +** +** Function l2c_link_process_num_completed_pkts +** +** Description This function is called when a "number-of-completed-packets" +** event is received from the controller. It updates all the +** LCB transmit counts. +** +** Returns void +** +*******************************************************************************/ +void l2c_link_process_num_completed_pkts (UINT8 *p) +{ + UINT8 num_handles, xx; + UINT16 handle; + UINT16 num_sent; + tL2C_LCB *p_lcb; + + STREAM_TO_UINT8 (num_handles, p); + + for (xx = 0; xx < num_handles; xx++) + { + STREAM_TO_UINT16 (handle, p); + STREAM_TO_UINT16 (num_sent, p); + + p_lcb = l2cu_find_lcb_by_handle (handle); + + /* Callback for number of completed packet event */ + /* Originally designed for [3DSG] */ + if((p_lcb != NULL) && (p_lcb->p_nocp_cb)) + { + L2CAP_TRACE_DEBUG ("L2CAP - calling NoCP callback"); + (*p_lcb->p_nocp_cb)(p_lcb->remote_bd_addr); + } + + if (p_lcb) + { +#if (BLE_INCLUDED == TRUE) + if (p_lcb && (p_lcb->transport == BT_TRANSPORT_LE)) + l2cb.controller_le_xmit_window += num_sent; + else +#endif + { + /* Maintain the total window to the controller */ + l2cb.controller_xmit_window += num_sent; + } + /* If doing round-robin, adjust communal counts */ + if (p_lcb->link_xmit_quota == 0) + { +#if BLE_INCLUDED == TRUE + if (p_lcb->transport == BT_TRANSPORT_LE) + { + /* Don't go negative */ + if (l2cb.ble_round_robin_unacked > num_sent) + l2cb.ble_round_robin_unacked -= num_sent; + else + l2cb.ble_round_robin_unacked = 0; + } + else +#endif + { + /* Don't go negative */ + if (l2cb.round_robin_unacked > num_sent) + l2cb.round_robin_unacked -= num_sent; + else + l2cb.round_robin_unacked = 0; + } + } + + /* Don't go negative */ + if (p_lcb->sent_not_acked > num_sent) + p_lcb->sent_not_acked -= num_sent; + else + p_lcb->sent_not_acked = 0; + + l2c_link_check_send_pkts (p_lcb, NULL, NULL); + + /* If we were doing round-robin for low priority links, check 'em */ + if ( (p_lcb->acl_priority == L2CAP_PRIORITY_HIGH) + && (l2cb.check_round_robin) + && (l2cb.round_robin_unacked < l2cb.round_robin_quota) ) + { + l2c_link_check_send_pkts (NULL, NULL, NULL); + } +#if BLE_INCLUDED == TRUE + if ((p_lcb->transport == BT_TRANSPORT_LE) + && (p_lcb->acl_priority == L2CAP_PRIORITY_HIGH) + && ((l2cb.ble_check_round_robin) + && (l2cb.ble_round_robin_unacked < l2cb.ble_round_robin_quota))) + { + l2c_link_check_send_pkts (NULL, NULL, NULL); + } +#endif + } + +#if (L2CAP_HCI_FLOW_CONTROL_DEBUG == TRUE) + if (p_lcb) + { +#if (BLE_INCLUDED == TRUE) + if (p_lcb->transport == BT_TRANSPORT_LE) + { + L2CAP_TRACE_DEBUG ("TotalWin=%d,LinkUnack(0x%x)=%d,RRCheck=%d,RRUnack=%d", + l2cb.controller_le_xmit_window, + p_lcb->handle, p_lcb->sent_not_acked, + l2cb.ble_check_round_robin, l2cb.ble_round_robin_unacked); + } + else +#endif + { + L2CAP_TRACE_DEBUG ("TotalWin=%d,LinkUnack(0x%x)=%d,RRCheck=%d,RRUnack=%d", + l2cb.controller_xmit_window, + p_lcb->handle, p_lcb->sent_not_acked, + l2cb.check_round_robin, l2cb.round_robin_unacked); + + } + } + else + { +#if (BLE_INCLUDED == TRUE) + L2CAP_TRACE_DEBUG ("TotalWin=%d LE_Win: %d, Handle=0x%x, RRCheck=%d, RRUnack=%d", + l2cb.controller_xmit_window, + l2cb.controller_le_xmit_window, + handle, + l2cb.ble_check_round_robin, l2cb.ble_round_robin_unacked); +#else + L2CAP_TRACE_DEBUG ("TotalWin=%d Handle=0x%x RRCheck=%d RRUnack=%d", + l2cb.controller_xmit_window, + handle, + l2cb.check_round_robin, l2cb.round_robin_unacked); +#endif + } +#endif + } + +#if (defined(HCILP_INCLUDED) && HCILP_INCLUDED == TRUE) + /* only full stack can enable sleep mode */ + btu_check_bt_sleep (); +#endif +} + +/******************************************************************************* +** +** Function l2c_link_segments_xmitted +** +** Description This function is called from the HCI Interface when an ACL +** data packet segment is transmitted. +** +** Returns void +** +*******************************************************************************/ +void l2c_link_segments_xmitted (BT_HDR *p_msg) +{ + UINT8 *p = (UINT8 *)(p_msg + 1) + p_msg->offset; + UINT16 handle; + tL2C_LCB *p_lcb; + + /* Extract the handle */ + STREAM_TO_UINT16 (handle, p); + handle = HCID_GET_HANDLE (handle); + + /* Find the LCB based on the handle */ + if ((p_lcb = l2cu_find_lcb_by_handle (handle)) == NULL) + { + L2CAP_TRACE_WARNING ("L2CAP - rcvd segment complete, unknown handle: %d", handle); + GKI_freebuf (p_msg); + return; + } + + if (p_lcb->link_state == LST_CONNECTED) + { + /* Enqueue the buffer to the head of the transmit queue, and see */ + /* if we can transmit anything more. */ + list_prepend(p_lcb->link_xmit_data_q, p_msg); + + p_lcb->partial_segment_being_sent = FALSE; + + l2c_link_check_send_pkts (p_lcb, NULL, NULL); + } + else + GKI_freebuf (p_msg); +} diff --git a/components/bt/bluedroid/stack/l2cap/l2c_main.c b/components/bt/bluedroid/stack/l2cap/l2c_main.c new file mode 100755 index 0000000000..7181fe1c04 --- /dev/null +++ b/components/bt/bluedroid/stack/l2cap/l2c_main.c @@ -0,0 +1,1006 @@ +/****************************************************************************** + * + * Copyright (C) 1999-2012 Broadcom Corporation + * + * 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 main L2CAP entry points + * + ******************************************************************************/ + +#include +#include +//#include + +#include "controller.h" +//#include "btcore/include/counter.h" +#include "bt_target.h" +#include "btm_int.h" +#include "btu.h" +#include "gki.h" +#include "hcimsgs.h" +#include "l2c_api.h" +#include "l2c_int.h" +#include "l2cdefs.h" +//#include "osi/include/log.h" + +/********************************************************************************/ +/* L O C A L F U N C T I O N P R O T O T Y P E S */ +/********************************************************************************/ +static void process_l2cap_cmd (tL2C_LCB *p_lcb, UINT8 *p, UINT16 pkt_len); + +/********************************************************************************/ +/* G L O B A L L 2 C A P D A T A */ +/********************************************************************************/ +#if L2C_DYNAMIC_MEMORY == FALSE +tL2C_CB l2cb; +#endif + +/******************************************************************************* +** +** Function l2c_bcst_msg +** +** Description +** +** Returns void +** +*******************************************************************************/ +void l2c_bcst_msg( BT_HDR *p_buf, UINT16 psm ) +{ + UINT8 *p; + + /* Ensure we have enough space in the buffer for the L2CAP and HCI headers */ + if (p_buf->offset < L2CAP_BCST_MIN_OFFSET) + { + L2CAP_TRACE_ERROR ("L2CAP - cannot send buffer, offset: %d", p_buf->offset); + GKI_freebuf (p_buf); + return; + } + + /* Step back some bytes to add the headers */ + p_buf->offset -= (HCI_DATA_PREAMBLE_SIZE + L2CAP_PKT_OVERHEAD + L2CAP_BCST_OVERHEAD); + p_buf->len += L2CAP_PKT_OVERHEAD + L2CAP_BCST_OVERHEAD; + + /* Set the pointer to the beginning of the data */ + p = (UINT8 *)(p_buf + 1) + p_buf->offset; + + /* First, the HCI transport header */ + UINT16_TO_STREAM (p, 0x0050 | (L2CAP_PKT_START << 12) | (2 << 14)); + + uint16_t acl_data_size = controller_get_interface()->get_acl_data_size_classic(); + /* The HCI transport will segment the buffers. */ + if (p_buf->len > acl_data_size) + { + UINT16_TO_STREAM (p, acl_data_size); + } + else + { + UINT16_TO_STREAM (p, p_buf->len); + } + + /* Now the L2CAP header */ + UINT16_TO_STREAM (p, p_buf->len - L2CAP_PKT_OVERHEAD); + UINT16_TO_STREAM (p, L2CAP_CONNECTIONLESS_CID); + UINT16_TO_STREAM (p, psm); + + p_buf->len += HCI_DATA_PREAMBLE_SIZE; + + if (p_buf->len <= controller_get_interface()->get_acl_packet_size_classic()) + { + //counter_add("l2cap.ch2.tx.bytes", p_buf->len); + //counter_add("l2cap.ch2.tx.pkts", 1); + + bte_main_hci_send(p_buf, BT_EVT_TO_LM_HCI_ACL); + } +} + + +/******************************************************************************* +** +** Function l2c_rcv_acl_data +** +** Description This function is called from the HCI Interface when an ACL +** data packet is received. +** +** Returns void +** +*******************************************************************************/ +void l2c_rcv_acl_data (BT_HDR *p_msg) +{ + UINT8 *p = (UINT8 *)(p_msg + 1) + p_msg->offset; + UINT16 handle, hci_len; + UINT8 pkt_type; + tL2C_LCB *p_lcb; + tL2C_CCB *p_ccb = NULL; + UINT16 l2cap_len, rcv_cid, psm; + + /* Extract the handle */ + STREAM_TO_UINT16 (handle, p); + pkt_type = HCID_GET_EVENT (handle); + handle = HCID_GET_HANDLE (handle); + + /* Since the HCI Transport is putting segmented packets back together, we */ + /* should never get a valid packet with the type set to "continuation" */ + if (pkt_type != L2CAP_PKT_CONTINUE) + { + /* Find the LCB based on the handle */ + if ((p_lcb = l2cu_find_lcb_by_handle (handle)) == NULL) + { + UINT8 cmd_code; + + /* There is a slight possibility (specifically with USB) that we get an */ + /* L2CAP connection request before we get the HCI connection complete. */ + /* So for these types of messages, hold them for up to 2 seconds. */ + STREAM_TO_UINT16 (hci_len, p); + STREAM_TO_UINT16 (l2cap_len, p); + STREAM_TO_UINT16 (rcv_cid, p); + STREAM_TO_UINT8 (cmd_code, p); + + if ((p_msg->layer_specific == 0) && (rcv_cid == L2CAP_SIGNALLING_CID) + && (cmd_code == L2CAP_CMD_INFO_REQ || cmd_code == L2CAP_CMD_CONN_REQ)) { + L2CAP_TRACE_WARNING ("L2CAP - holding ACL for unknown handle:%d ls:%d" + " cid:%d opcode:%d cur count:%d", handle, p_msg->layer_specific, + rcv_cid, cmd_code, list_length(l2cb.rcv_pending_q)); + p_msg->layer_specific = 2; + list_append(l2cb.rcv_pending_q, p_msg); + + if (list_length(l2cb.rcv_pending_q) == 1) + btu_start_timer (&l2cb.rcv_hold_tle, BTU_TTYPE_L2CAP_HOLD, BT_1SEC_TIMEOUT); + + return; + } else { + L2CAP_TRACE_ERROR ("L2CAP - rcvd ACL for unknown handle:%d ls:%d cid:%d" + " opcode:%d cur count:%d", handle, p_msg->layer_specific, rcv_cid, + cmd_code, list_length(l2cb.rcv_pending_q)); + } + GKI_freebuf (p_msg); + return; + } + } + else + { + L2CAP_TRACE_WARNING ("L2CAP - expected pkt start or complete, got: %d", pkt_type); + GKI_freebuf (p_msg); + return; + } + + /* Extract the length and update the buffer header */ + STREAM_TO_UINT16 (hci_len, p); + p_msg->offset += 4; + + /* Extract the length and CID */ + STREAM_TO_UINT16 (l2cap_len, p); + STREAM_TO_UINT16 (rcv_cid, p); + +#if BLE_INCLUDED == TRUE + /* for BLE channel, always notify connection when ACL data received on the link */ + if (p_lcb && p_lcb->transport == BT_TRANSPORT_LE && p_lcb->link_state != LST_DISCONNECTING) + /* only process fixed channel data as channel open indication when link is not in disconnecting mode */ + l2cble_notify_le_connection(p_lcb->remote_bd_addr); +#endif + + /* Find the CCB for this CID */ + if (rcv_cid >= L2CAP_BASE_APPL_CID) + { + if ((p_ccb = l2cu_find_ccb_by_cid (p_lcb, rcv_cid)) == NULL) + { + L2CAP_TRACE_WARNING ("L2CAP - unknown CID: 0x%04x", rcv_cid); + GKI_freebuf (p_msg); + return; + } + } + + if (hci_len >= L2CAP_PKT_OVERHEAD) /* Must receive at least the L2CAP length and CID.*/ + { + p_msg->len = hci_len - L2CAP_PKT_OVERHEAD; + p_msg->offset += L2CAP_PKT_OVERHEAD; + } + else + { + L2CAP_TRACE_WARNING ("L2CAP - got incorrect hci header" ); + GKI_freebuf (p_msg); + return; + } + + if (l2cap_len != p_msg->len) + { + L2CAP_TRACE_WARNING ("L2CAP - bad length in pkt. Exp: %d Act: %d", + l2cap_len, p_msg->len); + + GKI_freebuf (p_msg); + return; + } + + /* Send the data through the channel state machine */ + if (rcv_cid == L2CAP_SIGNALLING_CID) + { + //counter_add("l2cap.sig.rx.bytes", l2cap_len); + //counter_add("l2cap.sig.rx.pkts", 1); + process_l2cap_cmd (p_lcb, p, l2cap_len); + GKI_freebuf (p_msg); + } + else if (rcv_cid == L2CAP_CONNECTIONLESS_CID) + { + //counter_add("l2cap.ch2.rx.bytes", l2cap_len); + //counter_add("l2cap.ch2.rx.pkts", 1); + /* process_connectionless_data (p_lcb); */ + STREAM_TO_UINT16 (psm, p); + L2CAP_TRACE_DEBUG( "GOT CONNECTIONLESS DATA PSM:%d", psm ) ; + +#if (L2CAP_UCD_INCLUDED == TRUE) + /* if it is not broadcast, check UCD registration */ + if ( l2c_ucd_check_rx_pkts( p_lcb, p_msg ) ) + { + /* nothing to do */ + } + else +#endif + GKI_freebuf (p_msg); + } +#if (BLE_INCLUDED == TRUE) + else if (rcv_cid == L2CAP_BLE_SIGNALLING_CID) + { + //counter_add("l2cap.ble.rx.bytes", l2cap_len); + //counter_add("l2cap.ble.rx.pkts", 1); + l2cble_process_sig_cmd (p_lcb, p, l2cap_len); + GKI_freebuf (p_msg); + } +#endif +#if (L2CAP_NUM_FIXED_CHNLS > 0) + else if ((rcv_cid >= L2CAP_FIRST_FIXED_CHNL) && (rcv_cid <= L2CAP_LAST_FIXED_CHNL) && + (l2cb.fixed_reg[rcv_cid - L2CAP_FIRST_FIXED_CHNL].pL2CA_FixedData_Cb != NULL) ) + { + //counter_add("l2cap.fix.rx.bytes", l2cap_len); + //counter_add("l2cap.fix.rx.pkts", 1); + /* If no CCB for this channel, allocate one */ + if (p_lcb && + /* only process fixed channel data when link is open or wait for data indication */ + (p_lcb->link_state != LST_DISCONNECTING) && + l2cu_initialize_fixed_ccb (p_lcb, rcv_cid, &l2cb.fixed_reg[rcv_cid - L2CAP_FIRST_FIXED_CHNL].fixed_chnl_opts)) + { + p_ccb = p_lcb->p_fixed_ccbs[rcv_cid - L2CAP_FIRST_FIXED_CHNL]; + + if (p_ccb->peer_cfg.fcr.mode != L2CAP_FCR_BASIC_MODE) + l2c_fcr_proc_pdu (p_ccb, p_msg); + else + (*l2cb.fixed_reg[rcv_cid - L2CAP_FIRST_FIXED_CHNL].pL2CA_FixedData_Cb) + (rcv_cid, p_lcb->remote_bd_addr, p_msg); + } + else + GKI_freebuf (p_msg); + } +#endif + + else + { + //counter_add("l2cap.dyn.rx.bytes", l2cap_len); + //counter_add("l2cap.dyn.rx.pkts", 1); + if (p_ccb == NULL) + GKI_freebuf (p_msg); + else + { + /* Basic mode packets go straight to the state machine */ + if (p_ccb->peer_cfg.fcr.mode == L2CAP_FCR_BASIC_MODE) + l2c_csm_execute (p_ccb, L2CEVT_L2CAP_DATA, p_msg); + else + { + /* eRTM or streaming mode, so we need to validate states first */ + if ((p_ccb->chnl_state == CST_OPEN) || (p_ccb->chnl_state == CST_CONFIG)) + l2c_fcr_proc_pdu (p_ccb, p_msg); + else + GKI_freebuf (p_msg); + } + } + } +} + +/******************************************************************************* +** +** Function process_l2cap_cmd +** +** Description This function is called when a packet is received on the +** L2CAP signalling CID +** +** Returns void +** +*******************************************************************************/ +static void process_l2cap_cmd (tL2C_LCB *p_lcb, UINT8 *p, UINT16 pkt_len) +{ + UINT8 *p_pkt_end, *p_next_cmd, *p_cfg_end, *p_cfg_start; + UINT8 cmd_code, cfg_code, cfg_len, id; + tL2C_CONN_INFO con_info; + tL2CAP_CFG_INFO cfg_info; + UINT16 rej_reason, rej_mtu, lcid, rcid, info_type; + tL2C_CCB *p_ccb; + tL2C_RCB *p_rcb; + BOOLEAN cfg_rej, pkt_size_rej = FALSE; + UINT16 cfg_rej_len, cmd_len; + UINT16 result; + tL2C_CONN_INFO ci; + +#if (defined BLE_INCLUDED && BLE_INCLUDED == TRUE) + /* if l2cap command received in CID 1 on top of an LE link, ignore this command */ + if (p_lcb->transport == BT_TRANSPORT_LE) + return; +#endif + + /* Reject the packet if it exceeds the default Signalling Channel MTU */ + if (pkt_len > L2CAP_DEFAULT_MTU) + { + /* Core Spec requires a single response to the first command found in a multi-command + ** L2cap packet. If only responses in the packet, then it will be ignored. + ** Here we simply mark the bad packet and decide which cmd ID to reject later + */ + pkt_size_rej = TRUE; + L2CAP_TRACE_ERROR ("L2CAP SIG MTU Pkt Len Exceeded (672) -> pkt_len: %d", pkt_len); + } + + p_next_cmd = p; + p_pkt_end = p + pkt_len; + + memset (&cfg_info, 0, sizeof(cfg_info)); + + /* An L2CAP packet may contain multiple commands */ + while (TRUE) + { + /* Smallest command is 4 bytes */ + if ((p = p_next_cmd) > (p_pkt_end - 4)) + break; + + STREAM_TO_UINT8 (cmd_code, p); + STREAM_TO_UINT8 (id, p); + STREAM_TO_UINT16 (cmd_len, p); + + /* Check command length does not exceed packet length */ + if ((p_next_cmd = p + cmd_len) > p_pkt_end) + { + L2CAP_TRACE_WARNING ("Command len bad pkt_len: %d cmd_len: %d code: %d", + pkt_len, cmd_len, cmd_code); + break; + } + + L2CAP_TRACE_DEBUG ("cmd_code: %d, id:%d, cmd_len:%d", cmd_code, id, cmd_len); + + /* Bad L2CAP packet length, look or cmd to reject */ + if (pkt_size_rej) + { + /* If command found rejected it and we're done, otherwise keep looking */ + if (l2c_is_cmd_rejected(cmd_code, id, p_lcb)) + return; + else + continue; /* Look for next cmd/response in current packet */ + } + + switch (cmd_code) + { + case L2CAP_CMD_REJECT: + STREAM_TO_UINT16 (rej_reason, p); + if (rej_reason == L2CAP_CMD_REJ_MTU_EXCEEDED) + { + STREAM_TO_UINT16 (rej_mtu, p); + /* What to do with the MTU reject ? We have negotiated an MTU. For now */ + /* we will ignore it and let a higher protocol timeout take care of it */ + + L2CAP_TRACE_WARNING ("L2CAP - MTU rej Handle: %d MTU: %d", p_lcb->handle, rej_mtu); + } + if (rej_reason == L2CAP_CMD_REJ_INVALID_CID) + { + STREAM_TO_UINT16 (rcid, p); + STREAM_TO_UINT16 (lcid, p); + + L2CAP_TRACE_WARNING ("L2CAP - rej with CID invalid, LCID: 0x%04x RCID: 0x%04x", lcid, rcid); + + /* Remote CID invalid. Treat as a disconnect */ + if (((p_ccb = l2cu_find_ccb_by_cid (p_lcb, lcid)) != NULL) + && (p_ccb->remote_cid == rcid)) + { + /* Fake link disconnect - no reply is generated */ + l2c_csm_execute (p_ccb, L2CEVT_LP_DISCONNECT_IND, NULL); + } + } + + /* SonyEricsson Info request Bug workaround (Continue connection) */ + else if (rej_reason == L2CAP_CMD_REJ_NOT_UNDERSTOOD && p_lcb->w4_info_rsp) + { + btu_stop_timer (&p_lcb->info_timer_entry); + + p_lcb->w4_info_rsp = FALSE; + ci.status = HCI_SUCCESS; + memcpy (ci.bd_addr, p_lcb->remote_bd_addr, sizeof(BD_ADDR)); + + /* For all channels, send the event through their FSMs */ + for (p_ccb = p_lcb->ccb_queue.p_first_ccb; p_ccb; p_ccb = p_ccb->p_next_ccb) + { + l2c_csm_execute (p_ccb, L2CEVT_L2CAP_INFO_RSP, &ci); + } + } + break; + + case L2CAP_CMD_CONN_REQ: + STREAM_TO_UINT16 (con_info.psm, p); + STREAM_TO_UINT16 (rcid, p); + if ((p_rcb = l2cu_find_rcb_by_psm (con_info.psm)) == NULL) + { + L2CAP_TRACE_WARNING ("L2CAP - rcvd conn req for unknown PSM: %d", con_info.psm); + l2cu_reject_connection (p_lcb, rcid, id, L2CAP_CONN_NO_PSM); + break; + } + else + { + if (!p_rcb->api.pL2CA_ConnectInd_Cb) + { + L2CAP_TRACE_WARNING ("L2CAP - rcvd conn req for outgoing-only connection PSM: %d", con_info.psm); + l2cu_reject_connection (p_lcb, rcid, id, L2CAP_CONN_NO_PSM); + break; + } + } + if ((p_ccb = l2cu_allocate_ccb (p_lcb, 0)) == NULL) + { + L2CAP_TRACE_ERROR ("L2CAP - unable to allocate CCB"); + l2cu_reject_connection (p_lcb, rcid, id, L2CAP_CONN_NO_RESOURCES); + break; + } + p_ccb->remote_id = id; + p_ccb->p_rcb = p_rcb; + p_ccb->remote_cid = rcid; + + l2c_csm_execute(p_ccb, L2CEVT_L2CAP_CONNECT_REQ, &con_info); + break; + + case L2CAP_CMD_CONN_RSP: + STREAM_TO_UINT16 (con_info.remote_cid, p); + STREAM_TO_UINT16 (lcid, p); + STREAM_TO_UINT16 (con_info.l2cap_result, p); + STREAM_TO_UINT16 (con_info.l2cap_status, p); + + if ((p_ccb = l2cu_find_ccb_by_cid (p_lcb, lcid)) == NULL) + { + L2CAP_TRACE_WARNING ("L2CAP - no CCB for conn rsp, LCID: %d RCID: %d", + lcid, con_info.remote_cid); + break; + } + if (p_ccb->local_id != id) + { + L2CAP_TRACE_WARNING ("L2CAP - con rsp - bad ID. Exp: %d Got: %d", + p_ccb->local_id, id); + break; + } + + if (con_info.l2cap_result == L2CAP_CONN_OK) + l2c_csm_execute(p_ccb, L2CEVT_L2CAP_CONNECT_RSP, &con_info); + else if (con_info.l2cap_result == L2CAP_CONN_PENDING) + l2c_csm_execute(p_ccb, L2CEVT_L2CAP_CONNECT_RSP_PND, &con_info); + else + l2c_csm_execute(p_ccb, L2CEVT_L2CAP_CONNECT_RSP_NEG, &con_info); + + break; + + case L2CAP_CMD_CONFIG_REQ: + p_cfg_end = p + cmd_len; + cfg_rej = FALSE; + cfg_rej_len = 0; + + STREAM_TO_UINT16 (lcid, p); + STREAM_TO_UINT16 (cfg_info.flags, p); + + p_cfg_start = p; + + cfg_info.flush_to_present = cfg_info.mtu_present = cfg_info.qos_present = + cfg_info.fcr_present = cfg_info.fcs_present = FALSE; + + while (p < p_cfg_end) + { + STREAM_TO_UINT8 (cfg_code, p); + STREAM_TO_UINT8 (cfg_len, p); + + switch (cfg_code & 0x7F) + { + case L2CAP_CFG_TYPE_MTU: + cfg_info.mtu_present = TRUE; + STREAM_TO_UINT16 (cfg_info.mtu, p); + break; + + case L2CAP_CFG_TYPE_FLUSH_TOUT: + cfg_info.flush_to_present = TRUE; + STREAM_TO_UINT16 (cfg_info.flush_to, p); + break; + + case L2CAP_CFG_TYPE_QOS: + cfg_info.qos_present = TRUE; + STREAM_TO_UINT8 (cfg_info.qos.qos_flags, p); + STREAM_TO_UINT8 (cfg_info.qos.service_type, p); + STREAM_TO_UINT32 (cfg_info.qos.token_rate, p); + STREAM_TO_UINT32 (cfg_info.qos.token_bucket_size, p); + STREAM_TO_UINT32 (cfg_info.qos.peak_bandwidth, p); + STREAM_TO_UINT32 (cfg_info.qos.latency, p); + STREAM_TO_UINT32 (cfg_info.qos.delay_variation, p); + break; + + case L2CAP_CFG_TYPE_FCR: + cfg_info.fcr_present = TRUE; + STREAM_TO_UINT8 (cfg_info.fcr.mode, p); + STREAM_TO_UINT8 (cfg_info.fcr.tx_win_sz, p); + STREAM_TO_UINT8 (cfg_info.fcr.max_transmit, p); + STREAM_TO_UINT16 (cfg_info.fcr.rtrans_tout, p); + STREAM_TO_UINT16 (cfg_info.fcr.mon_tout, p); + STREAM_TO_UINT16 (cfg_info.fcr.mps, p); + break; + + case L2CAP_CFG_TYPE_FCS: + cfg_info.fcs_present = TRUE; + STREAM_TO_UINT8 (cfg_info.fcs, p); + break; + + case L2CAP_CFG_TYPE_EXT_FLOW: + cfg_info.ext_flow_spec_present = TRUE; + STREAM_TO_UINT8 (cfg_info.ext_flow_spec.id, p); + STREAM_TO_UINT8 (cfg_info.ext_flow_spec.stype, p); + STREAM_TO_UINT16 (cfg_info.ext_flow_spec.max_sdu_size, p); + STREAM_TO_UINT32 (cfg_info.ext_flow_spec.sdu_inter_time, p); + STREAM_TO_UINT32 (cfg_info.ext_flow_spec.access_latency, p); + STREAM_TO_UINT32 (cfg_info.ext_flow_spec.flush_timeout, p); + break; + + default: + /* sanity check option length */ + if ((cfg_len + L2CAP_CFG_OPTION_OVERHEAD) <= cmd_len) + { + p += cfg_len; + if ((cfg_code & 0x80) == 0) + { + cfg_rej_len += cfg_len + L2CAP_CFG_OPTION_OVERHEAD; + cfg_rej = TRUE; + } + } + /* bad length; force loop exit */ + else + { + p = p_cfg_end; + cfg_rej = TRUE; + } + break; + } + } + + if ((p_ccb = l2cu_find_ccb_by_cid (p_lcb, lcid)) != NULL) + { + p_ccb->remote_id = id; + if (cfg_rej) + { + l2cu_send_peer_config_rej (p_ccb, p_cfg_start, (UINT16) (cmd_len - L2CAP_CONFIG_REQ_LEN), cfg_rej_len); + } + else + { + l2c_csm_execute (p_ccb, L2CEVT_L2CAP_CONFIG_REQ, &cfg_info); + } + } + else + { + /* updated spec says send command reject on invalid cid */ + l2cu_send_peer_cmd_reject (p_lcb, L2CAP_CMD_REJ_INVALID_CID, id, 0, 0); + } + break; + + case L2CAP_CMD_CONFIG_RSP: + p_cfg_end = p + cmd_len; + STREAM_TO_UINT16 (lcid, p); + STREAM_TO_UINT16 (cfg_info.flags, p); + STREAM_TO_UINT16 (cfg_info.result, p); + + cfg_info.flush_to_present = cfg_info.mtu_present = cfg_info.qos_present = + cfg_info.fcr_present = cfg_info.fcs_present = FALSE; + + while (p < p_cfg_end) + { + STREAM_TO_UINT8 (cfg_code, p); + STREAM_TO_UINT8 (cfg_len, p); + + switch (cfg_code & 0x7F) + { + case L2CAP_CFG_TYPE_MTU: + cfg_info.mtu_present = TRUE; + STREAM_TO_UINT16 (cfg_info.mtu, p); + break; + + case L2CAP_CFG_TYPE_FLUSH_TOUT: + cfg_info.flush_to_present = TRUE; + STREAM_TO_UINT16 (cfg_info.flush_to, p); + break; + + case L2CAP_CFG_TYPE_QOS: + cfg_info.qos_present = TRUE; + STREAM_TO_UINT8 (cfg_info.qos.qos_flags, p); + STREAM_TO_UINT8 (cfg_info.qos.service_type, p); + STREAM_TO_UINT32 (cfg_info.qos.token_rate, p); + STREAM_TO_UINT32 (cfg_info.qos.token_bucket_size, p); + STREAM_TO_UINT32 (cfg_info.qos.peak_bandwidth, p); + STREAM_TO_UINT32 (cfg_info.qos.latency, p); + STREAM_TO_UINT32 (cfg_info.qos.delay_variation, p); + break; + + case L2CAP_CFG_TYPE_FCR: + cfg_info.fcr_present = TRUE; + STREAM_TO_UINT8 (cfg_info.fcr.mode, p); + STREAM_TO_UINT8 (cfg_info.fcr.tx_win_sz, p); + STREAM_TO_UINT8 (cfg_info.fcr.max_transmit, p); + STREAM_TO_UINT16 (cfg_info.fcr.rtrans_tout, p); + STREAM_TO_UINT16 (cfg_info.fcr.mon_tout, p); + STREAM_TO_UINT16 (cfg_info.fcr.mps, p); + break; + + case L2CAP_CFG_TYPE_FCS: + cfg_info.fcs_present = TRUE; + STREAM_TO_UINT8 (cfg_info.fcs, p); + break; + + case L2CAP_CFG_TYPE_EXT_FLOW: + cfg_info.ext_flow_spec_present = TRUE; + STREAM_TO_UINT8 (cfg_info.ext_flow_spec.id, p); + STREAM_TO_UINT8 (cfg_info.ext_flow_spec.stype, p); + STREAM_TO_UINT16 (cfg_info.ext_flow_spec.max_sdu_size, p); + STREAM_TO_UINT32 (cfg_info.ext_flow_spec.sdu_inter_time, p); + STREAM_TO_UINT32 (cfg_info.ext_flow_spec.access_latency, p); + STREAM_TO_UINT32 (cfg_info.ext_flow_spec.flush_timeout, p); + break; + } + } + + if ((p_ccb = l2cu_find_ccb_by_cid (p_lcb, lcid)) != NULL) + { + if (p_ccb->local_id != id) + { + L2CAP_TRACE_WARNING ("L2CAP - cfg rsp - bad ID. Exp: %d Got: %d", + p_ccb->local_id, id); + break; + } + if ( (cfg_info.result == L2CAP_CFG_OK) || (cfg_info.result == L2CAP_CFG_PENDING) ) + l2c_csm_execute (p_ccb, L2CEVT_L2CAP_CONFIG_RSP, &cfg_info); + else + l2c_csm_execute (p_ccb, L2CEVT_L2CAP_CONFIG_RSP_NEG, &cfg_info); + } + else + { + L2CAP_TRACE_WARNING ("L2CAP - rcvd cfg rsp for unknown CID: 0x%04x", lcid); + } + break; + + + case L2CAP_CMD_DISC_REQ: + STREAM_TO_UINT16 (lcid, p); + STREAM_TO_UINT16 (rcid, p); + + if ((p_ccb = l2cu_find_ccb_by_cid (p_lcb, lcid)) != NULL) + { + if (p_ccb->remote_cid == rcid) + { + p_ccb->remote_id = id; + l2c_csm_execute (p_ccb, L2CEVT_L2CAP_DISCONNECT_REQ, &con_info); + } + } + else + l2cu_send_peer_disc_rsp (p_lcb, id, lcid, rcid); + + break; + + case L2CAP_CMD_DISC_RSP: + STREAM_TO_UINT16 (rcid, p); + STREAM_TO_UINT16 (lcid, p); + + if ((p_ccb = l2cu_find_ccb_by_cid (p_lcb, lcid)) != NULL) + { + if ((p_ccb->remote_cid == rcid) && (p_ccb->local_id == id)) + { + l2c_csm_execute (p_ccb, L2CEVT_L2CAP_DISCONNECT_RSP, &con_info); + } + } + break; + + case L2CAP_CMD_ECHO_REQ: + l2cu_send_peer_echo_rsp (p_lcb, id, NULL, 0); + break; + + case L2CAP_CMD_ECHO_RSP: + if (p_lcb->p_echo_rsp_cb) + { + tL2CA_ECHO_RSP_CB *p_cb = p_lcb->p_echo_rsp_cb; + + /* Zero out the callback in case app immediately calls us again */ + p_lcb->p_echo_rsp_cb = NULL; + + (*p_cb) (L2CAP_PING_RESULT_OK); + } + break; + + case L2CAP_CMD_INFO_REQ: + STREAM_TO_UINT16 (info_type, p); + l2cu_send_peer_info_rsp (p_lcb, id, info_type); + break; + + case L2CAP_CMD_INFO_RSP: + /* Stop the link connect timer if sent before L2CAP connection is up */ + if (p_lcb->w4_info_rsp) + { + btu_stop_timer (&p_lcb->info_timer_entry); + p_lcb->w4_info_rsp = FALSE; + } + + STREAM_TO_UINT16 (info_type, p); + STREAM_TO_UINT16 (result, p); + + p_lcb->info_rx_bits |= (1 << info_type); + + if ( (info_type == L2CAP_EXTENDED_FEATURES_INFO_TYPE) + && (result == L2CAP_INFO_RESP_RESULT_SUCCESS) ) + { + STREAM_TO_UINT32( p_lcb->peer_ext_fea, p ); + +#if (L2CAP_NUM_FIXED_CHNLS > 0) + if (p_lcb->peer_ext_fea & L2CAP_EXTFEA_FIXED_CHNLS) + { + l2cu_send_peer_info_req (p_lcb, L2CAP_FIXED_CHANNELS_INFO_TYPE); + break; + } + else + { + l2cu_process_fixed_chnl_resp (p_lcb); + } +#endif + } + + +#if (L2CAP_NUM_FIXED_CHNLS > 0) + if (info_type == L2CAP_FIXED_CHANNELS_INFO_TYPE) + { + if (result == L2CAP_INFO_RESP_RESULT_SUCCESS) + { + memcpy (p_lcb->peer_chnl_mask, p, L2CAP_FIXED_CHNL_ARRAY_SIZE); + } + + l2cu_process_fixed_chnl_resp (p_lcb); + } +#endif +#if (L2CAP_UCD_INCLUDED == TRUE) + else if (info_type == L2CAP_CONNLESS_MTU_INFO_TYPE) + { + if (result == L2CAP_INFO_RESP_RESULT_SUCCESS) + { + STREAM_TO_UINT16 (p_lcb->ucd_mtu, p); + } + } +#endif + + ci.status = HCI_SUCCESS; + memcpy (ci.bd_addr, p_lcb->remote_bd_addr, sizeof(BD_ADDR)); + for (p_ccb = p_lcb->ccb_queue.p_first_ccb; p_ccb; p_ccb = p_ccb->p_next_ccb) + { + l2c_csm_execute (p_ccb, L2CEVT_L2CAP_INFO_RSP, &ci); + } + break; + + default: + L2CAP_TRACE_WARNING ("L2CAP - bad cmd code: %d", cmd_code); + l2cu_send_peer_cmd_reject (p_lcb, L2CAP_CMD_REJ_NOT_UNDERSTOOD, id, 0, 0); + return; + } + } +} + +/******************************************************************************* +** +** Function l2c_process_held_packets +** +** Description This function processes any L2CAP packets that arrived before +** the HCI connection complete arrived. It is a work around for +** badly behaved controllers. +** +** Returns void +** +*******************************************************************************/ +void l2c_process_held_packets(BOOLEAN timed_out) { + if (list_is_empty(l2cb.rcv_pending_q)) + return; + + if (!timed_out) { + btu_stop_timer(&l2cb.rcv_hold_tle); + L2CAP_TRACE_WARNING("L2CAP HOLD CONTINUE"); + } else { + L2CAP_TRACE_WARNING("L2CAP HOLD TIMEOUT"); + } + + for (const list_node_t *node = list_begin(l2cb.rcv_pending_q); + node != list_end(l2cb.rcv_pending_q);) { + BT_HDR *p_buf = list_node(node); + node = list_next(node); + if (!timed_out || (!p_buf->layer_specific) || (--p_buf->layer_specific == 0)) { + list_remove(l2cb.rcv_pending_q, p_buf); + p_buf->layer_specific = 0xFFFF; + l2c_rcv_acl_data(p_buf); + } + } + + /* If anyone still in the queue, restart the timeout */ + if (!list_is_empty(l2cb.rcv_pending_q)) + btu_start_timer (&l2cb.rcv_hold_tle, BTU_TTYPE_L2CAP_HOLD, BT_1SEC_TIMEOUT); +} + + +/******************************************************************************* +** +** Function l2c_init +** +** Description This function is called once at startup to initialize +** all the L2CAP structures +** +** Returns void +** +*******************************************************************************/ +void l2c_init (void) +{ + INT16 xx; + + memset (&l2cb, 0, sizeof (tL2C_CB)); + /* the psm is increased by 2 before being used */ + l2cb.dyn_psm = 0xFFF; + + /* Put all the channel control blocks on the free queue */ + for (xx = 0; xx < MAX_L2CAP_CHANNELS - 1; xx++) + { + l2cb.ccb_pool[xx].p_next_ccb = &l2cb.ccb_pool[xx + 1]; + } + +#if (L2CAP_NON_FLUSHABLE_PB_INCLUDED == TRUE) + /* it will be set to L2CAP_PKT_START_NON_FLUSHABLE if controller supports */ + l2cb.non_flushable_pbf = L2CAP_PKT_START << L2CAP_PKT_TYPE_SHIFT; +#endif + + + l2cb.p_free_ccb_first = &l2cb.ccb_pool[0]; + l2cb.p_free_ccb_last = &l2cb.ccb_pool[MAX_L2CAP_CHANNELS - 1]; + +#ifdef L2CAP_DESIRED_LINK_ROLE + l2cb.desire_role = L2CAP_DESIRED_LINK_ROLE; +#else + l2cb.desire_role = HCI_ROLE_SLAVE; +#endif + + /* Set the default idle timeout */ + l2cb.idle_timeout = L2CAP_LINK_INACTIVITY_TOUT; + +#if defined(L2CAP_INITIAL_TRACE_LEVEL) + l2cb.l2cap_trace_level = L2CAP_INITIAL_TRACE_LEVEL; +#else + l2cb.l2cap_trace_level = BT_TRACE_LEVEL_NONE; /* No traces */ +#endif + +#if L2CAP_CONFORMANCE_TESTING == TRUE + /* Conformance testing needs a dynamic response */ + l2cb.test_info_resp = L2CAP_EXTFEA_SUPPORTED_MASK; +#endif + + /* Number of ACL buffers to use for high priority channel */ +#if (defined(L2CAP_HIGH_PRI_CHAN_QUOTA_IS_CONFIGURABLE) && (L2CAP_HIGH_PRI_CHAN_QUOTA_IS_CONFIGURABLE == TRUE)) + l2cb.high_pri_min_xmit_quota = L2CAP_HIGH_PRI_MIN_XMIT_QUOTA; +#endif + +#if BLE_INCLUDED == TRUE + l2cb.l2c_ble_fixed_chnls_mask = + L2CAP_FIXED_CHNL_ATT_BIT | L2CAP_FIXED_CHNL_BLE_SIG_BIT | L2CAP_FIXED_CHNL_SMP_BIT; +#endif + + l2cb.rcv_pending_q = list_new(NULL); + if (l2cb.rcv_pending_q == NULL) + LOG_ERROR("%s unable to allocate memory for link layer control block", __func__); +} + +void l2c_free(void) { + list_free(l2cb.rcv_pending_q); +} + +/******************************************************************************* +** +** Function l2c_process_timeout +** +** Description This function is called when an L2CAP-related timeout occurs +** +** Returns void +** +*******************************************************************************/ +void l2c_process_timeout (TIMER_LIST_ENT *p_tle) +{ + /* What type of timeout ? */ + switch (p_tle->event) + { + case BTU_TTYPE_L2CAP_LINK: + l2c_link_timeout ((tL2C_LCB *)p_tle->param); + break; + + case BTU_TTYPE_L2CAP_CHNL: + l2c_csm_execute (((tL2C_CCB *)p_tle->param), L2CEVT_TIMEOUT, NULL); + break; + + case BTU_TTYPE_L2CAP_FCR_ACK: + l2c_csm_execute (((tL2C_CCB *)p_tle->param), L2CEVT_ACK_TIMEOUT, NULL); + break; + + case BTU_TTYPE_L2CAP_HOLD: + /* Update the timeouts in the hold queue */ + l2c_process_held_packets(TRUE); + break; + + case BTU_TTYPE_L2CAP_INFO: + l2c_info_timeout((tL2C_LCB *)p_tle->param); + break; + } +} + +/******************************************************************************* +** +** Function l2c_data_write +** +** Description API functions call this function to write data. +** +** Returns L2CAP_DW_SUCCESS, if data accepted, else FALSE +** L2CAP_DW_CONGESTED, if data accepted and the channel is congested +** L2CAP_DW_FAILED, if error +** +*******************************************************************************/ +UINT8 l2c_data_write (UINT16 cid, BT_HDR *p_data, UINT16 flags) +{ + tL2C_CCB *p_ccb; + + /* Find the channel control block. We don't know the link it is on. */ + if ((p_ccb = l2cu_find_ccb_by_cid (NULL, cid)) == NULL) + { + L2CAP_TRACE_WARNING ("L2CAP - no CCB for L2CA_DataWrite, CID: %d", cid); + GKI_freebuf (p_data); + return (L2CAP_DW_FAILED); + } + +#ifndef TESTER /* Tester may send any amount of data. otherwise sending message + bigger than mtu size of peer is a violation of protocol */ + if (p_data->len > p_ccb->peer_cfg.mtu) + { + L2CAP_TRACE_WARNING ("L2CAP - CID: 0x%04x cannot send message bigger than peer's mtu size", cid); + GKI_freebuf (p_data); + return (L2CAP_DW_FAILED); + } +#endif + + /* channel based, packet based flushable or non-flushable */ + p_data->layer_specific = flags; + + /* If already congested, do not accept any more packets */ + if (p_ccb->cong_sent) + { + L2CAP_TRACE_ERROR ("L2CAP - CID: 0x%04x cannot send, already congested xmit_hold_q.count: %u buff_quota: %u", + p_ccb->local_cid, GKI_queue_length(&p_ccb->xmit_hold_q), p_ccb->buff_quota); + + GKI_freebuf (p_data); + return (L2CAP_DW_FAILED); + } + + //counter_add("l2cap.dyn.tx.bytes", p_data->len); + //counter_add("l2cap.dyn.tx.pkts", 1); + + l2c_csm_execute (p_ccb, L2CEVT_L2CA_DATA_WRITE, p_data); + + if (p_ccb->cong_sent) + return (L2CAP_DW_CONGESTED); + + return (L2CAP_DW_SUCCESS); +} + diff --git a/components/bt/bluedroid/stack/l2cap/l2c_ucd.c b/components/bt/bluedroid/stack/l2cap/l2c_ucd.c new file mode 100755 index 0000000000..8118a708c4 --- /dev/null +++ b/components/bt/bluedroid/stack/l2cap/l2c_ucd.c @@ -0,0 +1,1170 @@ +/****************************************************************************** + * + * Copyright (C) 1999-2012 Broadcom Corporation + * + * 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 L2CAP UCD code + * + ******************************************************************************/ + +#include +#include +//#include + +#include "gki.h" +#include "bt_types.h" +#include "hcidefs.h" +#include "hcimsgs.h" +#include "l2cdefs.h" +#include "l2c_int.h" +#include "btu.h" +#include "btm_api.h" +#include "btm_int.h" + +#if (L2CAP_UCD_INCLUDED == TRUE) +static BOOLEAN l2c_ucd_connect ( BD_ADDR rem_bda ); + +/******************************************************************************* +** +** Function l2c_ucd_discover_cback +** +** Description UCD Discover callback +** +** Returns void +** +*******************************************************************************/ +static void l2c_ucd_discover_cback (BD_ADDR rem_bda, UINT8 info_type, UINT32 data) +{ + tL2C_RCB *p_rcb = &l2cb.rcb_pool[0]; + UINT16 xx; + + L2CAP_TRACE_DEBUG ("L2CAP - l2c_ucd_discover_cback"); + + for (xx = 0; xx < MAX_L2CAP_CLIENTS; xx++, p_rcb++) + { + if (p_rcb->in_use) + { + /* if this application is waiting UCD reception info */ + if (( info_type == L2CAP_UCD_INFO_TYPE_RECEPTION ) + && ( p_rcb->ucd.state & L2C_UCD_STATE_W4_RECEPTION )) + { + p_rcb->ucd.cb_info.pL2CA_UCD_Discover_Cb (rem_bda, info_type, data); + p_rcb->ucd.state &= ~(L2C_UCD_STATE_W4_RECEPTION); + } + + /* if this application is waiting UCD MTU info */ + if (( info_type == L2CAP_UCD_INFO_TYPE_MTU ) + && ( p_rcb->ucd.state & L2C_UCD_STATE_W4_MTU )) + { + p_rcb->ucd.cb_info.pL2CA_UCD_Discover_Cb (rem_bda, info_type, data); + p_rcb->ucd.state &= ~(L2C_UCD_STATE_W4_MTU); + } + } + } +} + +/******************************************************************************* +** +** Function l2c_ucd_data_ind_cback +** +** Description UCD Data callback +** +** Returns void +** +*******************************************************************************/ +static void l2c_ucd_data_ind_cback (BD_ADDR rem_bda, BT_HDR *p_buf) +{ + UINT8 *p; + UINT16 psm; + tL2C_RCB *p_rcb; + + L2CAP_TRACE_DEBUG ("L2CAP - l2c_ucd_data_ind_cback"); + + p = (UINT8 *)(p_buf + 1) + p_buf->offset; + STREAM_TO_UINT16(psm, p) + + p_buf->offset += L2CAP_UCD_OVERHEAD; + p_buf->len -= L2CAP_UCD_OVERHEAD; + + if ((p_rcb = l2cu_find_rcb_by_psm (psm)) == NULL) + { + L2CAP_TRACE_ERROR ("L2CAP - no RCB for l2c_ucd_data_ind_cback, PSM: 0x%04x", psm); + GKI_freebuf (p_buf); + } + else + { + p_rcb->ucd.cb_info.pL2CA_UCD_Data_Cb(rem_bda, p_buf); + } +} + +/******************************************************************************* +** +** Function l2c_ucd_congestion_status_cback +** +** Description UCD Congestion Status callback +** +** Returns void +** +*******************************************************************************/ +static void l2c_ucd_congestion_status_cback (BD_ADDR rem_bda, BOOLEAN is_congested) +{ + tL2C_RCB *p_rcb = &l2cb.rcb_pool[0]; + UINT16 xx; + + L2CAP_TRACE_DEBUG ("L2CAP - l2c_ucd_congestion_status_cback"); + + for (xx = 0; xx < MAX_L2CAP_CLIENTS; xx++, p_rcb++) + { + if (( p_rcb->in_use ) + &&( p_rcb->ucd.state != L2C_UCD_STATE_UNUSED )) + { + if ( p_rcb->ucd.cb_info.pL2CA_UCD_Congestion_Status_Cb ) + { + L2CAP_TRACE_DEBUG ("L2CAP - Calling UCDCongestionStatus_Cb (%d), PSM=0x%04x, BDA: %08x%04x,", + is_congested, p_rcb->psm, + (rem_bda[0]<<24)+(rem_bda[1]<<16)+(rem_bda[2]<<8)+rem_bda[3], + (rem_bda[4]<<8)+rem_bda[5]); + + p_rcb->ucd.cb_info.pL2CA_UCD_Congestion_Status_Cb ( rem_bda, is_congested ); + } + } + } +} + +/******************************************************************************* +** +** Function l2c_ucd_disconnect_ind_cback +** +** Description UCD disconnect callback (This prevent to access null pointer) +** +** Returns void +** +*******************************************************************************/ +static void l2c_ucd_disconnect_ind_cback (UINT16 cid, BOOLEAN result) +{ + /* do nothing */ +} + +/******************************************************************************* +** +** Function l2c_ucd_config_ind_cback +** +** Description UCD config callback (This prevent to access null pointer) +** +** Returns void +** +*******************************************************************************/ +static void l2c_ucd_config_ind_cback (UINT16 cid, tL2CAP_CFG_INFO *p_cfg) +{ + /* do nothing */ +} + +/******************************************************************************* +** +** Function l2c_ucd_config_cfm_cback +** +** Description UCD config callback (This prevent to access null pointer) +** +** Returns void +** +*******************************************************************************/ +static void l2c_ucd_config_cfm_cback (UINT16 cid, tL2CAP_CFG_INFO *p_cfg) +{ + /* do nothing */ +} + +/******************************************************************************* +** +** Function L2CA_UcdRegister +** +** Description Register PSM on UCD. +** +** Parameters: tL2CAP_UCD_CB_INFO +** +** Return value: TRUE if successs +** +*******************************************************************************/ +BOOLEAN L2CA_UcdRegister ( UINT16 psm, tL2CAP_UCD_CB_INFO *p_cb_info ) +{ + tL2C_RCB *p_rcb; + + L2CAP_TRACE_API ("L2CA_UcdRegister() PSM: 0x%04x", psm); + + if ((!p_cb_info->pL2CA_UCD_Discover_Cb) + || (!p_cb_info->pL2CA_UCD_Data_Cb)) + { + L2CAP_TRACE_ERROR ("L2CAP - no callback registering PSM(0x%04x) on UCD", psm); + return (FALSE); + } + + if ((p_rcb = l2cu_find_rcb_by_psm (psm)) == NULL) + { + L2CAP_TRACE_ERROR ("L2CAP - no RCB for L2CA_UcdRegister, PSM: 0x%04x", psm); + return (FALSE); + } + + p_rcb->ucd.state = L2C_UCD_STATE_W4_DATA; + p_rcb->ucd.cb_info = *p_cb_info; + + /* check if master rcb is created for UCD */ + if ((p_rcb = l2cu_find_rcb_by_psm (L2C_UCD_RCB_ID)) == NULL) + { + if ((p_rcb = l2cu_allocate_rcb (L2C_UCD_RCB_ID)) == NULL) + { + L2CAP_TRACE_ERROR ("L2CAP - no RCB available for L2CA_UcdRegister"); + return (FALSE); + } + else + { + /* these callback functions will forward data to each UCD application */ + p_rcb->ucd.cb_info.pL2CA_UCD_Discover_Cb = l2c_ucd_discover_cback; + p_rcb->ucd.cb_info.pL2CA_UCD_Data_Cb = l2c_ucd_data_ind_cback; + p_rcb->ucd.cb_info.pL2CA_UCD_Congestion_Status_Cb = l2c_ucd_congestion_status_cback; + + memset (&p_rcb->api, 0, sizeof(tL2CAP_APPL_INFO)); + p_rcb->api.pL2CA_DisconnectInd_Cb = l2c_ucd_disconnect_ind_cback; + + /* This will make L2CAP check UCD congestion callback */ + p_rcb->api.pL2CA_CongestionStatus_Cb = NULL; + + /* do nothing but prevent crash */ + p_rcb->api.pL2CA_ConfigInd_Cb = l2c_ucd_config_ind_cback; + p_rcb->api.pL2CA_ConfigCfm_Cb = l2c_ucd_config_cfm_cback; + } + } + + return (TRUE); +} + +/******************************************************************************* +** +** Function L2CA_UcdDeregister +** +** Description Deregister PSM on UCD. +** +** Parameters: PSM +** +** Return value: TRUE if successs +** +*******************************************************************************/ +BOOLEAN L2CA_UcdDeregister ( UINT16 psm ) +{ + tL2C_CCB *p_ccb; + tL2C_RCB *p_rcb; + UINT16 xx; + + L2CAP_TRACE_API ("L2CA_UcdDeregister() PSM: 0x%04x", psm); + + if ((p_rcb = l2cu_find_rcb_by_psm (psm)) == NULL) + { + L2CAP_TRACE_ERROR ("L2CAP - no RCB for L2CA_UcdDeregister, PSM: 0x%04x", psm); + return (FALSE); + } + + p_rcb->ucd.state = L2C_UCD_STATE_UNUSED; + + /* check this was the last UCD registration */ + p_rcb = &l2cb.rcb_pool[0]; + + for (xx = 0; xx < MAX_L2CAP_CLIENTS; xx++, p_rcb++) + { + if ((p_rcb->in_use) && (p_rcb->ucd.state != L2C_UCD_STATE_UNUSED)) + return (TRUE); + } + + /* delete master rcb for UCD */ + if ((p_rcb = l2cu_find_rcb_by_psm (L2C_UCD_RCB_ID)) != NULL) + { + l2cu_release_rcb (p_rcb); + } + + /* delete CCB for UCD */ + p_ccb = l2cb.ccb_pool; + for ( xx = 0; xx < MAX_L2CAP_CHANNELS; xx++ ) + { + if (( p_ccb->in_use ) + &&( p_ccb->local_cid == L2CAP_CONNECTIONLESS_CID )) + { + l2cu_release_ccb (p_ccb); + } + p_ccb++; + } + + return (TRUE); +} + +/******************************************************************************* +** +** Function L2CA_UcdDiscover +** +** Description Discover UCD of remote device. +** +** Parameters: PSM +** BD_ADDR of remote device +** info_type : L2CAP_UCD_INFO_TYPE_RECEPTION +** L2CAP_UCD_INFO_TYPE_MTU +** +** +** Return value: TRUE if successs +** +*******************************************************************************/ +BOOLEAN L2CA_UcdDiscover ( UINT16 psm, BD_ADDR rem_bda, UINT8 info_type ) +{ + tL2C_LCB *p_lcb; + tL2C_CCB *p_ccb; + tL2C_RCB *p_rcb; + + L2CAP_TRACE_API ("L2CA_UcdDiscover() PSM: 0x%04x BDA: %08x%04x, InfoType=0x%02x", psm, + (rem_bda[0]<<24)+(rem_bda[1]<<16)+(rem_bda[2]<<8)+rem_bda[3], + (rem_bda[4]<<8)+rem_bda[5], info_type); + + /* Fail if the PSM is not registered */ + if (((p_rcb = l2cu_find_rcb_by_psm (psm)) == NULL) + ||( p_rcb->ucd.state == L2C_UCD_STATE_UNUSED )) + { + L2CAP_TRACE_WARNING ("L2CAP - no RCB for L2CA_UcdDiscover, PSM: 0x%04x", psm); + return (FALSE); + } + + /* First, see if we already have a link to the remote */ + /* then find the channel control block for UCD. */ + if (((p_lcb = l2cu_find_lcb_by_bd_addr (rem_bda, BT_TRANSPORT_BR_EDR)) == NULL) + ||((p_ccb = l2cu_find_ccb_by_cid (p_lcb, L2CAP_CONNECTIONLESS_CID)) == NULL)) + { + if ( l2c_ucd_connect (rem_bda) == FALSE ) + { + return (FALSE); + } + } + + /* set waiting flags in rcb */ + + if ( info_type & L2CAP_UCD_INFO_TYPE_RECEPTION ) + p_rcb->ucd.state |= L2C_UCD_STATE_W4_RECEPTION; + + if ( info_type & L2CAP_UCD_INFO_TYPE_MTU ) + p_rcb->ucd.state |= L2C_UCD_STATE_W4_MTU; + + /* if link is already established */ + if ((p_lcb)&&(p_lcb->link_state == LST_CONNECTED)) + { + if (!p_ccb) + { + p_ccb = l2cu_find_ccb_by_cid (p_lcb, L2CAP_CONNECTIONLESS_CID); + } + l2c_ucd_check_pending_info_req(p_ccb); + } + return (TRUE); +} + +/******************************************************************************* +** +** Function L2CA_UcdDataWrite +** +** Description Send UCD to remote device +** +** Parameters: PSM +** BD Address of remote +** Pointer to buffer of type BT_HDR +** flags : L2CAP_FLUSHABLE_CH_BASED +** L2CAP_FLUSHABLE_PKT +** L2CAP_NON_FLUSHABLE_PKT +** +** Return value L2CAP_DW_SUCCESS, if data accepted +** L2CAP_DW_FAILED, if error +** +*******************************************************************************/ +UINT16 L2CA_UcdDataWrite (UINT16 psm, BD_ADDR rem_bda, BT_HDR *p_buf, UINT16 flags) +{ + tL2C_LCB *p_lcb; + tL2C_CCB *p_ccb; + tL2C_RCB *p_rcb; + UINT8 *p; + + L2CAP_TRACE_API ("L2CA_UcdDataWrite() PSM: 0x%04x BDA: %08x%04x", psm, + (rem_bda[0]<<24)+(rem_bda[1]<<16)+(rem_bda[2]<<8)+rem_bda[3], + (rem_bda[4]<<8)+rem_bda[5]); + + /* Fail if the PSM is not registered */ + if (((p_rcb = l2cu_find_rcb_by_psm (psm)) == NULL) + ||( p_rcb->ucd.state == L2C_UCD_STATE_UNUSED )) + { + L2CAP_TRACE_WARNING ("L2CAP - no RCB for L2CA_UcdDataWrite, PSM: 0x%04x", psm); + GKI_freebuf (p_buf); + return (L2CAP_DW_FAILED); + } + + /* First, see if we already have a link to the remote */ + /* then find the channel control block for UCD */ + if (((p_lcb = l2cu_find_lcb_by_bd_addr (rem_bda, BT_TRANSPORT_BR_EDR)) == NULL) + ||((p_ccb = l2cu_find_ccb_by_cid (p_lcb, L2CAP_CONNECTIONLESS_CID)) == NULL)) + { + if ( l2c_ucd_connect (rem_bda) == FALSE ) + { + GKI_freebuf (p_buf); + return (L2CAP_DW_FAILED); + } + + /* If we still don't have lcb and ccb after connect attempt, then can't proceed */ + if (((p_lcb = l2cu_find_lcb_by_bd_addr (rem_bda, BT_TRANSPORT_BR_EDR)) == NULL) + || ((p_ccb = l2cu_find_ccb_by_cid (p_lcb, L2CAP_CONNECTIONLESS_CID)) == NULL)) + { + GKI_freebuf (p_buf); + return (L2CAP_DW_FAILED); + } + } + + /* write PSM */ + p_buf->offset -= L2CAP_UCD_OVERHEAD; + p_buf->len += L2CAP_UCD_OVERHEAD; + p = (UINT8 *)(p_buf + 1) + p_buf->offset; + + UINT16_TO_STREAM (p, psm); + + /* UCD MTU check */ + if ((p_lcb->ucd_mtu) && (p_buf->len > p_lcb->ucd_mtu)) + { + L2CAP_TRACE_WARNING ("L2CAP - Handle: 0x%04x UCD bigger than peer's UCD mtu size cannot be sent", p_lcb->handle); + GKI_freebuf (p_buf); + return (L2CAP_DW_FAILED); + } + + /* If already congested, do not accept any more packets */ + if (p_ccb->cong_sent) + { + L2CAP_TRACE_ERROR ("L2CAP - Handle: 0x%04x UCD cannot be sent, already congested count: %u buff_quota: %u", + p_lcb->handle, + (p_ccb->xmit_hold_q.count + p_lcb->ucd_out_sec_pending_q.count), + p_ccb->buff_quota); + + GKI_freebuf (p_buf); + return (L2CAP_DW_FAILED); + } + + /* channel based, packet based flushable or non-flushable */ + p_buf->layer_specific = flags; + + l2c_csm_execute (p_ccb, L2CEVT_L2CA_DATA_WRITE, p_buf); + + if (p_ccb->cong_sent) + return (L2CAP_DW_CONGESTED); + else + return (L2CAP_DW_SUCCESS); +} + +/******************************************************************************* +** +** Function L2CA_UcdSetIdleTimeout +** +** Description Set UCD Idle timeout. +** +** Parameters: BD Addr +** Timeout in second +** +** Return value: TRUE if successs +** +*******************************************************************************/ +BOOLEAN L2CA_UcdSetIdleTimeout ( BD_ADDR rem_bda, UINT16 timeout ) +{ + tL2C_LCB *p_lcb; + tL2C_CCB *p_ccb; + + L2CAP_TRACE_API ("L2CA_UcdSetIdleTimeout() Timeout: 0x%04x BDA: %08x%04x", timeout, + (rem_bda[0]<<24)+(rem_bda[1]<<16)+(rem_bda[2]<<8)+rem_bda[3], + (rem_bda[4]<<8)+rem_bda[5]); + + /* First, see if we already have a link to the remote */ + /* then find the channel control block. */ + if (((p_lcb = l2cu_find_lcb_by_bd_addr (rem_bda, BT_TRANSPORT_BR_EDR)) == NULL) + ||((p_ccb = l2cu_find_ccb_by_cid (p_lcb, L2CAP_CONNECTIONLESS_CID)) == NULL)) + { + L2CAP_TRACE_WARNING ("L2CAP - no UCD channel"); + return (FALSE); + } + else + { + p_ccb->fixed_chnl_idle_tout = timeout; + return (TRUE); + } +} + +/******************************************************************************* +** +** Function L2CA_UCDSetTxPriority +** +** Description Sets the transmission priority for a connectionless channel. +** +** Returns TRUE if a valid channel, else FALSE +** +*******************************************************************************/ +BOOLEAN L2CA_UCDSetTxPriority ( BD_ADDR rem_bda, tL2CAP_CHNL_PRIORITY priority ) +{ + tL2C_LCB *p_lcb; + tL2C_CCB *p_ccb; + + L2CAP_TRACE_API ("L2CA_UCDSetTxPriority() priority: 0x%02x BDA: %08x%04x", priority, + (rem_bda[0]<<24)+(rem_bda[1]<<16)+(rem_bda[2]<<8)+rem_bda[3], + (rem_bda[4]<<8)+rem_bda[5]); + + if ((p_lcb = l2cu_find_lcb_by_bd_addr (rem_bda, BT_TRANSPORT_BR_EDR)) == NULL) + { + L2CAP_TRACE_WARNING ("L2CAP - no LCB for L2CA_UCDSetTxPriority"); + return (FALSE); + } + + /* Find the channel control block */ + if ((p_ccb = l2cu_find_ccb_by_cid (p_lcb, L2CAP_CONNECTIONLESS_CID)) == NULL) + { + L2CAP_TRACE_WARNING ("L2CAP - no CCB for L2CA_UCDSetTxPriority"); + return (FALSE); + } + + /* it will update the order of CCB in LCB by priority and update round robin service variables */ + l2cu_change_pri_ccb (p_ccb, priority); + + return (TRUE); +} + +/******************************************************************************* +** +** Function l2c_ucd_connect +** +** Description Connect UCD to remote device. +** +** Parameters: BD_ADDR of remote device +** +** Return value: TRUE if successs +** +*******************************************************************************/ +static BOOLEAN l2c_ucd_connect ( BD_ADDR rem_bda ) +{ + tL2C_LCB *p_lcb; + tL2C_CCB *p_ccb; + tL2C_RCB *p_rcb; + + L2CAP_TRACE_DEBUG ("l2c_ucd_connect() BDA: %08x%04x", + (rem_bda[0]<<24)+(rem_bda[1]<<16)+(rem_bda[2]<<8)+rem_bda[3], + (rem_bda[4]<<8)+rem_bda[5]); + + /* Fail if we have not established communications with the controller */ + if (!BTM_IsDeviceUp()) + { + L2CAP_TRACE_WARNING ("l2c_ucd_connect - BTU not ready"); + return (FALSE); + } + + /* First, see if we already have a link to the remote */ + if ((p_lcb = l2cu_find_lcb_by_bd_addr (rem_bda, BT_TRANSPORT_BR_EDR)) == NULL) + { + /* No link. Get an LCB and start link establishment */ + if ( ((p_lcb = l2cu_allocate_lcb (rem_bda, FALSE, BT_TRANSPORT_BR_EDR)) == NULL) + || (l2cu_create_conn(p_lcb, BT_TRANSPORT_BR_EDR) == FALSE) ) + { + L2CAP_TRACE_WARNING ("L2CAP - conn not started l2c_ucd_connect"); + return (FALSE); + } + } + else if ( p_lcb->info_rx_bits & (1 << L2CAP_EXTENDED_FEATURES_INFO_TYPE) ) + { + if (!(p_lcb->peer_ext_fea & L2CAP_EXTFEA_UCD_RECEPTION)) + { + L2CAP_TRACE_WARNING ("L2CAP - UCD is not supported by peer, l2c_ucd_connect"); + return (FALSE); + } + } + + /* Find the channel control block. */ + if ((p_ccb = l2cu_find_ccb_by_cid (p_lcb, L2CAP_CONNECTIONLESS_CID)) == NULL) + { + /* Allocate a channel control block */ + if ((p_ccb = l2cu_allocate_ccb (p_lcb, 0)) == NULL) + { + L2CAP_TRACE_WARNING ("L2CAP - no CCB for l2c_ucd_connect"); + return (FALSE); + } + else + { + /* Set CID for the connection */ + p_ccb->local_cid = L2CAP_CONNECTIONLESS_CID; + p_ccb->remote_cid = L2CAP_CONNECTIONLESS_CID; + + /* Set the default idle timeout value to use */ + p_ccb->fixed_chnl_idle_tout = L2CAP_UCD_IDLE_TIMEOUT; + + /* Set the default channel priority value to use */ + l2cu_change_pri_ccb (p_ccb, L2CAP_UCD_CH_PRIORITY); + + if ((p_rcb = l2cu_find_rcb_by_psm (L2C_UCD_RCB_ID)) == NULL) + { + L2CAP_TRACE_WARNING ("L2CAP - no UCD registered, l2c_ucd_connect"); + return (FALSE); + } + /* Save UCD registration info */ + p_ccb->p_rcb = p_rcb; + + /* There is no configuration, so if the link is up, the channel is up */ + if (p_lcb->link_state == LST_CONNECTED) + { + p_ccb->chnl_state = CST_OPEN; + } + } + } + + return (TRUE); +} + +/******************************************************************************* +** +** Function l2c_ucd_delete_sec_pending_q +** +** Description discard all of UCD packets in security pending queue +** +** Returns None +** +*******************************************************************************/ +void l2c_ucd_delete_sec_pending_q(tL2C_LCB *p_lcb) +{ + /* clean up any security pending UCD */ + while (p_lcb->ucd_out_sec_pending_q.p_first) + GKI_freebuf (GKI_dequeue (&p_lcb->ucd_out_sec_pending_q)); + + while (p_lcb->ucd_in_sec_pending_q.p_first) + GKI_freebuf (GKI_dequeue (&p_lcb->ucd_in_sec_pending_q)); +} + +/******************************************************************************* +** +** Function l2c_ucd_check_pending_info_req +** +** Description check if any application is waiting for UCD information +** +** Return TRUE if any pending UCD info request +** +*******************************************************************************/ +BOOLEAN l2c_ucd_check_pending_info_req(tL2C_CCB *p_ccb) +{ + tL2C_RCB *p_rcb = &l2cb.rcb_pool[0]; + UINT16 xx; + BOOLEAN pending = FALSE; + + if (p_ccb == NULL) + { + L2CAP_TRACE_ERROR ("L2CAP - NULL p_ccb in l2c_ucd_check_pending_info_req"); + return (FALSE); + } + + for (xx = 0; xx < MAX_L2CAP_CLIENTS; xx++, p_rcb++) + { + if (p_rcb->in_use) + { + /* if application is waiting UCD reception info */ + if (p_rcb->ucd.state & L2C_UCD_STATE_W4_RECEPTION) + { + /* if this information is available */ + if ( p_ccb->p_lcb->info_rx_bits & (1 << L2CAP_EXTENDED_FEATURES_INFO_TYPE) ) + { + if (!(p_ccb->p_lcb->peer_ext_fea & L2CAP_EXTFEA_UCD_RECEPTION)) + { + L2CAP_TRACE_WARNING ("L2CAP - UCD is not supported by peer, l2c_ucd_check_pending_info_req"); + + l2c_ucd_delete_sec_pending_q(p_ccb->p_lcb); + l2cu_release_ccb (p_ccb); + } + + p_ccb->p_rcb->ucd.cb_info.pL2CA_UCD_Discover_Cb (p_ccb->p_lcb->remote_bd_addr, + L2CAP_UCD_INFO_TYPE_RECEPTION, + p_ccb->p_lcb->peer_ext_fea & L2CAP_EXTFEA_UCD_RECEPTION); + } + else + { + pending = TRUE; + if (p_ccb->p_lcb->w4_info_rsp == FALSE) + { + l2cu_send_peer_info_req (p_ccb->p_lcb, L2CAP_EXTENDED_FEATURES_INFO_TYPE); + } + } + } + + /* if application is waiting for UCD MTU */ + if (p_rcb->ucd.state & L2C_UCD_STATE_W4_MTU) + { + /* if this information is available */ + if ( p_ccb->p_lcb->info_rx_bits & (1 << L2CAP_CONNLESS_MTU_INFO_TYPE)) + { + p_ccb->p_rcb->ucd.cb_info.pL2CA_UCD_Discover_Cb (p_ccb->p_lcb->remote_bd_addr, + L2CAP_UCD_INFO_TYPE_MTU, + p_ccb->p_lcb->ucd_mtu); + } + else + { + pending = TRUE; + if (p_ccb->p_lcb->w4_info_rsp == FALSE) + { + l2cu_send_peer_info_req (p_ccb->p_lcb, L2CAP_CONNLESS_MTU_INFO_TYPE); + } + } + } + } + } + return (pending); +} + +/******************************************************************************* +** +** Function l2c_ucd_enqueue_pending_out_sec_q +** +** Description enqueue outgoing UCD packet into security pending queue +** and check congestion +** +** Return None +** +*******************************************************************************/ +void l2c_ucd_enqueue_pending_out_sec_q(tL2C_CCB *p_ccb, void *p_data) +{ + GKI_enqueue (&p_ccb->p_lcb->ucd_out_sec_pending_q, p_data); + l2cu_check_channel_congestion (p_ccb); +} + +/******************************************************************************* +** +** Function l2c_ucd_check_pending_out_sec_q +** +** Description check outgoing security +** +** Return TRUE if any UCD packet for security +** +*******************************************************************************/ +BOOLEAN l2c_ucd_check_pending_out_sec_q(tL2C_CCB *p_ccb) +{ + UINT8 *p; + UINT16 psm; + BT_HDR *p_buf; + + if ( p_ccb->p_lcb->ucd_out_sec_pending_q.count ) + { + p_buf = (BT_HDR*)(p_ccb->p_lcb->ucd_out_sec_pending_q.p_first); + p = (UINT8 *)(p_buf + 1) + p_buf->offset; + STREAM_TO_UINT16(psm, p) + + p_ccb->chnl_state = CST_ORIG_W4_SEC_COMP; + btm_sec_l2cap_access_req (p_ccb->p_lcb->remote_bd_addr, psm, + p_ccb->p_lcb->handle, CONNLESS_ORIG, &l2c_link_sec_comp, p_ccb); + + return (TRUE); + } + return (FALSE); +} + +/******************************************************************************* +** +** Function l2c_ucd_send_pending_out_sec_q +** +** Description dequeue UCD packet from security pending queue and +** enqueue it into CCB +** +** Return None +** +*******************************************************************************/ +void l2c_ucd_send_pending_out_sec_q(tL2C_CCB *p_ccb) +{ + BT_HDR *p_buf; + + if ( p_ccb->p_lcb->ucd_out_sec_pending_q.count ) + { + p_buf = (BT_HDR*)GKI_dequeue (&p_ccb->p_lcb->ucd_out_sec_pending_q); + + l2c_enqueue_peer_data (p_ccb, (BT_HDR *)p_buf); + l2c_link_check_send_pkts (p_ccb->p_lcb, NULL, NULL); + } +} + +/******************************************************************************* +** +** Function l2c_ucd_discard_pending_out_sec_q +** +** Description dequeue UCD packet from security pending queue and +** discard it. +** +** Return None +** +*******************************************************************************/ +void l2c_ucd_discard_pending_out_sec_q(tL2C_CCB *p_ccb) +{ + BT_HDR *p_buf; + + p_buf = (BT_HDR*)GKI_dequeue (&p_ccb->p_lcb->ucd_out_sec_pending_q); + + /* we may need to report to application */ + + if (p_buf) + { + GKI_freebuf (p_buf); + } +} + +/******************************************************************************* +** +** Function l2c_ucd_check_pending_in_sec_q +** +** Description check incoming security +** +** Return TRUE if any UCD packet for security +** +*******************************************************************************/ +BOOLEAN l2c_ucd_check_pending_in_sec_q(tL2C_CCB *p_ccb) +{ + UINT8 *p; + UINT16 psm; + BT_HDR *p_buf; + + if ( p_ccb->p_lcb->ucd_in_sec_pending_q.count ) + { + p_buf = (BT_HDR*)(p_ccb->p_lcb->ucd_in_sec_pending_q.p_first); + p = (UINT8 *)(p_buf + 1) + p_buf->offset; + STREAM_TO_UINT16(psm, p) + + p_ccb->chnl_state = CST_TERM_W4_SEC_COMP; + btm_sec_l2cap_access_req (p_ccb->p_lcb->remote_bd_addr, psm, + p_ccb->p_lcb->handle, CONNLESS_TERM, &l2c_link_sec_comp, p_ccb); + + return (TRUE); + } + return (FALSE); +} + +/******************************************************************************* +** +** Function l2c_ucd_send_pending_in_sec_q +** +** Description dequeue UCD packet from security pending queue and +** send it to application +** +** Return None +** +*******************************************************************************/ +void l2c_ucd_send_pending_in_sec_q(tL2C_CCB *p_ccb) +{ + BT_HDR *p_buf; + + if ( p_ccb->p_lcb->ucd_in_sec_pending_q.count ) + { + p_buf = (BT_HDR*)GKI_dequeue (&p_ccb->p_lcb->ucd_in_sec_pending_q); + + p_ccb->p_rcb->ucd.cb_info.pL2CA_UCD_Data_Cb(p_ccb->p_lcb->remote_bd_addr, (BT_HDR *)p_buf); + } +} + +/******************************************************************************* +** +** Function l2c_ucd_discard_pending_in_sec_q +** +** Description dequeue UCD packet from security pending queue and +** discard it. +** +** Return None +** +*******************************************************************************/ +void l2c_ucd_discard_pending_in_sec_q(tL2C_CCB *p_ccb) +{ + BT_HDR *p_buf; + + p_buf = (BT_HDR*)GKI_dequeue (&p_ccb->p_lcb->ucd_in_sec_pending_q); + + if (p_buf) + { + GKI_freebuf (p_buf); + } +} + +/******************************************************************************* +** +** Function l2c_ucd_check_rx_pkts +** +** Description Check if UCD reception is registered. +** Process received UCD packet if application is expecting. +** +** Return TRUE if UCD reception is registered +** +*******************************************************************************/ +BOOLEAN l2c_ucd_check_rx_pkts(tL2C_LCB *p_lcb, BT_HDR *p_msg) +{ + tL2C_CCB *p_ccb; + tL2C_RCB *p_rcb; + + if (((p_ccb = l2cu_find_ccb_by_cid (p_lcb, L2CAP_CONNECTIONLESS_CID)) != NULL) + ||((p_rcb = l2cu_find_rcb_by_psm (L2C_UCD_RCB_ID)) != NULL)) + { + if (p_ccb == NULL) + { + /* Allocate a channel control block */ + if ((p_ccb = l2cu_allocate_ccb (p_lcb, 0)) == NULL) + { + L2CAP_TRACE_WARNING ("L2CAP - no CCB for UCD reception"); + GKI_freebuf (p_msg); + return TRUE; + } + else + { + /* Set CID for the connection */ + p_ccb->local_cid = L2CAP_CONNECTIONLESS_CID; + p_ccb->remote_cid = L2CAP_CONNECTIONLESS_CID; + + /* Set the default idle timeout value to use */ + p_ccb->fixed_chnl_idle_tout = L2CAP_UCD_IDLE_TIMEOUT; + + /* Set the default channel priority value to use */ + l2cu_change_pri_ccb (p_ccb, L2CAP_UCD_CH_PRIORITY); + + /* Save registration info */ + p_ccb->p_rcb = p_rcb; + + p_ccb->chnl_state = CST_OPEN; + } + } + l2c_csm_execute(p_ccb, L2CEVT_L2CAP_DATA, p_msg); + return TRUE; + } + else + return FALSE; +} + +/******************************************************************************* +** +** Function l2c_ucd_process_event +** +** Description This is called from main state machine when LCID is connectionless +** Process the event if it is for UCD. +** +** Return TRUE if the event is consumed by UCD +** FALSE if the event needs to be processed by main state machine +** +*******************************************************************************/ +BOOLEAN l2c_ucd_process_event(tL2C_CCB *p_ccb, UINT16 event, void *p_data) +{ + /* if the event is not processed by this function, this variable will be set to FALSE */ + BOOLEAN done = TRUE; + + switch (p_ccb->chnl_state) + { + case CST_CLOSED: + switch (event) + { + case L2CEVT_LP_CONNECT_CFM: /* Link came up */ + /* check if waiting for UCD info */ + if (!l2c_ucd_check_pending_info_req (p_ccb)) + { + /* check if any outgoing UCD packet is waiting security check */ + if (!l2c_ucd_check_pending_out_sec_q(p_ccb)) + { + p_ccb->chnl_state = CST_OPEN; + } + } + break; + + case L2CEVT_L2CAP_DATA: /* Peer data packet rcvd */ + GKI_enqueue (&p_ccb->p_lcb->ucd_in_sec_pending_q, p_data); + break; + + case L2CEVT_L2CA_DATA_WRITE: /* Upper layer data to send */ + l2c_ucd_enqueue_pending_out_sec_q(p_ccb, p_data); + break; + + case L2CEVT_L2CAP_INFO_RSP: + /* check if waiting for UCD info */ + if (!l2c_ucd_check_pending_info_req (p_ccb)) + { + /* check if any outgoing UCD packet is waiting security check */ + if (!l2c_ucd_check_pending_out_sec_q(p_ccb)) + { + p_ccb->chnl_state = CST_OPEN; + } + } + break; + + default: + done = FALSE; /* main state machine continues to process event */ + break; + } + break; + + case CST_ORIG_W4_SEC_COMP: + switch (event) + { + case L2CEVT_SEC_RE_SEND_CMD: /* BTM has enough info to proceed */ + /* check if any outgoing UCD packet is waiting security check */ + if (!l2c_ucd_check_pending_out_sec_q(p_ccb)) + { + p_ccb->chnl_state = CST_OPEN; + } + break; + + case L2CEVT_SEC_COMP: /* Security completed success */ + p_ccb->chnl_state = CST_OPEN; + l2c_ucd_send_pending_out_sec_q(p_ccb); + + if ( p_ccb->p_lcb->ucd_out_sec_pending_q.count ) + { + /* start a timer to send next UCD packet in OPEN state */ + /* it will prevent stack overflow */ + btu_start_timer (&p_ccb->timer_entry, BTU_TTYPE_L2CAP_CHNL, 0); + } + else + { + /* start a timer for idle timeout of UCD */ + btu_start_timer (&p_ccb->timer_entry, BTU_TTYPE_L2CAP_CHNL, p_ccb->fixed_chnl_idle_tout); + } + break; + + case L2CEVT_SEC_COMP_NEG: + p_ccb->chnl_state = CST_OPEN; + l2c_ucd_discard_pending_out_sec_q(p_ccb); + + /* start a timer for idle timeout of UCD */ + btu_start_timer (&p_ccb->timer_entry, BTU_TTYPE_L2CAP_CHNL, p_ccb->fixed_chnl_idle_tout); + break; + + case L2CEVT_L2CA_DATA_WRITE: /* Upper layer data to send */ + l2c_ucd_enqueue_pending_out_sec_q(p_ccb, p_data); + break; + + case L2CEVT_L2CAP_DATA: /* Peer data packet rcvd */ + GKI_enqueue (&p_ccb->p_lcb->ucd_in_sec_pending_q, p_data); + break; + + case L2CEVT_L2CAP_INFO_RSP: + /* check if waiting for UCD info */ + l2c_ucd_check_pending_info_req (p_ccb); + break; + + default: + done = FALSE; /* main state machine continues to process event */ + break; + } + break; + + + case CST_TERM_W4_SEC_COMP: + switch (event) + { + case L2CEVT_SEC_COMP: + p_ccb->chnl_state = CST_OPEN; + l2c_ucd_send_pending_in_sec_q (p_ccb); + + if ( p_ccb->p_lcb->ucd_in_sec_pending_q.count ) + { + /* start a timer to check next UCD packet in OPEN state */ + /* it will prevent stack overflow */ + btu_start_timer (&p_ccb->timer_entry, BTU_TTYPE_L2CAP_CHNL, 0); + } + else + { + /* start a timer for idle timeout of UCD */ + btu_start_timer (&p_ccb->timer_entry, BTU_TTYPE_L2CAP_CHNL, p_ccb->fixed_chnl_idle_tout); + } + break; + + case L2CEVT_SEC_COMP_NEG: + if (((tL2C_CONN_INFO *)p_data)->status == BTM_DELAY_CHECK) + { + done = FALSE; + break; + } + p_ccb->chnl_state = CST_OPEN; + l2c_ucd_discard_pending_in_sec_q (p_ccb); + + /* start a timer for idle timeout of UCD */ + btu_start_timer (&p_ccb->timer_entry, BTU_TTYPE_L2CAP_CHNL, p_ccb->fixed_chnl_idle_tout); + break; + + case L2CEVT_L2CA_DATA_WRITE: /* Upper layer data to send */ + l2c_ucd_enqueue_pending_out_sec_q(p_ccb, p_data); + break; + + case L2CEVT_L2CAP_DATA: /* Peer data packet rcvd */ + GKI_enqueue (&p_ccb->p_lcb->ucd_in_sec_pending_q, p_data); + break; + + case L2CEVT_SEC_RE_SEND_CMD: /* BTM has enough info to proceed */ + /* check if any incoming UCD packet is waiting security check */ + if (!l2c_ucd_check_pending_in_sec_q(p_ccb)) + { + p_ccb->chnl_state = CST_OPEN; + } + break; + + case L2CEVT_L2CAP_INFO_RSP: + /* check if waiting for UCD info */ + l2c_ucd_check_pending_info_req (p_ccb); + break; + + default: + done = FALSE; /* main state machine continues to process event */ + break; + } + break; + + case CST_OPEN: + switch (event) + { + case L2CEVT_L2CAP_DATA: /* Peer data packet rcvd */ + /* stop idle timer of UCD */ + btu_stop_timer (&p_ccb->timer_entry); + + GKI_enqueue (&p_ccb->p_lcb->ucd_in_sec_pending_q, p_data); + l2c_ucd_check_pending_in_sec_q (p_ccb); + break; + + case L2CEVT_L2CA_DATA_WRITE: /* Upper layer data to send */ + /* stop idle timer of UCD */ + btu_stop_timer (&p_ccb->timer_entry); + + l2c_ucd_enqueue_pending_out_sec_q(p_ccb, p_data); + + /* coverity[check_return] */ /* coverity[unchecked_value] */ + /* success changes state, failure stays in current state */ + l2c_ucd_check_pending_out_sec_q (p_ccb); + break; + + case L2CEVT_TIMEOUT: + /* check if any UCD packet is waiting security check */ + if ((!l2c_ucd_check_pending_in_sec_q(p_ccb)) + &&(!l2c_ucd_check_pending_out_sec_q(p_ccb))) + { + l2cu_release_ccb (p_ccb); + } + break; + + case L2CEVT_L2CAP_INFO_RSP: + /* check if waiting for UCD info */ + l2c_ucd_check_pending_info_req (p_ccb); + break; + + default: + done = FALSE; /* main state machine continues to process event */ + break; + } + break; + + default: + done = FALSE; /* main state machine continues to process event */ + break; + } + + return done; +} +#endif /* (L2CAP_UCD_INCLUDED == TRUE) */ diff --git a/components/bt/bluedroid/stack/l2cap/l2c_utils.c b/components/bt/bluedroid/stack/l2cap/l2c_utils.c new file mode 100755 index 0000000000..f8d91759c8 --- /dev/null +++ b/components/bt/bluedroid/stack/l2cap/l2c_utils.c @@ -0,0 +1,3531 @@ +/****************************************************************************** + * + * Copyright (C) 1999-2012 Broadcom Corporation + * + * 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 L2CAP utility functions + * + ******************************************************************************/ + +#include +#include +//#include + +#include "controller.h" +#include "gki.h" +#include "bt_types.h" +#include "hcimsgs.h" +#include "l2cdefs.h" +#include "l2c_int.h" +#include "hcidefs.h" +#include "btu.h" +#include "btm_api.h" +#include "btm_int.h" +#include "hcidefs.h" +#include "allocator.h" + +/******************************************************************************* +** +** Function l2cu_allocate_lcb +** +** Description Look for an unused LCB +** +** Returns LCB address or NULL if none found +** +*******************************************************************************/ +tL2C_LCB *l2cu_allocate_lcb (BD_ADDR p_bd_addr, BOOLEAN is_bonding, tBT_TRANSPORT transport) +{ + int xx; + tL2C_LCB *p_lcb = &l2cb.lcb_pool[0]; + + for (xx = 0; xx < MAX_L2CAP_LINKS; xx++, p_lcb++) + { + if (!p_lcb->in_use) + { + memset (p_lcb, 0, sizeof (tL2C_LCB)); + + memcpy (p_lcb->remote_bd_addr, p_bd_addr, BD_ADDR_LEN); + + p_lcb->in_use = TRUE; + p_lcb->link_state = LST_DISCONNECTED; + p_lcb->handle = HCI_INVALID_HANDLE; + p_lcb->link_flush_tout = 0xFFFF; + p_lcb->timer_entry.param = (TIMER_PARAM_TYPE)p_lcb; + p_lcb->info_timer_entry.param = (TIMER_PARAM_TYPE)p_lcb; + p_lcb->idle_timeout = l2cb.idle_timeout; + p_lcb->id = 1; /* spec does not allow '0' */ + p_lcb->is_bonding = is_bonding; +#if (BLE_INCLUDED == TRUE) + p_lcb->transport = transport; + p_lcb->tx_data_len = controller_get_interface()->get_ble_default_data_packet_length(); + + if (transport == BT_TRANSPORT_LE) + { + l2cb.num_ble_links_active++; + l2c_ble_link_adjust_allocation(); + } + else +#endif + { + l2cb.num_links_active++; + l2c_link_adjust_allocation(); + } + p_lcb->link_xmit_data_q = list_new(NULL); + return (p_lcb); + } + } + + /* If here, no free LCB found */ + return (NULL); +} + +/******************************************************************************* +** +** Function l2cu_update_lcb_4_bonding +** +** Description Mark the lcb for bonding. Used when bonding takes place on +** an existing ACL connection. (Pre-Lisbon devices) +** +** Returns Nothing +** +*******************************************************************************/ +void l2cu_update_lcb_4_bonding (BD_ADDR p_bd_addr, BOOLEAN is_bonding) +{ + tL2C_LCB *p_lcb = l2cu_find_lcb_by_bd_addr (p_bd_addr, BT_TRANSPORT_BR_EDR); + + if (p_lcb) + { + p_lcb->is_bonding = is_bonding; + } +} + +/******************************************************************************* +** +** Function l2cu_release_lcb +** +** Description Release an LCB. All timers will be stopped, channels +** dropped, buffers returned etc. +** +** Returns void +** +*******************************************************************************/ +void l2cu_release_lcb (tL2C_LCB *p_lcb) +{ + tL2C_CCB *p_ccb; + + p_lcb->in_use = FALSE; + p_lcb->is_bonding = FALSE; + + /* Stop timers */ + btu_stop_timer (&p_lcb->timer_entry); + btu_stop_timer (&p_lcb->info_timer_entry); + + /* Release any unfinished L2CAP packet on this link */ + if (p_lcb->p_hcit_rcv_acl) + { + GKI_freebuf(p_lcb->p_hcit_rcv_acl); + p_lcb->p_hcit_rcv_acl = NULL; + } + +#if BTM_SCO_INCLUDED == TRUE +#if (BLE_INCLUDED == TRUE) + if (p_lcb->transport == BT_TRANSPORT_BR_EDR) +#endif + /* Release all SCO links */ + btm_remove_sco_links(p_lcb->remote_bd_addr); +#endif + + if (p_lcb->sent_not_acked > 0) + { +#if (BLE_INCLUDED == TRUE) + if (p_lcb->transport == BT_TRANSPORT_LE) + { + l2cb.controller_le_xmit_window += p_lcb->sent_not_acked; + if (l2cb.controller_le_xmit_window > l2cb.num_lm_ble_bufs) + { + l2cb.controller_le_xmit_window = l2cb.num_lm_ble_bufs; + } + } + else +#endif + { + l2cb.controller_xmit_window += p_lcb->sent_not_acked; + if (l2cb.controller_xmit_window > l2cb.num_lm_acl_bufs) + { + l2cb.controller_xmit_window = l2cb.num_lm_acl_bufs; + } + } + } + +#if (BLE_INCLUDED == TRUE) + // Reset BLE connecting flag only if the address matches + if (!memcmp(l2cb.ble_connecting_bda, p_lcb->remote_bd_addr, BD_ADDR_LEN)) + l2cb.is_ble_connecting = FALSE; +#endif + +#if (L2CAP_NUM_FIXED_CHNLS > 0) + l2cu_process_fixed_disc_cback(p_lcb); +#endif + + /* Ensure no CCBs left on this LCB */ + for (p_ccb = p_lcb->ccb_queue.p_first_ccb; p_ccb; p_ccb = p_lcb->ccb_queue.p_first_ccb) + { + l2cu_release_ccb (p_ccb); + } + + /* Tell BTM Acl management the link was removed */ + if ((p_lcb->link_state == LST_CONNECTED) || (p_lcb->link_state == LST_DISCONNECTING)) +#if (BLE_INCLUDED == TRUE) + btm_acl_removed (p_lcb->remote_bd_addr, p_lcb->transport); +#else + btm_acl_removed (p_lcb->remote_bd_addr, BT_TRANSPORT_BR_EDR); +#endif + + /* Release any held buffers */ + if (p_lcb->link_xmit_data_q) + { + while (!list_is_empty(p_lcb->link_xmit_data_q)) { + BT_HDR *p_buf = list_front(p_lcb->link_xmit_data_q); + list_remove(p_lcb->link_xmit_data_q, p_buf); + GKI_freebuf(p_buf); + } + list_free(p_lcb->link_xmit_data_q); + p_lcb->link_xmit_data_q = NULL; + } + +#if (L2CAP_UCD_INCLUDED == TRUE) + /* clean up any security pending UCD */ + l2c_ucd_delete_sec_pending_q(p_lcb); +#endif + +#if BLE_INCLUDED == TRUE + /* Re-adjust flow control windows make sure it does not go negative */ + if (p_lcb->transport == BT_TRANSPORT_LE) + { + if (l2cb.num_ble_links_active >= 1) + l2cb.num_ble_links_active--; + + l2c_ble_link_adjust_allocation(); + } + else +#endif + { + if (l2cb.num_links_active >= 1) + l2cb.num_links_active--; + + l2c_link_adjust_allocation(); + } + + /* Check for ping outstanding */ + if (p_lcb->p_echo_rsp_cb) + { + tL2CA_ECHO_RSP_CB *p_cb = p_lcb->p_echo_rsp_cb; + + /* Zero out the callback in case app immediately calls us again */ + p_lcb->p_echo_rsp_cb = NULL; + + (*p_cb) (L2CAP_PING_RESULT_NO_LINK); + } +} + + +/******************************************************************************* +** +** Function l2cu_find_lcb_by_bd_addr +** +** Description Look through all active LCBs for a match based on the +** remote BD address. +** +** Returns pointer to matched LCB, or NULL if no match +** +*******************************************************************************/ +tL2C_LCB *l2cu_find_lcb_by_bd_addr (BD_ADDR p_bd_addr, tBT_TRANSPORT transport) +{ + int xx; + tL2C_LCB *p_lcb = &l2cb.lcb_pool[0]; + + for (xx = 0; xx < MAX_L2CAP_LINKS; xx++, p_lcb++) + { + if ((p_lcb->in_use) && +#if BLE_INCLUDED == TRUE + p_lcb->transport == transport && +#endif + (!memcmp (p_lcb->remote_bd_addr, p_bd_addr, BD_ADDR_LEN))) + { + return (p_lcb); + } + } + + /* If here, no match found */ + return (NULL); +} + +/******************************************************************************* +** +** Function l2cu_get_conn_role +** +** Description Determine the desired role (master or slave) of a link. +** If already got a slave link, this one must be a master. If +** already got at least 1 link where we are the master, make this +** also a master. +** +** Returns HCI_ROLE_MASTER or HCI_ROLE_SLAVE +** +*******************************************************************************/ +UINT8 l2cu_get_conn_role (tL2C_LCB *p_this_lcb) +{ + return l2cb.desire_role; +} + +/******************************************************************************* +** +** Function l2c_is_cmd_rejected +** +** Description Checks if cmd_code is command or response +** If a command it will be rejected per spec. +** This function is used when a illegal packet length is detected +** +** Returns BOOLEAN - TRUE if cmd_code is a command and it is rejected, +** FALSE if response code. (command not rejected) +** +*******************************************************************************/ +BOOLEAN l2c_is_cmd_rejected (UINT8 cmd_code, UINT8 id, tL2C_LCB *p_lcb) +{ + switch(cmd_code) + { + case L2CAP_CMD_CONN_REQ: + case L2CAP_CMD_CONFIG_REQ: + case L2CAP_CMD_DISC_REQ: + case L2CAP_CMD_ECHO_REQ: + case L2CAP_CMD_INFO_REQ: + case L2CAP_CMD_AMP_CONN_REQ: + case L2CAP_CMD_AMP_MOVE_REQ: + case L2CAP_CMD_BLE_UPDATE_REQ: + l2cu_send_peer_cmd_reject (p_lcb, L2CAP_CMD_REJ_MTU_EXCEEDED, id, L2CAP_DEFAULT_MTU, 0); + L2CAP_TRACE_WARNING ("Dumping first Command (%d)", cmd_code); + return TRUE; + + default: /* Otherwise a response */ + return FALSE; + } +} + +/******************************************************************************* +** +** Function l2cu_build_header +** +** Description Builds the L2CAP command packet header +** +** Returns Pointer to allocated packet or NULL if no resources +** +*******************************************************************************/ +BT_HDR *l2cu_build_header (tL2C_LCB *p_lcb, UINT16 len, UINT8 cmd, UINT8 id) +{ + BT_HDR *p_buf = (BT_HDR *)GKI_getpoolbuf (L2CAP_CMD_POOL_ID); + UINT8 *p; + + if (!p_buf) + { + return (NULL); + } + + p_buf->offset = L2CAP_SEND_CMD_OFFSET; + p_buf->len = len + HCI_DATA_PREAMBLE_SIZE + L2CAP_PKT_OVERHEAD + L2CAP_CMD_OVERHEAD; + p = (UINT8 *)(p_buf + 1) + L2CAP_SEND_CMD_OFFSET; + + /* Put in HCI header - handle + pkt boundary */ +#if (BLE_INCLUDED == TRUE) + if (p_lcb->transport == BT_TRANSPORT_LE) + { + UINT16_TO_STREAM (p, (p_lcb->handle | (L2CAP_PKT_START_NON_FLUSHABLE << L2CAP_PKT_TYPE_SHIFT))); + } + else +#endif + { +#if (L2CAP_NON_FLUSHABLE_PB_INCLUDED == TRUE) + UINT16_TO_STREAM (p, p_lcb->handle | l2cb.non_flushable_pbf); +#else + UINT16_TO_STREAM (p, (p_lcb->handle | (L2CAP_PKT_START << L2CAP_PKT_TYPE_SHIFT))); +#endif + } + + UINT16_TO_STREAM (p, len + L2CAP_PKT_OVERHEAD + L2CAP_CMD_OVERHEAD); + UINT16_TO_STREAM (p, len + L2CAP_CMD_OVERHEAD); + +#if (BLE_INCLUDED == TRUE) + if (p_lcb->transport == BT_TRANSPORT_LE) + { + //counter_add("l2cap.ble.tx.bytes", p_buf->len); + //counter_add("l2cap.ble.tx.pkts", 1); + + UINT16_TO_STREAM (p, L2CAP_BLE_SIGNALLING_CID); + } + else +#endif + { + //counter_add("l2cap.sig.tx.bytes", p_buf->len); + //counter_add("l2cap.sig.tx.pkts", 1); + UINT16_TO_STREAM (p, L2CAP_SIGNALLING_CID); + } + + /* Put in L2CAP command header */ + UINT8_TO_STREAM (p, cmd); + UINT8_TO_STREAM (p, id); + UINT16_TO_STREAM (p, len); + + return (p_buf); +} + +/******************************************************************************* +** +** Function l2cu_adj_id +** +** Description Checks for valid ID based on specified mask +** and adjusts the id if invalid. +** +** Returns void +** +*******************************************************************************/ +void l2cu_adj_id (tL2C_LCB *p_lcb, UINT8 adj_mask) +{ + if ((adj_mask & L2CAP_ADJ_ZERO_ID) && !p_lcb->id) + { + p_lcb->id++; + } +} + +/******************************************************************************* +** +** Function l2cu_send_peer_cmd_reject +** +** Description Build and send an L2CAP "command reject" message +** to the peer. +** +** Returns void +** +*******************************************************************************/ +void l2cu_send_peer_cmd_reject (tL2C_LCB *p_lcb, UINT16 reason, UINT8 rem_id, + UINT16 p1, UINT16 p2) +{ + UINT16 param_len; + BT_HDR *p_buf; + UINT8 *p; + + /* Put in L2CAP packet header */ + if (reason == L2CAP_CMD_REJ_MTU_EXCEEDED) + param_len = 2; + else if (reason == L2CAP_CMD_REJ_INVALID_CID) + param_len = 4; + else + param_len = 0; + + if ((p_buf = l2cu_build_header (p_lcb, (UINT16) (L2CAP_CMD_REJECT_LEN + param_len), L2CAP_CMD_REJECT, rem_id)) == NULL ) + { + L2CAP_TRACE_WARNING ("L2CAP - no buffer cmd_rej"); + return; + } + + p = (UINT8 *)(p_buf + 1) + L2CAP_SEND_CMD_OFFSET + HCI_DATA_PREAMBLE_SIZE + + L2CAP_PKT_OVERHEAD + L2CAP_CMD_OVERHEAD; + + UINT16_TO_STREAM (p, reason); + + if (param_len >= 2) + UINT16_TO_STREAM (p, p1); + + if (param_len >= 4) + UINT16_TO_STREAM (p, p2); + + l2c_link_check_send_pkts (p_lcb, NULL, p_buf); +} + + +/******************************************************************************* +** +** Function l2cu_send_peer_connect_req +** +** Description Build and send an L2CAP "connection request" message +** to the peer. +** +** Returns void +** +*******************************************************************************/ +void l2cu_send_peer_connect_req (tL2C_CCB *p_ccb) +{ + BT_HDR *p_buf; + UINT8 *p; + + /* Create an identifier for this packet */ + p_ccb->p_lcb->id++; + l2cu_adj_id(p_ccb->p_lcb, L2CAP_ADJ_ID); + + p_ccb->local_id = p_ccb->p_lcb->id; + + if ((p_buf = l2cu_build_header (p_ccb->p_lcb, L2CAP_CONN_REQ_LEN, L2CAP_CMD_CONN_REQ, + p_ccb->local_id)) == NULL) + { + L2CAP_TRACE_WARNING ("L2CAP - no buffer for conn_req"); + return; + } + + p = (UINT8 *)(p_buf + 1) + L2CAP_SEND_CMD_OFFSET+HCI_DATA_PREAMBLE_SIZE + + L2CAP_PKT_OVERHEAD + L2CAP_CMD_OVERHEAD; + + UINT16_TO_STREAM (p, p_ccb->p_rcb->real_psm); + UINT16_TO_STREAM (p, p_ccb->local_cid); + + l2c_link_check_send_pkts (p_ccb->p_lcb, NULL, p_buf); +} + + +/******************************************************************************* +** +** Function l2cu_send_peer_connect_rsp +** +** Description Build and send an L2CAP "connection response" message +** to the peer. +** +** Returns void +** +*******************************************************************************/ +void l2cu_send_peer_connect_rsp (tL2C_CCB *p_ccb, UINT16 result, UINT16 status) +{ + BT_HDR *p_buf; + UINT8 *p; + + if (result == L2CAP_CONN_PENDING) + { + /* if we already sent pending response */ + if (p_ccb->flags & CCB_FLAG_SENT_PENDING) + return; + else + p_ccb->flags |= CCB_FLAG_SENT_PENDING; + } + + if ((p_buf=l2cu_build_header(p_ccb->p_lcb, L2CAP_CONN_RSP_LEN, L2CAP_CMD_CONN_RSP, p_ccb->remote_id)) == NULL) + { + L2CAP_TRACE_WARNING ("L2CAP - no buffer for conn_rsp"); + return; + } + + p = (UINT8 *)(p_buf + 1) + L2CAP_SEND_CMD_OFFSET+HCI_DATA_PREAMBLE_SIZE + + L2CAP_PKT_OVERHEAD + L2CAP_CMD_OVERHEAD; + + UINT16_TO_STREAM (p, p_ccb->local_cid); + UINT16_TO_STREAM (p, p_ccb->remote_cid); + UINT16_TO_STREAM (p, result); + UINT16_TO_STREAM (p, status); + + l2c_link_check_send_pkts (p_ccb->p_lcb, NULL, p_buf); +} + + +/******************************************************************************* +** +** Function l2cu_reject_connection +** +** Description Build and send an L2CAP "connection response neg" message +** to the peer. This function is called when there is no peer +** CCB (non-existant PSM or no resources). +** +** Returns void +** +*******************************************************************************/ +void l2cu_reject_connection (tL2C_LCB *p_lcb, UINT16 remote_cid, UINT8 rem_id, UINT16 result) +{ + BT_HDR *p_buf; + UINT8 *p; + + if ((p_buf = l2cu_build_header(p_lcb, L2CAP_CONN_RSP_LEN, L2CAP_CMD_CONN_RSP, rem_id)) == NULL ) + { + L2CAP_TRACE_WARNING ("L2CAP - no buffer for conn_req"); + return; + } + + p = (UINT8 *)(p_buf + 1) + L2CAP_SEND_CMD_OFFSET+HCI_DATA_PREAMBLE_SIZE + L2CAP_PKT_OVERHEAD + L2CAP_CMD_OVERHEAD; + + UINT16_TO_STREAM (p, 0); /* Local CID of 0 */ + UINT16_TO_STREAM (p, remote_cid); + UINT16_TO_STREAM (p, result); + UINT16_TO_STREAM (p, 0); /* Status of 0 */ + + l2c_link_check_send_pkts (p_lcb, NULL, p_buf); +} + +/******************************************************************************* +** +** Function l2cu_send_peer_config_req +** +** Description Build and send an L2CAP "configuration request" message +** to the peer. +** +** Returns void +** +*******************************************************************************/ +void l2cu_send_peer_config_req (tL2C_CCB *p_ccb, tL2CAP_CFG_INFO *p_cfg) +{ + BT_HDR *p_buf; + UINT16 cfg_len=0; + UINT8 *p; + + /* Create an identifier for this packet */ + p_ccb->p_lcb->id++; + l2cu_adj_id(p_ccb->p_lcb, L2CAP_ADJ_ID); + + p_ccb->local_id = p_ccb->p_lcb->id; + + if (p_cfg->mtu_present) + cfg_len += L2CAP_CFG_MTU_OPTION_LEN + L2CAP_CFG_OPTION_OVERHEAD; + if (p_cfg->flush_to_present) + cfg_len += L2CAP_CFG_FLUSH_OPTION_LEN + L2CAP_CFG_OPTION_OVERHEAD; + if (p_cfg->qos_present) + cfg_len += L2CAP_CFG_QOS_OPTION_LEN + L2CAP_CFG_OPTION_OVERHEAD; + if (p_cfg->fcr_present) + cfg_len += L2CAP_CFG_FCR_OPTION_LEN + L2CAP_CFG_OPTION_OVERHEAD; + if (p_cfg->fcs_present) + cfg_len += L2CAP_CFG_FCS_OPTION_LEN + L2CAP_CFG_OPTION_OVERHEAD; + if (p_cfg->ext_flow_spec_present) + cfg_len += L2CAP_CFG_EXT_FLOW_OPTION_LEN + L2CAP_CFG_OPTION_OVERHEAD; + + if ((p_buf = l2cu_build_header (p_ccb->p_lcb, (UINT16) (L2CAP_CONFIG_REQ_LEN + cfg_len), + L2CAP_CMD_CONFIG_REQ, p_ccb->local_id)) == NULL ) + { + L2CAP_TRACE_WARNING ("L2CAP - no buffer for conn_req"); + return; + } + + p = (UINT8 *)(p_buf + 1) + L2CAP_SEND_CMD_OFFSET + HCI_DATA_PREAMBLE_SIZE + + L2CAP_PKT_OVERHEAD + L2CAP_CMD_OVERHEAD; + + UINT16_TO_STREAM (p, p_ccb->remote_cid); + UINT16_TO_STREAM (p, p_cfg->flags); /* Flags (continuation) */ + + /* Now, put the options */ + if (p_cfg->mtu_present) + { + UINT8_TO_STREAM (p, L2CAP_CFG_TYPE_MTU); + UINT8_TO_STREAM (p, L2CAP_CFG_MTU_OPTION_LEN); + UINT16_TO_STREAM (p, p_cfg->mtu); + } + if (p_cfg->flush_to_present) + { + UINT8_TO_STREAM (p, L2CAP_CFG_TYPE_FLUSH_TOUT); + UINT8_TO_STREAM (p, L2CAP_CFG_FLUSH_OPTION_LEN); + UINT16_TO_STREAM (p, p_cfg->flush_to); + } + if (p_cfg->qos_present) + { + UINT8_TO_STREAM (p, L2CAP_CFG_TYPE_QOS); + UINT8_TO_STREAM (p, L2CAP_CFG_QOS_OPTION_LEN); + UINT8_TO_STREAM (p, p_cfg->qos.qos_flags); + UINT8_TO_STREAM (p, p_cfg->qos.service_type); + UINT32_TO_STREAM (p, p_cfg->qos.token_rate); + UINT32_TO_STREAM (p, p_cfg->qos.token_bucket_size); + UINT32_TO_STREAM (p, p_cfg->qos.peak_bandwidth); + UINT32_TO_STREAM (p, p_cfg->qos.latency); + UINT32_TO_STREAM (p, p_cfg->qos.delay_variation); + } + if (p_cfg->fcr_present) + { + UINT8_TO_STREAM (p, L2CAP_CFG_TYPE_FCR); + UINT8_TO_STREAM (p, L2CAP_CFG_FCR_OPTION_LEN); + UINT8_TO_STREAM (p, p_cfg->fcr.mode); + UINT8_TO_STREAM (p, p_cfg->fcr.tx_win_sz); + UINT8_TO_STREAM (p, p_cfg->fcr.max_transmit); + UINT16_TO_STREAM (p, p_cfg->fcr.rtrans_tout); + UINT16_TO_STREAM (p, p_cfg->fcr.mon_tout); + UINT16_TO_STREAM (p, p_cfg->fcr.mps); + } + + if (p_cfg->fcs_present) + { + UINT8_TO_STREAM (p, L2CAP_CFG_TYPE_FCS); + UINT8_TO_STREAM (p, L2CAP_CFG_FCS_OPTION_LEN); + UINT8_TO_STREAM (p, p_cfg->fcs); + } + + if (p_cfg->ext_flow_spec_present) + { + UINT8_TO_STREAM (p, L2CAP_CFG_TYPE_EXT_FLOW); + UINT8_TO_STREAM (p, L2CAP_CFG_EXT_FLOW_OPTION_LEN); + UINT8_TO_STREAM (p, p_cfg->ext_flow_spec.id); + UINT8_TO_STREAM (p, p_cfg->ext_flow_spec.stype); + UINT16_TO_STREAM (p, p_cfg->ext_flow_spec.max_sdu_size); + UINT32_TO_STREAM (p, p_cfg->ext_flow_spec.sdu_inter_time); + UINT32_TO_STREAM (p, p_cfg->ext_flow_spec.access_latency); + UINT32_TO_STREAM (p, p_cfg->ext_flow_spec.flush_timeout); + } + + l2c_link_check_send_pkts (p_ccb->p_lcb, NULL, p_buf); +} + +/******************************************************************************* +** +** Function l2cu_send_peer_config_rsp +** +** Description Build and send an L2CAP "configuration response" message +** to the peer. +** +** Returns void +** +*******************************************************************************/ +void l2cu_send_peer_config_rsp (tL2C_CCB *p_ccb, tL2CAP_CFG_INFO *p_cfg) +{ + BT_HDR *p_buf; + UINT16 cfg_len = 0; + UINT8 *p; + + /* Create an identifier for this packet */ + if (p_cfg->mtu_present) + cfg_len += L2CAP_CFG_MTU_OPTION_LEN + L2CAP_CFG_OPTION_OVERHEAD; + if (p_cfg->flush_to_present) + cfg_len += L2CAP_CFG_FLUSH_OPTION_LEN + L2CAP_CFG_OPTION_OVERHEAD; + if (p_cfg->qos_present) + cfg_len += L2CAP_CFG_QOS_OPTION_LEN + L2CAP_CFG_OPTION_OVERHEAD; + if (p_cfg->fcr_present) + cfg_len += L2CAP_CFG_FCR_OPTION_LEN + L2CAP_CFG_OPTION_OVERHEAD; + if (p_cfg->ext_flow_spec_present) + cfg_len += L2CAP_CFG_EXT_FLOW_OPTION_LEN + L2CAP_CFG_OPTION_OVERHEAD; + + if ((p_buf = l2cu_build_header (p_ccb->p_lcb, (UINT16)(L2CAP_CONFIG_RSP_LEN + cfg_len), + L2CAP_CMD_CONFIG_RSP, p_ccb->remote_id)) == NULL ) + { + L2CAP_TRACE_WARNING ("L2CAP - no buffer for conn_req"); + return; + } + + p = (UINT8 *)(p_buf + 1) + L2CAP_SEND_CMD_OFFSET+HCI_DATA_PREAMBLE_SIZE + L2CAP_PKT_OVERHEAD + L2CAP_CMD_OVERHEAD; + + UINT16_TO_STREAM (p, p_ccb->remote_cid); + UINT16_TO_STREAM (p, p_cfg->flags); /* Flags (continuation) Must match request */ + UINT16_TO_STREAM (p, p_cfg->result); + + /* Now, put the options */ + if (p_cfg->mtu_present) + { + UINT8_TO_STREAM (p, L2CAP_CFG_TYPE_MTU); + UINT8_TO_STREAM (p, L2CAP_CFG_MTU_OPTION_LEN); + UINT16_TO_STREAM (p, p_cfg->mtu); + } + if (p_cfg->flush_to_present) + { + UINT8_TO_STREAM (p, L2CAP_CFG_TYPE_FLUSH_TOUT); + UINT8_TO_STREAM (p, L2CAP_CFG_FLUSH_OPTION_LEN); + UINT16_TO_STREAM (p, p_cfg->flush_to); + } + if (p_cfg->qos_present) + { + UINT8_TO_STREAM (p, L2CAP_CFG_TYPE_QOS); + UINT8_TO_STREAM (p, L2CAP_CFG_QOS_OPTION_LEN); + UINT8_TO_STREAM (p, p_cfg->qos.qos_flags); + UINT8_TO_STREAM (p, p_cfg->qos.service_type); + UINT32_TO_STREAM (p, p_cfg->qos.token_rate); + UINT32_TO_STREAM (p, p_cfg->qos.token_bucket_size); + UINT32_TO_STREAM (p, p_cfg->qos.peak_bandwidth); + UINT32_TO_STREAM (p, p_cfg->qos.latency); + UINT32_TO_STREAM (p, p_cfg->qos.delay_variation); + } + if (p_cfg->fcr_present) + { + UINT8_TO_STREAM (p, L2CAP_CFG_TYPE_FCR); + UINT8_TO_STREAM (p, L2CAP_CFG_FCR_OPTION_LEN); + UINT8_TO_STREAM (p, p_cfg->fcr.mode); + UINT8_TO_STREAM (p, p_cfg->fcr.tx_win_sz); + UINT8_TO_STREAM (p, p_cfg->fcr.max_transmit); + UINT16_TO_STREAM (p, p_ccb->our_cfg.fcr.rtrans_tout); + UINT16_TO_STREAM (p, p_ccb->our_cfg.fcr.mon_tout); + UINT16_TO_STREAM (p, p_cfg->fcr.mps); + } + + if (p_cfg->ext_flow_spec_present) + { + UINT8_TO_STREAM (p, L2CAP_CFG_TYPE_EXT_FLOW); + UINT8_TO_STREAM (p, L2CAP_CFG_EXT_FLOW_OPTION_LEN); + UINT8_TO_STREAM (p, p_cfg->ext_flow_spec.id); + UINT8_TO_STREAM (p, p_cfg->ext_flow_spec.stype); + UINT16_TO_STREAM (p, p_cfg->ext_flow_spec.max_sdu_size); + UINT32_TO_STREAM (p, p_cfg->ext_flow_spec.sdu_inter_time); + UINT32_TO_STREAM (p, p_cfg->ext_flow_spec.access_latency); + UINT32_TO_STREAM (p, p_cfg->ext_flow_spec.flush_timeout); + } + + l2c_link_check_send_pkts (p_ccb->p_lcb, NULL, p_buf); +} + +/******************************************************************************* +** +** Function l2cu_send_peer_config_rej +** +** Description Build and send an L2CAP "configuration reject" message +** to the peer. +** +** Returns void +** +*******************************************************************************/ +void l2cu_send_peer_config_rej (tL2C_CCB *p_ccb, UINT8 *p_data, UINT16 data_len, UINT16 rej_len) +{ + BT_HDR *p_buf; + UINT16 len, cfg_len, buf_space, len1; + UINT8 *p, *p_hci_len, *p_data_end; + UINT8 cfg_code; + + L2CAP_TRACE_DEBUG("l2cu_send_peer_config_rej: data_len=%d, rej_len=%d", data_len, rej_len); + + + len = BT_HDR_SIZE + HCI_DATA_PREAMBLE_SIZE + L2CAP_PKT_OVERHEAD + L2CAP_CMD_OVERHEAD + L2CAP_CONFIG_RSP_LEN; + len1 = 0xFFFF - len; + if (rej_len > len1) + { + L2CAP_TRACE_ERROR ("L2CAP - cfg_rej pkt size exceeds buffer design max limit."); + return; + } + + p_buf = (BT_HDR *)GKI_getbuf (len + rej_len); + + if (!p_buf) + { + L2CAP_TRACE_ERROR ("L2CAP - no buffer for cfg_rej"); + return; + } + + p_buf->offset = L2CAP_SEND_CMD_OFFSET; + p = (UINT8 *)(p_buf + 1) + L2CAP_SEND_CMD_OFFSET; + + /* Put in HCI header - handle + pkt boundary */ +#if (L2CAP_NON_FLUSHABLE_PB_INCLUDED == TRUE) + if (HCI_NON_FLUSHABLE_PB_SUPPORTED(BTM_ReadLocalFeatures ())) + { + UINT16_TO_STREAM (p, (p_ccb->p_lcb->handle | (L2CAP_PKT_START_NON_FLUSHABLE << L2CAP_PKT_TYPE_SHIFT))); + } + else +#endif + { + UINT16_TO_STREAM (p, (p_ccb->p_lcb->handle | (L2CAP_PKT_START << L2CAP_PKT_TYPE_SHIFT))); + } + + /* Remember the HCI header length position, and save space for it */ + p_hci_len = p; + p += 2; + + /* Put in L2CAP packet header */ + UINT16_TO_STREAM (p, L2CAP_CMD_OVERHEAD + L2CAP_CONFIG_RSP_LEN + rej_len); + UINT16_TO_STREAM (p, L2CAP_SIGNALLING_CID); + + /* Put in L2CAP command header */ + UINT8_TO_STREAM (p, L2CAP_CMD_CONFIG_RSP); + UINT8_TO_STREAM (p, p_ccb->remote_id); + + UINT16_TO_STREAM (p, L2CAP_CONFIG_RSP_LEN + rej_len); + + UINT16_TO_STREAM (p, p_ccb->remote_cid); + UINT16_TO_STREAM (p, 0); /* Flags = 0 (no continuation) */ + UINT16_TO_STREAM (p, L2CAP_CFG_UNKNOWN_OPTIONS); + + buf_space = rej_len; + + /* Now, put the rejected options */ + p_data_end = p_data + data_len; + while (p_data < p_data_end) + { + cfg_code = *p_data; + cfg_len = *(p_data + 1); + + switch (cfg_code & 0x7F) + { + /* skip known options */ + case L2CAP_CFG_TYPE_MTU: + case L2CAP_CFG_TYPE_FLUSH_TOUT: + case L2CAP_CFG_TYPE_QOS: + p_data += cfg_len + L2CAP_CFG_OPTION_OVERHEAD; + break; + + /* unknown options; copy into rsp if not hints */ + default: + /* sanity check option length */ + if ((cfg_len + L2CAP_CFG_OPTION_OVERHEAD) <= data_len) + { + if ((cfg_code & 0x80) == 0) + { + if (buf_space >= (cfg_len + L2CAP_CFG_OPTION_OVERHEAD)) + { + memcpy(p, p_data, cfg_len + L2CAP_CFG_OPTION_OVERHEAD); + p += cfg_len + L2CAP_CFG_OPTION_OVERHEAD; + buf_space -= (cfg_len + L2CAP_CFG_OPTION_OVERHEAD); + } + else + { + L2CAP_TRACE_WARNING("L2CAP - cfg_rej exceeds allocated buffer"); + p_data = p_data_end; /* force loop exit */ + break; + } + } + p_data += cfg_len + L2CAP_CFG_OPTION_OVERHEAD; + } + /* bad length; force loop exit */ + else + { + p_data = p_data_end; + } + break; + } + } + + len = (UINT16) (p - p_hci_len - 2); + UINT16_TO_STREAM (p_hci_len, len); + + p_buf->len = len + 4; + + L2CAP_TRACE_DEBUG ("L2CAP - cfg_rej pkt hci_len=%d, l2cap_len=%d", + len, (L2CAP_CMD_OVERHEAD+L2CAP_CONFIG_RSP_LEN+rej_len)); + + l2c_link_check_send_pkts (p_ccb->p_lcb, NULL, p_buf); +} + +/******************************************************************************* +** +** Function l2cu_send_peer_disc_req +** +** Description Build and send an L2CAP "disconnect request" message +** to the peer. +** +** Returns void +** +*******************************************************************************/ +void l2cu_send_peer_disc_req (tL2C_CCB *p_ccb) +{ + BT_HDR *p_buf, *p_buf2; + UINT8 *p; + + /* Create an identifier for this packet */ + p_ccb->p_lcb->id++; + l2cu_adj_id(p_ccb->p_lcb, L2CAP_ADJ_ID); + + p_ccb->local_id = p_ccb->p_lcb->id; + + if ((p_buf = l2cu_build_header(p_ccb->p_lcb, L2CAP_DISC_REQ_LEN, L2CAP_CMD_DISC_REQ, p_ccb->local_id)) == NULL) + { + L2CAP_TRACE_WARNING ("L2CAP - no buffer for disc_req"); + return; + } + + p = (UINT8 *)(p_buf + 1) + L2CAP_SEND_CMD_OFFSET + HCI_DATA_PREAMBLE_SIZE + L2CAP_PKT_OVERHEAD + L2CAP_CMD_OVERHEAD; + + UINT16_TO_STREAM (p, p_ccb->remote_cid); + UINT16_TO_STREAM (p, p_ccb->local_cid); + + /* Move all queued data packets to the LCB. In FCR mode, assume the higher + layer checks that all buffers are sent before disconnecting. + */ + if (p_ccb->peer_cfg.fcr.mode == L2CAP_FCR_BASIC_MODE) + { + while (GKI_getfirst(&p_ccb->xmit_hold_q)) + { + p_buf2 = (BT_HDR *)GKI_dequeue (&p_ccb->xmit_hold_q); + l2cu_set_acl_hci_header (p_buf2, p_ccb); + l2c_link_check_send_pkts (p_ccb->p_lcb, p_ccb, p_buf2); + } + } + + l2c_link_check_send_pkts (p_ccb->p_lcb, NULL, p_buf); +} + + +/******************************************************************************* +** +** Function l2cu_send_peer_disc_rsp +** +** Description Build and send an L2CAP "disconnect response" message +** to the peer. +** +** This function is passed the parameters for the disconnect +** response instead of the CCB address, as it may be called +** to send a disconnect response when there is no CCB. +** +** Returns void +** +*******************************************************************************/ +void l2cu_send_peer_disc_rsp (tL2C_LCB *p_lcb, UINT8 remote_id, UINT16 local_cid, + UINT16 remote_cid) +{ + BT_HDR *p_buf; + UINT8 *p; + + if ((p_buf=l2cu_build_header(p_lcb, L2CAP_DISC_RSP_LEN, L2CAP_CMD_DISC_RSP, remote_id)) == NULL) + { + L2CAP_TRACE_WARNING ("L2CAP - no buffer for disc_rsp"); + return; + } + + p = (UINT8 *)(p_buf + 1) + L2CAP_SEND_CMD_OFFSET + HCI_DATA_PREAMBLE_SIZE + L2CAP_PKT_OVERHEAD + L2CAP_CMD_OVERHEAD; + + UINT16_TO_STREAM (p, local_cid); + UINT16_TO_STREAM (p, remote_cid); + + l2c_link_check_send_pkts (p_lcb, NULL, p_buf); +} + + +/******************************************************************************* +** +** Function l2cu_send_peer_echo_req +** +** Description Build and send an L2CAP "echo request" message +** to the peer. Note that we do not currently allow +** data in the echo request. +** +** Returns void +** +*******************************************************************************/ +void l2cu_send_peer_echo_req (tL2C_LCB *p_lcb, UINT8 *p_data, UINT16 data_len) +{ + BT_HDR *p_buf; + UINT8 *p; + + p_lcb->id++; + l2cu_adj_id(p_lcb, L2CAP_ADJ_ZERO_ID); /* check for wrap to '0' */ + + if ((p_buf = l2cu_build_header(p_lcb, (UINT16) (L2CAP_ECHO_REQ_LEN + data_len), L2CAP_CMD_ECHO_REQ, p_lcb->id)) == NULL) + { + L2CAP_TRACE_WARNING ("L2CAP - no buffer for echo_req"); + return; + } + + p = (UINT8 *)(p_buf + 1) + L2CAP_SEND_CMD_OFFSET + HCI_DATA_PREAMBLE_SIZE + L2CAP_PKT_OVERHEAD + L2CAP_CMD_OVERHEAD; + + if (data_len) + { + ARRAY_TO_STREAM (p, p_data, data_len); + } + + l2c_link_check_send_pkts (p_lcb, NULL, p_buf); +} + + +/******************************************************************************* +** +** Function l2cu_send_peer_echo_rsp +** +** Description Build and send an L2CAP "echo response" message +** to the peer. +** +** Returns void +** +*******************************************************************************/ +void l2cu_send_peer_echo_rsp (tL2C_LCB *p_lcb, UINT8 id, UINT8 *p_data, UINT16 data_len) +{ + BT_HDR *p_buf; + UINT8 *p; + UINT16 maxlen; + /* Filter out duplicate IDs or if available buffers are low (intruder checking) */ + if (!id || id == p_lcb->cur_echo_id) + { + /* Dump this request since it is illegal */ + L2CAP_TRACE_WARNING ("L2CAP ignoring duplicate echo request (%d)", id); + return; + } + else + p_lcb->cur_echo_id = id; + /* Don't respond if we more than 10% of our buffers are used */ + if (GKI_poolutilization (L2CAP_CMD_POOL_ID) > 10) + { + L2CAP_TRACE_WARNING ("L2CAP gki pool used up to more than 10%%, ignore echo response"); + return; + } + + uint16_t acl_data_size = controller_get_interface()->get_acl_data_size_classic(); + uint16_t acl_packet_size = controller_get_interface()->get_acl_packet_size_classic(); + /* Don't return data if it does not fit in ACL and L2CAP MTU */ + maxlen = (GKI_get_pool_bufsize(L2CAP_CMD_POOL_ID) > acl_packet_size) ? + acl_data_size : (UINT16)GKI_get_pool_bufsize(L2CAP_CMD_POOL_ID); + maxlen -= (UINT16)(BT_HDR_SIZE + HCI_DATA_PREAMBLE_SIZE + L2CAP_PKT_OVERHEAD + + L2CAP_CMD_OVERHEAD + L2CAP_ECHO_RSP_LEN); + + if (data_len > maxlen) + data_len = 0; + + if ((p_buf = l2cu_build_header (p_lcb, (UINT16)(L2CAP_ECHO_RSP_LEN + data_len), L2CAP_CMD_ECHO_RSP, id)) == NULL) + { + L2CAP_TRACE_WARNING ("L2CAP - no buffer for echo_rsp"); + return; + } + + p = (UINT8 *)(p_buf + 1) + L2CAP_SEND_CMD_OFFSET + HCI_DATA_PREAMBLE_SIZE + + L2CAP_PKT_OVERHEAD + L2CAP_CMD_OVERHEAD; + + if (data_len) + { + ARRAY_TO_STREAM (p, p_data, data_len); + } + + l2c_link_check_send_pkts (p_lcb, NULL, p_buf); +} + +/******************************************************************************* +** +** Function l2cu_send_peer_info_req +** +** Description Build and send an L2CAP "info request" message +** to the peer. +** Returns void +** +*******************************************************************************/ +void l2cu_send_peer_info_req (tL2C_LCB *p_lcb, UINT16 info_type) +{ + BT_HDR *p_buf; + UINT8 *p; + + /* check for wrap and/or BRCM ID */ + p_lcb->id++; + l2cu_adj_id(p_lcb, L2CAP_ADJ_ID); + + if ((p_buf = l2cu_build_header(p_lcb, 2, L2CAP_CMD_INFO_REQ, p_lcb->id)) == NULL) + { + L2CAP_TRACE_WARNING ("L2CAP - no buffer for info_req"); + return; + } + + L2CAP_TRACE_EVENT ("l2cu_send_peer_info_req: type 0x%04x", info_type); + + p = (UINT8 *)(p_buf + 1) + L2CAP_SEND_CMD_OFFSET+HCI_DATA_PREAMBLE_SIZE + + L2CAP_PKT_OVERHEAD + L2CAP_CMD_OVERHEAD; + + UINT16_TO_STREAM (p, info_type); + + p_lcb->w4_info_rsp = TRUE; + btu_start_timer (&p_lcb->info_timer_entry, BTU_TTYPE_L2CAP_INFO, L2CAP_WAIT_INFO_RSP_TOUT); + + l2c_link_check_send_pkts (p_lcb, NULL, p_buf); +} + + +/******************************************************************************* +** +** Function l2cu_send_peer_info_rsp +** +** Description Build and send an L2CAP "info response" message +** to the peer. +** +** Returns void +** +*******************************************************************************/ +void l2cu_send_peer_info_rsp (tL2C_LCB *p_lcb, UINT8 remote_id, UINT16 info_type) +{ + BT_HDR *p_buf; + UINT8 *p; + UINT16 len = L2CAP_INFO_RSP_LEN; + +#if (L2CAP_CONFORMANCE_TESTING == TRUE) + if ((info_type == L2CAP_EXTENDED_FEATURES_INFO_TYPE) + && (l2cb.test_info_resp & (L2CAP_EXTFEA_ENH_RETRANS | L2CAP_EXTFEA_STREAM_MODE | + L2CAP_EXTFEA_NO_CRC | L2CAP_EXTFEA_EXT_FLOW_SPEC | + L2CAP_EXTFEA_FIXED_CHNLS | L2CAP_EXTFEA_EXT_WINDOW | + L2CAP_EXTFEA_UCD_RECEPTION )) ) +#else + if ((info_type == L2CAP_EXTENDED_FEATURES_INFO_TYPE) + && (L2CAP_EXTFEA_SUPPORTED_MASK & (L2CAP_EXTFEA_ENH_RETRANS | L2CAP_EXTFEA_STREAM_MODE | + L2CAP_EXTFEA_NO_CRC |L2CAP_EXTFEA_FIXED_CHNLS | + L2CAP_EXTFEA_UCD_RECEPTION )) ) +#endif + { + len += L2CAP_EXTENDED_FEATURES_ARRAY_SIZE; + } + else if (info_type == L2CAP_FIXED_CHANNELS_INFO_TYPE) + { + len += L2CAP_FIXED_CHNL_ARRAY_SIZE; + } + else if (info_type == L2CAP_CONNLESS_MTU_INFO_TYPE) + { + len += L2CAP_CONNLESS_MTU_INFO_SIZE; + } + + if ((p_buf = l2cu_build_header(p_lcb, len, L2CAP_CMD_INFO_RSP, remote_id)) == NULL) + { + L2CAP_TRACE_WARNING ("L2CAP - no buffer for info_rsp"); + return; + } + + p = (UINT8 *)(p_buf + 1) + L2CAP_SEND_CMD_OFFSET + HCI_DATA_PREAMBLE_SIZE + + L2CAP_PKT_OVERHEAD + L2CAP_CMD_OVERHEAD; + + UINT16_TO_STREAM (p, info_type); + +#if (L2CAP_CONFORMANCE_TESTING == TRUE) + if ((info_type == L2CAP_EXTENDED_FEATURES_INFO_TYPE) + && (l2cb.test_info_resp & ( L2CAP_EXTFEA_ENH_RETRANS | L2CAP_EXTFEA_STREAM_MODE + | L2CAP_EXTFEA_UCD_RECEPTION )) ) +#else + if ((info_type == L2CAP_EXTENDED_FEATURES_INFO_TYPE) + && (L2CAP_EXTFEA_SUPPORTED_MASK & ( L2CAP_EXTFEA_ENH_RETRANS | L2CAP_EXTFEA_STREAM_MODE + | L2CAP_EXTFEA_UCD_RECEPTION )) ) +#endif + { + UINT16_TO_STREAM (p, L2CAP_INFO_RESP_RESULT_SUCCESS); +#if (BLE_INCLUDED == TRUE) + if (p_lcb->transport == BT_TRANSPORT_LE) + { + /* optional data are not added for now */ + UINT32_TO_STREAM (p, L2CAP_BLE_EXTFEA_MASK); + } + else +#endif + { +#if L2CAP_CONFORMANCE_TESTING == TRUE + UINT32_TO_STREAM (p, l2cb.test_info_resp); +#else +#if (L2CAP_NUM_FIXED_CHNLS > 0) + UINT32_TO_STREAM (p, L2CAP_EXTFEA_SUPPORTED_MASK | L2CAP_EXTFEA_FIXED_CHNLS); +#else + UINT32_TO_STREAM (p, L2CAP_EXTFEA_SUPPORTED_MASK); +#endif +#endif + } + } + else if (info_type == L2CAP_FIXED_CHANNELS_INFO_TYPE) + { + UINT16_TO_STREAM (p, L2CAP_INFO_RESP_RESULT_SUCCESS); + memset (p, 0, L2CAP_FIXED_CHNL_ARRAY_SIZE); + + p[0] = L2CAP_FIXED_CHNL_SIG_BIT; + + if ( L2CAP_EXTFEA_SUPPORTED_MASK & L2CAP_EXTFEA_UCD_RECEPTION ) + p[0] |= L2CAP_FIXED_CHNL_CNCTLESS_BIT; + +#if (L2CAP_NUM_FIXED_CHNLS > 0) + { + int xx; + + for (xx = 0; xx < L2CAP_NUM_FIXED_CHNLS; xx++) + if (l2cb.fixed_reg[xx].pL2CA_FixedConn_Cb != NULL) + p[(xx + L2CAP_FIRST_FIXED_CHNL) / 8] |= 1 << ((xx + L2CAP_FIRST_FIXED_CHNL) % 8); + } +#endif + } + else if (info_type == L2CAP_CONNLESS_MTU_INFO_TYPE) + { + UINT16_TO_STREAM (p, L2CAP_INFO_RESP_RESULT_SUCCESS); + UINT16_TO_STREAM (p, L2CAP_UCD_MTU); + } + else + { + UINT16_TO_STREAM (p, L2CAP_INFO_RESP_RESULT_NOT_SUPPORTED); /* 'not supported' */ + } + + l2c_link_check_send_pkts (p_lcb, NULL, p_buf); +} + +/****************************************************************************** +** +** Function l2cu_enqueue_ccb +** +** Description queue CCB by priority. The first CCB is highest priority and +** is served at first. The CCB is queued to an LLCB or an LCB. +** +** Returns None +** +*******************************************************************************/ +void l2cu_enqueue_ccb (tL2C_CCB *p_ccb) +{ + tL2C_CCB *p_ccb1; + tL2C_CCB_Q *p_q = NULL; + + /* Find out which queue the channel is on + */ + if (p_ccb->p_lcb != NULL) + p_q = &p_ccb->p_lcb->ccb_queue; + + if ( (!p_ccb->in_use) || (p_q == NULL) ) + { + L2CAP_TRACE_ERROR ("l2cu_enqueue_ccb CID: 0x%04x ERROR in_use: %u p_lcb: 0x%08x", + p_ccb->local_cid, p_ccb->in_use, p_ccb->p_lcb); + return; + } + + L2CAP_TRACE_DEBUG ("l2cu_enqueue_ccb CID: 0x%04x priority: %d", + p_ccb->local_cid, p_ccb->ccb_priority); + + /* If the queue is empty, we go at the front */ + if (!p_q->p_first_ccb) + { + p_q->p_first_ccb = p_q->p_last_ccb = p_ccb; + p_ccb->p_next_ccb = p_ccb->p_prev_ccb = NULL; + } + else + { + p_ccb1 = p_q->p_first_ccb; + + while (p_ccb1 != NULL) + { + /* Insert new ccb at the end of the same priority. Lower number, higher priority */ + if (p_ccb->ccb_priority < p_ccb1->ccb_priority) + { + /* Are we at the head of the queue ? */ + if (p_ccb1 == p_q->p_first_ccb) + p_q->p_first_ccb = p_ccb; + else + p_ccb1->p_prev_ccb->p_next_ccb = p_ccb; + + p_ccb->p_next_ccb = p_ccb1; + p_ccb->p_prev_ccb = p_ccb1->p_prev_ccb; + p_ccb1->p_prev_ccb = p_ccb; + break; + } + + p_ccb1 = p_ccb1->p_next_ccb; + } + + /* If we are lower then anyone in the list, we go at the end */ + if (!p_ccb1) + { + /* add new ccb at the end of the list */ + p_q->p_last_ccb->p_next_ccb = p_ccb; + + p_ccb->p_next_ccb = NULL; + p_ccb->p_prev_ccb = p_q->p_last_ccb; + p_q->p_last_ccb = p_ccb; + } + } + +#if (L2CAP_ROUND_ROBIN_CHANNEL_SERVICE == TRUE) + /* Adding CCB into round robin service table of its LCB */ + if (p_ccb->p_lcb != NULL) + { + /* if this is the first channel in this priority group */ + if (p_ccb->p_lcb->rr_serv[p_ccb->ccb_priority].num_ccb == 0 ) + { + /* Set the first channel to this CCB */ + p_ccb->p_lcb->rr_serv[p_ccb->ccb_priority].p_first_ccb = p_ccb; + /* Set the next serving channel in this group to this CCB */ + p_ccb->p_lcb->rr_serv[p_ccb->ccb_priority].p_serve_ccb = p_ccb; + /* Initialize quota of this priority group based on its priority */ + p_ccb->p_lcb->rr_serv[p_ccb->ccb_priority].quota = L2CAP_GET_PRIORITY_QUOTA(p_ccb->ccb_priority); + } + /* increase number of channels in this group */ + p_ccb->p_lcb->rr_serv[p_ccb->ccb_priority].num_ccb++; + } +#endif + +} + +/****************************************************************************** +** +** Function l2cu_dequeue_ccb +** +** Description dequeue CCB from a queue +** +** Returns - +** +*******************************************************************************/ +void l2cu_dequeue_ccb (tL2C_CCB *p_ccb) +{ + tL2C_CCB_Q *p_q = NULL; + + L2CAP_TRACE_DEBUG ("l2cu_dequeue_ccb CID: 0x%04x", p_ccb->local_cid); + + /* Find out which queue the channel is on + */ + if (p_ccb->p_lcb != NULL) + p_q = &p_ccb->p_lcb->ccb_queue; + + if ( (!p_ccb->in_use) || (p_q == NULL) || (p_q->p_first_ccb == NULL) ) + { + L2CAP_TRACE_ERROR ("l2cu_dequeue_ccb CID: 0x%04x ERROR in_use: %u p_lcb: 0x%08x p_q: 0x%08x p_q->p_first_ccb: 0x%08x", + p_ccb->local_cid, p_ccb->in_use, p_ccb->p_lcb, p_q, p_q ? p_q->p_first_ccb : 0); + return; + } + +#if (L2CAP_ROUND_ROBIN_CHANNEL_SERVICE == TRUE) + /* Removing CCB from round robin service table of its LCB */ + if (p_ccb->p_lcb != NULL) + { + /* decrease number of channels in this priority group */ + p_ccb->p_lcb->rr_serv[p_ccb->ccb_priority].num_ccb--; + + /* if it was the last channel in the priority group */ + if (p_ccb->p_lcb->rr_serv[p_ccb->ccb_priority].num_ccb == 0 ) + { + p_ccb->p_lcb->rr_serv[p_ccb->ccb_priority].p_first_ccb = NULL; + p_ccb->p_lcb->rr_serv[p_ccb->ccb_priority].p_serve_ccb = NULL; + } + else + { + /* if it is the first channel of this group */ + if ( p_ccb->p_lcb->rr_serv[p_ccb->ccb_priority].p_first_ccb == p_ccb ) + { + p_ccb->p_lcb->rr_serv[p_ccb->ccb_priority].p_first_ccb = p_ccb->p_next_ccb; + } + /* if it is the next serving channel of this group */ + if ( p_ccb->p_lcb->rr_serv[p_ccb->ccb_priority].p_serve_ccb == p_ccb ) + { + /* simply, start serving from the first channel */ + p_ccb->p_lcb->rr_serv[p_ccb->ccb_priority].p_serve_ccb + = p_ccb->p_lcb->rr_serv[p_ccb->ccb_priority].p_first_ccb; + } + } + } +#endif + + if (p_ccb == p_q->p_first_ccb) + { + /* We are removing the first in a queue */ + p_q->p_first_ccb = p_ccb->p_next_ccb; + + if (p_q->p_first_ccb) + p_q->p_first_ccb->p_prev_ccb = NULL; + else + p_q->p_last_ccb = NULL; + } + else if (p_ccb == p_q->p_last_ccb) + { + /* We are removing the last in a queue */ + p_q->p_last_ccb = p_ccb->p_prev_ccb; + p_q->p_last_ccb->p_next_ccb = NULL; + } + else + { + /* In the middle of a chain. */ + p_ccb->p_prev_ccb->p_next_ccb = p_ccb->p_next_ccb; + p_ccb->p_next_ccb->p_prev_ccb = p_ccb->p_prev_ccb; + } + + p_ccb->p_next_ccb = p_ccb->p_prev_ccb = NULL; +} + +/****************************************************************************** +** +** Function l2cu_change_pri_ccb +** +** Description +** +** Returns - +** +*******************************************************************************/ +void l2cu_change_pri_ccb (tL2C_CCB *p_ccb, tL2CAP_CHNL_PRIORITY priority) +{ + if (p_ccb->ccb_priority != priority) + { + /* If CCB is not the only guy on the queue */ + if ( (p_ccb->p_next_ccb != NULL) || (p_ccb->p_prev_ccb != NULL) ) + { + L2CAP_TRACE_DEBUG ("Update CCB list in logical link"); + + /* Remove CCB from queue and re-queue it at new priority */ + l2cu_dequeue_ccb (p_ccb); + + p_ccb->ccb_priority = priority; + l2cu_enqueue_ccb (p_ccb); + } +#if (L2CAP_ROUND_ROBIN_CHANNEL_SERVICE == TRUE) + else + { + /* If CCB is the only guy on the queue, no need to re-enqueue */ + /* update only round robin service data */ + p_ccb->p_lcb->rr_serv[p_ccb->ccb_priority].num_ccb = 0; + p_ccb->p_lcb->rr_serv[p_ccb->ccb_priority].p_first_ccb = NULL; + p_ccb->p_lcb->rr_serv[p_ccb->ccb_priority].p_serve_ccb = NULL; + + p_ccb->ccb_priority = priority; + + p_ccb->p_lcb->rr_serv[p_ccb->ccb_priority].p_first_ccb = p_ccb; + p_ccb->p_lcb->rr_serv[p_ccb->ccb_priority].p_serve_ccb = p_ccb; + p_ccb->p_lcb->rr_serv[p_ccb->ccb_priority].quota = L2CAP_GET_PRIORITY_QUOTA(p_ccb->ccb_priority); + p_ccb->p_lcb->rr_serv[p_ccb->ccb_priority].num_ccb = 1; + } +#endif + } +} + +/******************************************************************************* +** +** Function l2cu_allocate_ccb +** +** Description This function allocates a Channel Control Block and +** attaches it to a link control block. The local CID +** is also assigned. +** +** Returns pointer to CCB, or NULL if none +** +*******************************************************************************/ +tL2C_CCB *l2cu_allocate_ccb (tL2C_LCB *p_lcb, UINT16 cid) +{ + tL2C_CCB *p_ccb; + tL2C_CCB *p_prev; + + L2CAP_TRACE_DEBUG ("l2cu_allocate_ccb: cid 0x%04x", cid); + + if (!l2cb.p_free_ccb_first) + return (NULL); + + /* If a CID was passed in, use that, else take the first free one */ + if (cid == 0) + { + p_ccb = l2cb.p_free_ccb_first; + l2cb.p_free_ccb_first = p_ccb->p_next_ccb; + } + else + { + p_prev = NULL; + + p_ccb = &l2cb.ccb_pool[cid - L2CAP_BASE_APPL_CID]; + + if (p_ccb == l2cb.p_free_ccb_first) + l2cb.p_free_ccb_first = p_ccb->p_next_ccb; + else + { + for (p_prev = l2cb.p_free_ccb_first; p_prev != NULL; p_prev = p_prev->p_next_ccb) + { + if (p_prev->p_next_ccb == p_ccb) + { + p_prev->p_next_ccb = p_ccb->p_next_ccb; + + if (p_ccb == l2cb.p_free_ccb_last) + l2cb.p_free_ccb_last = p_prev; + + break; + } + } + if (p_prev == NULL) + { + L2CAP_TRACE_ERROR ("l2cu_allocate_ccb: could not find CCB for CID 0x%04x in the free list", cid); + return NULL; + } + } + } + + p_ccb->p_next_ccb = p_ccb->p_prev_ccb = NULL; + + p_ccb->in_use = TRUE; + + /* Get a CID for the connection */ + p_ccb->local_cid = L2CAP_BASE_APPL_CID + (UINT16)(p_ccb - l2cb.ccb_pool); + + p_ccb->p_lcb = p_lcb; + p_ccb->p_rcb = NULL; + p_ccb->should_free_rcb = false; + + /* Set priority then insert ccb into LCB queue (if we have an LCB) */ + p_ccb->ccb_priority = L2CAP_CHNL_PRIORITY_LOW; + + if (p_lcb) + l2cu_enqueue_ccb (p_ccb); + + /* clear what peer wants to configure */ + p_ccb->peer_cfg_bits = 0; + + /* Put in default values for configuration */ + memset (&p_ccb->our_cfg, 0, sizeof(tL2CAP_CFG_INFO)); + memset (&p_ccb->peer_cfg, 0, sizeof(tL2CAP_CFG_INFO)); + + /* Put in default values for local/peer configurations */ + p_ccb->our_cfg.flush_to = p_ccb->peer_cfg.flush_to = L2CAP_DEFAULT_FLUSH_TO; + p_ccb->our_cfg.mtu = p_ccb->peer_cfg.mtu = L2CAP_DEFAULT_MTU; + p_ccb->our_cfg.qos.service_type = p_ccb->peer_cfg.qos.service_type = L2CAP_DEFAULT_SERV_TYPE; + p_ccb->our_cfg.qos.token_rate = p_ccb->peer_cfg.qos.token_rate = L2CAP_DEFAULT_TOKEN_RATE; + p_ccb->our_cfg.qos.token_bucket_size = p_ccb->peer_cfg.qos.token_bucket_size = L2CAP_DEFAULT_BUCKET_SIZE; + p_ccb->our_cfg.qos.peak_bandwidth = p_ccb->peer_cfg.qos.peak_bandwidth = L2CAP_DEFAULT_PEAK_BANDWIDTH; + p_ccb->our_cfg.qos.latency = p_ccb->peer_cfg.qos.latency = L2CAP_DEFAULT_LATENCY; + p_ccb->our_cfg.qos.delay_variation = p_ccb->peer_cfg.qos.delay_variation = L2CAP_DEFAULT_DELAY; + + p_ccb->bypass_fcs = 0; + memset (&p_ccb->ertm_info, 0, sizeof(tL2CAP_ERTM_INFO)); + p_ccb->peer_cfg_already_rejected = FALSE; + p_ccb->fcr_cfg_tries = L2CAP_MAX_FCR_CFG_TRIES; + p_ccb->fcrb.ack_timer.param = (TIMER_PARAM_TYPE)p_ccb; + + /* if timer is running, remove it from timer list */ + if (p_ccb->fcrb.ack_timer.in_use) + btu_stop_quick_timer (&p_ccb->fcrb.ack_timer); + + p_ccb->fcrb.mon_retrans_timer.param = (TIMER_PARAM_TYPE)p_ccb; + +// btla-specific ++ + /* CSP408639 Fix: When L2CAP send amp move channel request or receive + * L2CEVT_AMP_MOVE_REQ do following sequence. Send channel move + * request -> Stop retrans/monitor timer -> Change channel state to CST_AMP_MOVING. */ + if (p_ccb->fcrb.mon_retrans_timer.in_use) + btu_stop_quick_timer (&p_ccb->fcrb.mon_retrans_timer); +// btla-specific -- + + l2c_fcr_stop_timer (p_ccb); + + p_ccb->ertm_info.preferred_mode = L2CAP_FCR_BASIC_MODE; /* Default mode for channel is basic mode */ + p_ccb->ertm_info.allowed_modes = L2CAP_FCR_CHAN_OPT_BASIC; /* Default mode for channel is basic mode */ + p_ccb->ertm_info.fcr_rx_pool_id = L2CAP_FCR_RX_POOL_ID; + p_ccb->ertm_info.fcr_tx_pool_id = L2CAP_FCR_TX_POOL_ID; + p_ccb->ertm_info.user_rx_pool_id = HCI_ACL_POOL_ID; + p_ccb->ertm_info.user_tx_pool_id = HCI_ACL_POOL_ID; + p_ccb->max_rx_mtu = L2CAP_MTU_SIZE; + p_ccb->tx_mps = GKI_get_pool_bufsize(HCI_ACL_POOL_ID) - 32; + + GKI_init_q (&p_ccb->xmit_hold_q); + + p_ccb->cong_sent = FALSE; + p_ccb->buff_quota = 2; /* This gets set after config */ + + /* If CCB was reserved Config_Done can already have some value */ + if (cid == 0) + p_ccb->config_done = 0; + else + { + L2CAP_TRACE_DEBUG ("l2cu_allocate_ccb: cid 0x%04x config_done:0x%x", cid, p_ccb->config_done); + } + + p_ccb->chnl_state = CST_CLOSED; + p_ccb->flags = 0; + p_ccb->tx_data_rate = L2CAP_CHNL_DATA_RATE_LOW; + p_ccb->rx_data_rate = L2CAP_CHNL_DATA_RATE_LOW; + +#if (L2CAP_NON_FLUSHABLE_PB_INCLUDED == TRUE) + p_ccb->is_flushable = FALSE; +#endif + + p_ccb->timer_entry.param = (TIMER_PARAM_TYPE)p_ccb; + p_ccb->timer_entry.in_use = 0; + + l2c_link_adjust_chnl_allocation (); + + return (p_ccb); +} + +/******************************************************************************* +** +** Function l2cu_start_post_bond_timer +** +** Description This function starts the ACL Link inactivity timer after +** dedicated bonding +** This timer can be longer than the normal link inactivity +** timer for some platforms. +** +** Returns BOOLEAN - TRUE if idle timer started or disconnect initiated +** FALSE if there's one or more pending CCB's exist +** +*******************************************************************************/ +BOOLEAN l2cu_start_post_bond_timer (UINT16 handle) +{ + UINT16 timeout; + tL2C_LCB *p_lcb = l2cu_find_lcb_by_handle(handle); + + if (!p_lcb) + return (TRUE); + + p_lcb->is_bonding = FALSE; + + /* Only start timer if no control blocks allocated */ + if (p_lcb->ccb_queue.p_first_ccb != NULL) + return (FALSE); + + /* If no channels on the connection, start idle timeout */ + if ( (p_lcb->link_state == LST_CONNECTED) || (p_lcb->link_state == LST_CONNECTING) || (p_lcb->link_state == LST_DISCONNECTING) ) + { + if (p_lcb->idle_timeout == 0) + { + if (btsnd_hcic_disconnect (p_lcb->handle, HCI_ERR_PEER_USER)) + { + p_lcb->link_state = LST_DISCONNECTING; + timeout = L2CAP_LINK_DISCONNECT_TOUT; + } + else + timeout = BT_1SEC_TIMEOUT; + } + else + { + timeout = L2CAP_BONDING_TIMEOUT; + } + + if (timeout != 0xFFFF) + btu_start_timer (&p_lcb->timer_entry, BTU_TTYPE_L2CAP_LINK, timeout); + + return (TRUE); + } + + return (FALSE); +} + +/******************************************************************************* +** +** Function l2cu_release_ccb +** +** Description This function releases a Channel Control Block. The timer +** is stopped, any attached buffers freed, and the CCB is removed +** from the link control block. +** +** Returns void +** +*******************************************************************************/ +void l2cu_release_ccb (tL2C_CCB *p_ccb) +{ + tL2C_LCB *p_lcb = p_ccb->p_lcb; + tL2C_RCB *p_rcb = p_ccb->p_rcb; + + L2CAP_TRACE_DEBUG ("l2cu_release_ccb: cid 0x%04x in_use: %u", p_ccb->local_cid, p_ccb->in_use); + + /* If already released, could be race condition */ + if (!p_ccb->in_use) + return; + + if (p_rcb && (p_rcb->psm != p_rcb->real_psm)) + { + btm_sec_clr_service_by_psm(p_rcb->psm); + } + + if (p_ccb->should_free_rcb) + { + osi_free(p_rcb); + p_ccb->p_rcb = NULL; + p_ccb->should_free_rcb = false; + } + + btm_sec_clr_temp_auth_service (p_lcb->remote_bd_addr); + + /* Stop the timer */ + btu_stop_timer (&p_ccb->timer_entry); + + while (!GKI_queue_is_empty(&p_ccb->xmit_hold_q)) + GKI_freebuf (GKI_dequeue (&p_ccb->xmit_hold_q)); + + l2c_fcr_cleanup (p_ccb); + + /* Channel may not be assigned to any LCB if it was just pre-reserved */ + if ( (p_lcb) && + ( (p_ccb->local_cid >= L2CAP_BASE_APPL_CID) +#if (L2CAP_UCD_INCLUDED == TRUE) + ||(p_ccb->local_cid == L2CAP_CONNECTIONLESS_CID) +#endif + ) + ) + { + l2cu_dequeue_ccb (p_ccb); + + /* Delink the CCB from the LCB */ + p_ccb->p_lcb = NULL; + } + + /* Put the CCB back on the free pool */ + if (!l2cb.p_free_ccb_first) + { + l2cb.p_free_ccb_first = p_ccb; + l2cb.p_free_ccb_last = p_ccb; + p_ccb->p_next_ccb = NULL; + p_ccb->p_prev_ccb = NULL; + } + else + { + p_ccb->p_next_ccb = NULL; + p_ccb->p_prev_ccb = l2cb.p_free_ccb_last; + l2cb.p_free_ccb_last->p_next_ccb = p_ccb; + l2cb.p_free_ccb_last = p_ccb; + } + + /* Flag as not in use */ + p_ccb->in_use = FALSE; + + /* If no channels on the connection, start idle timeout */ + if ((p_lcb) && p_lcb->in_use && (p_lcb->link_state == LST_CONNECTED)) + { + if (!p_lcb->ccb_queue.p_first_ccb) + { + l2cu_no_dynamic_ccbs (p_lcb); + } + else + { + /* Link is still active, adjust channel quotas. */ + l2c_link_adjust_chnl_allocation (); + } + } +} + +/******************************************************************************* +** +** Function l2cu_find_ccb_by_remote_cid +** +** Description Look through all active CCBs on a link for a match based +** on the remote CID. +** +** Returns pointer to matched CCB, or NULL if no match +** +*******************************************************************************/ +tL2C_CCB *l2cu_find_ccb_by_remote_cid (tL2C_LCB *p_lcb, UINT16 remote_cid) +{ + tL2C_CCB *p_ccb; + + /* If LCB is NULL, look through all active links */ + if (!p_lcb) + { + return NULL; + } + else + { + for (p_ccb = p_lcb->ccb_queue.p_first_ccb; p_ccb; p_ccb = p_ccb->p_next_ccb) + if ((p_ccb->in_use) && (p_ccb->remote_cid == remote_cid)) + return (p_ccb); + } + + /* If here, no match found */ + return (NULL); +} + +/******************************************************************************* +** +** Function l2cu_allocate_rcb +** +** Description Look through the Registration Control Blocks for a free +** one. +** +** Returns Pointer to the RCB or NULL if not found +** +*******************************************************************************/ +tL2C_RCB *l2cu_allocate_rcb (UINT16 psm) +{ + tL2C_RCB *p_rcb = &l2cb.rcb_pool[0]; + UINT16 xx; + + for (xx = 0; xx < MAX_L2CAP_CLIENTS; xx++, p_rcb++) + { + if (!p_rcb->in_use) + { + p_rcb->in_use = TRUE; + p_rcb->psm = psm; +#if (L2CAP_UCD_INCLUDED == TRUE) + p_rcb->ucd.state = L2C_UCD_STATE_UNUSED; +#endif + return (p_rcb); + } + } + + /* If here, no free RCB found */ + return (NULL); +} + + +/******************************************************************************* +** +** Function l2cu_release_rcb +** +** Description Mark an RCB as no longet in use +** +** Returns void +** +*******************************************************************************/ +void l2cu_release_rcb (tL2C_RCB *p_rcb) +{ + p_rcb->in_use = FALSE; + p_rcb->psm = 0; +} + + +/******************************************************************************* +** +** Function l2cu_disconnect_chnl +** +** Description Disconnect a channel. Typically, this is due to either +** receiving a bad configuration, bad packet or max_retries expiring. +** +*******************************************************************************/ +void l2cu_disconnect_chnl (tL2C_CCB *p_ccb) +{ + UINT16 local_cid = p_ccb->local_cid; + + if (local_cid >= L2CAP_BASE_APPL_CID) + { + tL2CA_DISCONNECT_IND_CB *p_disc_cb = p_ccb->p_rcb->api.pL2CA_DisconnectInd_Cb; + + L2CAP_TRACE_WARNING ("L2CAP - disconnect_chnl CID: 0x%04x", local_cid); + + l2cu_send_peer_disc_req (p_ccb); + + l2cu_release_ccb (p_ccb); + + (*p_disc_cb)(local_cid, FALSE); + } + else + { + /* failure on the AMP channel, probably need to disconnect ACL */ + L2CAP_TRACE_ERROR ("L2CAP - disconnect_chnl CID: 0x%04x Ignored", local_cid); + } +} + + +/******************************************************************************* +** +** Function l2cu_find_rcb_by_psm +** +** Description Look through the Registration Control Blocks to see if +** anyone registered to handle the PSM in question +** +** Returns Pointer to the RCB or NULL if not found +** +*******************************************************************************/ +tL2C_RCB *l2cu_find_rcb_by_psm (UINT16 psm) +{ + tL2C_RCB *p_rcb = &l2cb.rcb_pool[0]; + UINT16 xx; + + for (xx = 0; xx < MAX_L2CAP_CLIENTS; xx++, p_rcb++) + { + if ((p_rcb->in_use) && (p_rcb->psm == psm)) + return (p_rcb); + } + + /* If here, no match found */ + return (NULL); +} + + +/******************************************************************************* +** +** Function l2cu_process_peer_cfg_req +** +** Description This function is called when the peer sends us a "config request" +** message. It extracts the configuration of interest and saves +** it in the CCB. +** +** Note: Negotiation of the FCR channel type is handled internally, +** all others are passed to the upper layer. +** +** Returns UINT8 - L2CAP_PEER_CFG_OK if passed to upper layer, +** L2CAP_PEER_CFG_UNACCEPTABLE if automatically responded to +** because parameters are unnacceptable from a specification +** point of view. +** L2CAP_PEER_CFG_DISCONNECT if no compatible channel modes +** between the two devices, and shall be closed. +** +*******************************************************************************/ +UINT8 l2cu_process_peer_cfg_req (tL2C_CCB *p_ccb, tL2CAP_CFG_INFO *p_cfg) +{ + BOOLEAN mtu_ok = TRUE; + BOOLEAN qos_type_ok = TRUE; + BOOLEAN flush_to_ok = TRUE; + BOOLEAN fcr_ok = TRUE; + UINT8 fcr_status; + + /* Ignore FCR parameters for basic mode */ + if (!p_cfg->fcr_present) + p_cfg->fcr.mode = L2CAP_FCR_BASIC_MODE; + + /* Save the MTU that our peer can receive */ + if (p_cfg->mtu_present) + { + /* Make sure MTU is at least the minimum */ + if (p_cfg->mtu >= L2CAP_MIN_MTU) + { + /* In basic mode, limit the MTU to our buffer size */ + if ( (p_cfg->fcr_present == FALSE) && (p_cfg->mtu > L2CAP_MTU_SIZE) ) + p_cfg->mtu = L2CAP_MTU_SIZE; + + /* Save the accepted value in case of renegotiation */ + p_ccb->peer_cfg.mtu = p_cfg->mtu; + p_ccb->peer_cfg.mtu_present = TRUE; + p_ccb->peer_cfg_bits |= L2CAP_CH_CFG_MASK_MTU; + } + else /* Illegal MTU value */ + { + p_cfg->mtu = L2CAP_MIN_MTU; + mtu_ok = FALSE; + } + } + /* Reload mtu from a previously accepted config request */ + else if (p_ccb->peer_cfg.mtu_present) + { + p_cfg->mtu_present = TRUE; + p_cfg->mtu = p_ccb->peer_cfg.mtu; + } + + /* Verify that the flush timeout is a valid value (0 is illegal) */ + if (p_cfg->flush_to_present) + { + if (!p_cfg->flush_to) + { + p_cfg->flush_to = 0xFFFF; /* Infinite retransmissions (spec default) */ + flush_to_ok = FALSE; + } + else /* Save the accepted value in case of renegotiation */ + { + p_ccb->peer_cfg.flush_to_present = TRUE; + p_ccb->peer_cfg.flush_to = p_cfg->flush_to; + p_ccb->peer_cfg_bits |= L2CAP_CH_CFG_MASK_FLUSH_TO; + } + } + /* Reload flush_to from a previously accepted config request */ + else if (p_ccb->peer_cfg.flush_to_present) + { + p_cfg->flush_to_present = TRUE; + p_cfg->flush_to = p_ccb->peer_cfg.flush_to; + } + + /* Save the QOS settings the the peer is using */ + if (p_cfg->qos_present) + { + /* Make sure service type is not a reserved value; otherwise let upper + layer decide if acceptable + */ + if (p_cfg->qos.service_type <= GUARANTEED) + { + p_ccb->peer_cfg.qos = p_cfg->qos; + p_ccb->peer_cfg.qos_present = TRUE; + p_ccb->peer_cfg_bits |= L2CAP_CH_CFG_MASK_QOS; + } + else /* Illegal service type value */ + { + p_cfg->qos.service_type = BEST_EFFORT; + qos_type_ok = FALSE; + } + } + /* Reload QOS from a previously accepted config request */ + else if (p_ccb->peer_cfg.qos_present) + { + p_cfg->qos_present = TRUE; + p_cfg->qos = p_ccb->peer_cfg.qos; + } + + if ((fcr_status = l2c_fcr_process_peer_cfg_req (p_ccb, p_cfg)) == L2CAP_PEER_CFG_DISCONNECT) + { + /* Notify caller to disconnect the channel (incompatible modes) */ + p_cfg->result = L2CAP_CFG_FAILED_NO_REASON; + p_cfg->mtu_present = p_cfg->qos_present = p_cfg->flush_to_present = 0; + + return (L2CAP_PEER_CFG_DISCONNECT); + } + + fcr_ok = (fcr_status == L2CAP_PEER_CFG_OK); + + /* Return any unacceptable parameters */ + if (mtu_ok && flush_to_ok && qos_type_ok && fcr_ok) + { + l2cu_adjust_out_mps (p_ccb); + return (L2CAP_PEER_CFG_OK); + } + else + { + p_cfg->result = L2CAP_CFG_UNACCEPTABLE_PARAMS; + + if (mtu_ok) + p_cfg->mtu_present = FALSE; + if (flush_to_ok) + p_cfg->flush_to_present = FALSE; + if (qos_type_ok) + p_cfg->qos_present = FALSE; + if (fcr_ok) + p_cfg->fcr_present = FALSE; + + return (L2CAP_PEER_CFG_UNACCEPTABLE); + } +} + + +/******************************************************************************* +** +** Function l2cu_process_peer_cfg_rsp +** +** Description This function is called when the peer sends us a "config response" +** message. It extracts the configuration of interest and saves +** it in the CCB. +** +** Returns void +** +*******************************************************************************/ +void l2cu_process_peer_cfg_rsp (tL2C_CCB *p_ccb, tL2CAP_CFG_INFO *p_cfg) +{ + /* If we wanted QoS and the peer sends us a positive response with QoS, use his values */ + if ( (p_cfg->qos_present) && (p_ccb->our_cfg.qos_present) ) + p_ccb->our_cfg.qos = p_cfg->qos; + + if (p_cfg->fcr_present) + { + /* Save the retransmission and monitor timeout values */ + if (p_cfg->fcr.mode == L2CAP_FCR_ERTM_MODE) + { + p_ccb->peer_cfg.fcr.rtrans_tout = p_cfg->fcr.rtrans_tout; + p_ccb->peer_cfg.fcr.mon_tout = p_cfg->fcr.mon_tout; + } + + /* Calculate the max number of packets for which we can delay sending an ack */ + if (p_cfg->fcr.tx_win_sz < p_ccb->our_cfg.fcr.tx_win_sz) + p_ccb->fcrb.max_held_acks = p_cfg->fcr.tx_win_sz / 3; + else + p_ccb->fcrb.max_held_acks = p_ccb->our_cfg.fcr.tx_win_sz / 3; + + L2CAP_TRACE_DEBUG ("l2cu_process_peer_cfg_rsp(): peer tx_win_sz: %d, our tx_win_sz: %d, max_held_acks: %d", + p_cfg->fcr.tx_win_sz, p_ccb->our_cfg.fcr.tx_win_sz, p_ccb->fcrb.max_held_acks); + } +} + +/******************************************************************************* +** +** Function l2cu_process_our_cfg_req +** +** Description This function is called when we send a "config request" +** message. It extracts the configuration of interest and saves +** it in the CCB. +** +** Returns void +** +*******************************************************************************/ +void l2cu_process_our_cfg_req (tL2C_CCB *p_ccb, tL2CAP_CFG_INFO *p_cfg) +{ + tL2C_LCB *p_lcb; + UINT16 hci_flush_to; + + /* Save the QOS settings we are using for transmit */ + if (p_cfg->qos_present) + { + p_ccb->our_cfg.qos_present = TRUE; + p_ccb->our_cfg.qos = p_cfg->qos; + } + + if (p_cfg->fcr_present) + { + /* Override FCR options if attempting streaming or basic */ + if (p_cfg->fcr.mode == L2CAP_FCR_BASIC_MODE) + memset(&p_cfg->fcr, 0, sizeof(tL2CAP_FCR_OPTS)); + else + { + /* On BR/EDR, timer values are zero in config request */ + /* On class 2 AMP, timer value in config request shall be non-0 processing time */ + /* timer value in config response shall be greater than received processing time */ + p_cfg->fcr.mon_tout = p_cfg->fcr.rtrans_tout = 0; + + if (p_cfg->fcr.mode == L2CAP_FCR_STREAM_MODE) + p_cfg->fcr.max_transmit = p_cfg->fcr.tx_win_sz = 0; + } + + /* Set the threshold to send acks (may be updated in the cfg response) */ + p_ccb->fcrb.max_held_acks = p_cfg->fcr.tx_win_sz / 3; + + /* Include FCS option only if peer can handle it */ + if (p_ccb->p_lcb->peer_ext_fea & L2CAP_EXTFEA_NO_CRC) + { + /* FCS check can be bypassed if peer also desires to bypass */ + if (p_cfg->fcs_present && p_cfg->fcs == L2CAP_CFG_FCS_BYPASS) + p_ccb->bypass_fcs |= L2CAP_CFG_FCS_OUR; + } + else + p_cfg->fcs_present = FALSE; + } + else + { + p_cfg->fcr.mode = L2CAP_FCR_BASIC_MODE; + } + + p_ccb->our_cfg.fcr.mode = p_cfg->fcr.mode; + p_ccb->our_cfg.fcr_present = p_cfg->fcr_present; + + /* Check the flush timeout. If it is lower than the current one used */ + /* then we need to adjust the flush timeout sent to the controller */ + if (p_cfg->flush_to_present) + { + if ((p_cfg->flush_to == 0)||(p_cfg->flush_to == L2CAP_NO_AUTOMATIC_FLUSH)) + { + /* don't send invalid flush timeout */ + /* SPEC: The sender of the Request shall specify its flush timeout value */ + /* if it differs from the default value of 0xFFFF */ + p_cfg->flush_to_present = FALSE; + } + else + { + p_ccb->our_cfg.flush_to = p_cfg->flush_to; + p_lcb = p_ccb->p_lcb; + + if (p_cfg->flush_to < p_lcb->link_flush_tout) + { + p_lcb->link_flush_tout = p_cfg->flush_to; + + /* If the timeout is within range of HCI, set the flush timeout */ + if (p_cfg->flush_to <= ((HCI_MAX_AUTO_FLUSH_TOUT * 5) / 8)) + { + /* Convert flush timeout to 0.625 ms units, with round */ + hci_flush_to = ((p_cfg->flush_to * 8) + 3) / 5; + btsnd_hcic_write_auto_flush_tout (p_lcb->handle, hci_flush_to); + } + } + } + } +} + + +/******************************************************************************* +** +** Function l2cu_process_our_cfg_rsp +** +** Description This function is called when we send the peer a "config response" +** message. It extracts the configuration of interest and saves +** it in the CCB. +** +** Returns void +** +*******************************************************************************/ +void l2cu_process_our_cfg_rsp (tL2C_CCB *p_ccb, tL2CAP_CFG_INFO *p_cfg) +{ + /* If peer wants QoS, we are allowed to change the values in a positive response */ + if ( (p_cfg->qos_present) && (p_ccb->peer_cfg.qos_present) ) + p_ccb->peer_cfg.qos = p_cfg->qos; + else + p_cfg->qos_present = FALSE; + + l2c_fcr_adj_our_rsp_options (p_ccb, p_cfg); +} + + +/******************************************************************************* +** +** Function l2cu_device_reset +** +** Description This function is called when reset of the device is +** completed. For all active connection simulate HCI_DISC +** +** Returns void +** +*******************************************************************************/ +void l2cu_device_reset (void) +{ + int xx; + tL2C_LCB *p_lcb = &l2cb.lcb_pool[0]; + + for (xx = 0; xx < MAX_L2CAP_LINKS; xx++, p_lcb++) + { + if ((p_lcb->in_use) && (p_lcb->handle != HCI_INVALID_HANDLE)) + { + l2c_link_hci_disc_comp (p_lcb->handle, (UINT8) -1); + } + } +#if (BLE_INCLUDED == TRUE) + l2cb.is_ble_connecting = FALSE; +#endif +} + +/******************************************************************************* +** +** Function l2cu_create_conn +** +** Description This function initiates an acl connection via HCI +** +** Returns TRUE if successful, FALSE if gki get buffer fails. +** +*******************************************************************************/ +BOOLEAN l2cu_create_conn (tL2C_LCB *p_lcb, tBT_TRANSPORT transport) +{ + int xx; + tL2C_LCB *p_lcb_cur = &l2cb.lcb_pool[0]; +#if BTM_SCO_INCLUDED == TRUE + BOOLEAN is_sco_active; +#endif + +#if (BLE_INCLUDED == TRUE) + tBT_DEVICE_TYPE dev_type; + tBLE_ADDR_TYPE addr_type; + + + BTM_ReadDevInfo(p_lcb->remote_bd_addr, &dev_type, &addr_type); + + if (transport == BT_TRANSPORT_LE) + { + if (!controller_get_interface()->supports_ble()) + return FALSE; + + p_lcb->ble_addr_type = addr_type; + p_lcb->transport = BT_TRANSPORT_LE; + + return (l2cble_create_conn(p_lcb)); + } +#endif + + /* If there is a connection where we perform as a slave, try to switch roles + for this connection */ + for (xx = 0, p_lcb_cur = &l2cb.lcb_pool[0]; xx < MAX_L2CAP_LINKS; xx++, p_lcb_cur++) + { + if (p_lcb_cur == p_lcb) + continue; + + if ((p_lcb_cur->in_use) && (p_lcb_cur->link_role == HCI_ROLE_SLAVE)) + { + +#if BTM_SCO_INCLUDED == TRUE + /* The LMP_switch_req shall be sent only if the ACL logical transport + is in active mode, when encryption is disabled, and all synchronous + logical transports on the same physical link are disabled." */ + + /* Check if there is any SCO Active on this BD Address */ + is_sco_active = btm_is_sco_active_by_bdaddr(p_lcb_cur->remote_bd_addr); + + L2CAP_TRACE_API ("l2cu_create_conn - btm_is_sco_active_by_bdaddr() is_sco_active = %s", \ + (is_sco_active == TRUE) ? "TRUE":"FALSE"); + + if (is_sco_active == TRUE) + continue; /* No Master Slave switch not allowed when SCO Active */ +#endif + /*4_1_TODO check if btm_cb.devcb.local_features to be used instead */ + if (HCI_SWITCH_SUPPORTED(BTM_ReadLocalFeatures())) + { + /* mark this lcb waiting for switch to be completed and + start switch on the other one */ + p_lcb->link_state = LST_CONNECTING_WAIT_SWITCH; + p_lcb->link_role = HCI_ROLE_MASTER; + + if (BTM_SwitchRole (p_lcb_cur->remote_bd_addr, HCI_ROLE_MASTER, NULL) == BTM_CMD_STARTED) + { + btu_start_timer (&p_lcb->timer_entry, BTU_TTYPE_L2CAP_LINK, L2CAP_LINK_ROLE_SWITCH_TOUT); + return (TRUE); + } + } + } + } + + p_lcb->link_state = LST_CONNECTING; + + return (l2cu_create_conn_after_switch (p_lcb)); +} + +/******************************************************************************* +** +** Function l2cu_get_num_hi_priority +** +** Description Gets the number of high priority channels. +** +** Returns +** +*******************************************************************************/ +UINT8 l2cu_get_num_hi_priority (void) +{ + UINT8 no_hi = 0; + int xx; + tL2C_LCB *p_lcb = &l2cb.lcb_pool[0]; + + for (xx = 0; xx < MAX_L2CAP_LINKS; xx++, p_lcb++) + { + if ((p_lcb->in_use) && (p_lcb->acl_priority == L2CAP_PRIORITY_HIGH)) + { + no_hi++; + } + } + return no_hi; +} + + +/******************************************************************************* +** +** Function l2cu_create_conn_after_switch +** +** Description This function initiates an acl connection via HCI +** If switch required to create connection it is already done. +** +** Returns TRUE if successful, FALSE if gki get buffer fails. +** +*******************************************************************************/ + +BOOLEAN l2cu_create_conn_after_switch (tL2C_LCB *p_lcb) +{ + UINT8 allow_switch = HCI_CR_CONN_ALLOW_SWITCH; + tBTM_INQ_INFO *p_inq_info; + UINT8 page_scan_rep_mode; + UINT8 page_scan_mode; + UINT16 clock_offset; + UINT8 *p_features; + UINT16 num_acl = BTM_GetNumAclLinks(); + tBTM_SEC_DEV_REC *p_dev_rec = btm_find_dev (p_lcb->remote_bd_addr); + UINT8 no_hi_prio_chs = l2cu_get_num_hi_priority(); + + p_features = BTM_ReadLocalFeatures(); + + L2CAP_TRACE_DEBUG ("l2cu_create_conn_after_switch :%d num_acl:%d no_hi: %d is_bonding:%d", + l2cb.disallow_switch, num_acl, no_hi_prio_chs, p_lcb->is_bonding); + /* FW team says that we can participant in 4 piconets + * typically 3 piconet + 1 for scanning. + * We can enhance the code to count the number of piconets later. */ + if ( ((!l2cb.disallow_switch && (num_acl < 3)) || (p_lcb->is_bonding && (no_hi_prio_chs==0))) + && HCI_SWITCH_SUPPORTED(p_features)) + allow_switch = HCI_CR_CONN_ALLOW_SWITCH; + else + allow_switch = HCI_CR_CONN_NOT_ALLOW_SWITCH; + + p_lcb->link_state = LST_CONNECTING; + + /* Check with the BT manager if details about remote device are known */ + if ((p_inq_info = BTM_InqDbRead(p_lcb->remote_bd_addr)) != NULL) + { + page_scan_rep_mode = p_inq_info->results.page_scan_rep_mode; + page_scan_mode = p_inq_info->results.page_scan_mode; + clock_offset = (UINT16)(p_inq_info->results.clock_offset); + } + else + { + /* No info known. Use default settings */ + page_scan_rep_mode = HCI_PAGE_SCAN_REP_MODE_R1; + page_scan_mode = HCI_MANDATARY_PAGE_SCAN_MODE; + + clock_offset = (p_dev_rec) ? p_dev_rec->clock_offset : 0; + } + + if (!btsnd_hcic_create_conn (p_lcb->remote_bd_addr, + ( HCI_PKT_TYPES_MASK_DM1 | HCI_PKT_TYPES_MASK_DH1 + | HCI_PKT_TYPES_MASK_DM3 | HCI_PKT_TYPES_MASK_DH3 + | HCI_PKT_TYPES_MASK_DM5 | HCI_PKT_TYPES_MASK_DH5 ), + page_scan_rep_mode, + page_scan_mode, + clock_offset, + allow_switch)) + + { + L2CAP_TRACE_ERROR ("L2CAP - no buffer for l2cu_create_conn"); + l2cu_release_lcb (p_lcb); + return (FALSE); + } + + btm_acl_update_busy_level (BTM_BLI_PAGE_EVT); + + btu_start_timer (&p_lcb->timer_entry, BTU_TTYPE_L2CAP_LINK, + L2CAP_LINK_CONNECT_TOUT); + + return (TRUE); +} + + +/******************************************************************************* +** +** Function l2cu_find_lcb_by_state +** +** Description Look through all active LCBs for a match based on the +** LCB state. +** +** Returns pointer to first matched LCB, or NULL if no match +** +*******************************************************************************/ +tL2C_LCB *l2cu_find_lcb_by_state (tL2C_LINK_STATE state) +{ + UINT16 i; + tL2C_LCB *p_lcb = &l2cb.lcb_pool[0]; + + for (i = 0; i < MAX_L2CAP_LINKS; i++, p_lcb++) + { + if ((p_lcb->in_use) && (p_lcb->link_state == state)) + { + return (p_lcb); + } + } + + /* If here, no match found */ + return (NULL); +} + + +/******************************************************************************* +** +** Function l2cu_lcb_disconnecting +** +** Description On each active lcb, check if the lcb is in disconnecting +** state, or if there are no ccb's on the lcb (implying + idle timeout is running), or if last ccb on the link + is in disconnecting state. +** +** Returns TRUE if any of above conditions met, FALSE otherwise +** +*******************************************************************************/ +BOOLEAN l2cu_lcb_disconnecting (void) +{ + tL2C_LCB *p_lcb; + tL2C_CCB *p_ccb; + UINT16 i; + BOOLEAN status = FALSE; + + p_lcb = &l2cb.lcb_pool[0]; + + for (i = 0; i < MAX_L2CAP_LINKS; i++, p_lcb++) + { + if (p_lcb->in_use) + { + /* no ccbs on lcb, or lcb is in disconnecting state */ + if ((!p_lcb->ccb_queue.p_first_ccb) || (p_lcb->link_state == LST_DISCONNECTING)) + { + status = TRUE; + break; + } + /* only one ccb left on lcb */ + else if (p_lcb->ccb_queue.p_first_ccb == p_lcb->ccb_queue.p_last_ccb) + { + p_ccb = p_lcb->ccb_queue.p_first_ccb; + + if ((p_ccb->in_use) && + ((p_ccb->chnl_state == CST_W4_L2CAP_DISCONNECT_RSP) || + (p_ccb->chnl_state == CST_W4_L2CA_DISCONNECT_RSP))) + { + status = TRUE; + break; + } + } + } + } + return status; +} + + +/******************************************************************************* +** +** Function l2cu_set_acl_priority +** +** Description Sets the transmission priority for a channel. +** (For initial implementation only two values are valid. +** L2CAP_PRIORITY_NORMAL and L2CAP_PRIORITY_HIGH). +** +** Returns TRUE if a valid channel, else FALSE +** +*******************************************************************************/ + +BOOLEAN l2cu_set_acl_priority (BD_ADDR bd_addr, UINT8 priority, BOOLEAN reset_after_rs) +{ + tL2C_LCB *p_lcb; + UINT8 *pp; + UINT8 command[HCI_BRCM_ACL_PRIORITY_PARAM_SIZE]; + UINT8 vs_param; + + //APPL_TRACE_EVENT("SET ACL PRIORITY %d", priority); + + /* Find the link control block for the acl channel */ + if ((p_lcb = l2cu_find_lcb_by_bd_addr(bd_addr, BT_TRANSPORT_BR_EDR)) == NULL) + { + L2CAP_TRACE_WARNING ("L2CAP - no LCB for L2CA_SetAclPriority"); + return (FALSE); + } + + if (BTM_IS_BRCM_CONTROLLER()) + { + /* Called from above L2CAP through API; send VSC if changed */ + if ((!reset_after_rs && (priority != p_lcb->acl_priority)) || + /* Called because of a master/slave role switch; if high resend VSC */ + ( reset_after_rs && p_lcb->acl_priority == L2CAP_PRIORITY_HIGH)) + { + pp = command; + + vs_param = (priority == L2CAP_PRIORITY_HIGH) ? HCI_BRCM_ACL_PRIORITY_HIGH : HCI_BRCM_ACL_PRIORITY_LOW; + + UINT16_TO_STREAM (pp, p_lcb->handle); + UINT8_TO_STREAM (pp, vs_param); + + BTM_VendorSpecificCommand (HCI_BRCM_SET_ACL_PRIORITY, HCI_BRCM_ACL_PRIORITY_PARAM_SIZE, command, NULL); + + /* Adjust lmp buffer allocation for this channel if priority changed */ + if (p_lcb->acl_priority != priority) + { + p_lcb->acl_priority = priority; + l2c_link_adjust_allocation(); + } + } + } + return(TRUE); +} + +#if (L2CAP_NON_FLUSHABLE_PB_INCLUDED == TRUE) +/****************************************************************************** +** +** Function l2cu_set_non_flushable_pbf +** +** Description set L2CAP_PKT_START_NON_FLUSHABLE if controller supoorts +** +** Returns void +** +*******************************************************************************/ +void l2cu_set_non_flushable_pbf (BOOLEAN is_supported) +{ + if (is_supported) + l2cb.non_flushable_pbf = (L2CAP_PKT_START_NON_FLUSHABLE << L2CAP_PKT_TYPE_SHIFT); + else + l2cb.non_flushable_pbf = (L2CAP_PKT_START << L2CAP_PKT_TYPE_SHIFT); +} +#endif + +/******************************************************************************* +** +** Function l2cu_resubmit_pending_sec_req +** +** Description This function is called when required security procedures +** are completed and any pending requests can be re-submitted. +** +** Returns void +** +*******************************************************************************/ +void l2cu_resubmit_pending_sec_req (BD_ADDR p_bda) +{ + tL2C_LCB *p_lcb; + tL2C_CCB *p_ccb; + tL2C_CCB *p_next_ccb; + int xx; + + L2CAP_TRACE_DEBUG ("l2cu_resubmit_pending_sec_req p_bda: 0x%08x", p_bda); + + /* If we are called with a BDA, only resubmit for that BDA */ + if (p_bda) + { + p_lcb = l2cu_find_lcb_by_bd_addr (p_bda, BT_TRANSPORT_BR_EDR); + + /* If we don't have one, this is an error */ + if (p_lcb) + { + /* For all channels, send the event through their FSMs */ + for (p_ccb = p_lcb->ccb_queue.p_first_ccb; p_ccb; p_ccb = p_next_ccb) + { + p_next_ccb = p_ccb->p_next_ccb; + l2c_csm_execute (p_ccb, L2CEVT_SEC_RE_SEND_CMD, NULL); + } + } + else + { + L2CAP_TRACE_WARNING ("l2cu_resubmit_pending_sec_req - unknown BD_ADDR"); + } + } + else + { + /* No BDA pasesed in, so check all links */ + for (xx = 0, p_lcb = &l2cb.lcb_pool[0]; xx < MAX_L2CAP_LINKS; xx++, p_lcb++) + { + if (p_lcb->in_use) + { + /* For all channels, send the event through their FSMs */ + for (p_ccb = p_lcb->ccb_queue.p_first_ccb; p_ccb; p_ccb = p_next_ccb) + { + p_next_ccb = p_ccb->p_next_ccb; + l2c_csm_execute (p_ccb, L2CEVT_SEC_RE_SEND_CMD, NULL); + } + } + } + } +} + +#if L2CAP_CONFORMANCE_TESTING == TRUE +/******************************************************************************* +** +** Function l2cu_set_info_rsp_mask +** +** Description This function allows the script wrapper to change the +** info resp mask for conformance testing. +** +** Returns pointer to CCB, or NULL if none +** +*******************************************************************************/ +void l2cu_set_info_rsp_mask (UINT32 mask) +{ + l2cb.test_info_resp = mask; +} +#endif /* L2CAP_CONFORMANCE_TESTING */ + +/******************************************************************************* +** +** Function l2cu_adjust_out_mps +** +** Description Sets our MPS based on current controller capabilities +** +** Returns void +** +*******************************************************************************/ +void l2cu_adjust_out_mps (tL2C_CCB *p_ccb) +{ + UINT16 packet_size; + + /* on the tx side MTU is selected based on packet size of the controller */ + packet_size = btm_get_max_packet_size (p_ccb->p_lcb->remote_bd_addr); + + if (packet_size <= (L2CAP_PKT_OVERHEAD + L2CAP_FCR_OVERHEAD + L2CAP_SDU_LEN_OVERHEAD + L2CAP_FCS_LEN)) + { + /* something is very wrong */ + L2CAP_TRACE_ERROR ("l2cu_adjust_out_mps bad packet size: %u will use MPS: %u", packet_size, p_ccb->peer_cfg.fcr.mps); + p_ccb->tx_mps = p_ccb->peer_cfg.fcr.mps; + } + else + { + packet_size -= (L2CAP_PKT_OVERHEAD + L2CAP_FCR_OVERHEAD + L2CAP_SDU_LEN_OVERHEAD + L2CAP_FCS_LEN); + + /* We try to negotiate MTU that each packet can be split into whole + number of max packets. For example if link is 1.2 max packet size is 339 bytes. + At first calculate how many whole packets it is. MAX L2CAP is 1691 + 4 overhead. + 1695, that will be 5 Dh5 packets. Now maximum L2CAP packet is + 5 * 339 = 1695. Minus 4 bytes L2CAP header 1691. + + For EDR 2.0 packet size is 1027. So we better send RFCOMM packet as 1 3DH5 packet + 1 * 1027 = 1027. Minus 4 bytes L2CAP header 1023. */ + if (p_ccb->peer_cfg.fcr.mps >= packet_size) + p_ccb->tx_mps = p_ccb->peer_cfg.fcr.mps / packet_size * packet_size; + else + p_ccb->tx_mps = p_ccb->peer_cfg.fcr.mps; + + L2CAP_TRACE_DEBUG ("l2cu_adjust_out_mps use %d Based on peer_cfg.fcr.mps: %u packet_size: %u", + p_ccb->tx_mps, p_ccb->peer_cfg.fcr.mps, packet_size); + } +} + + +/******************************************************************************* +** +** Function l2cu_initialize_fixed_ccb +** +** Description Initialize a fixed channel's CCB +** +** Returns TRUE or FALSE +** +*******************************************************************************/ +BOOLEAN l2cu_initialize_fixed_ccb (tL2C_LCB *p_lcb, UINT16 fixed_cid, tL2CAP_FCR_OPTS *p_fcr) +{ +#if (L2CAP_NUM_FIXED_CHNLS > 0) + tL2C_CCB *p_ccb; + + /* If we already have a CCB, then simply return */ + if (p_lcb->p_fixed_ccbs[fixed_cid - L2CAP_FIRST_FIXED_CHNL] != NULL) + return (TRUE); + + if ((p_ccb = l2cu_allocate_ccb (NULL, 0)) == NULL) + return (FALSE); + + btu_stop_timer(&p_lcb->timer_entry); + + /* Set CID for the connection */ + p_ccb->local_cid = fixed_cid; + p_ccb->remote_cid = fixed_cid; + + GKI_init_q (&p_ccb->xmit_hold_q); + + p_ccb->is_flushable = FALSE; + + p_ccb->timer_entry.param = (TIMER_PARAM_TYPE)p_ccb; + + + if (p_fcr) + { + /* Set the FCR parameters. For now, we will use default pools */ + p_ccb->our_cfg.fcr = p_ccb->peer_cfg.fcr = *p_fcr; + + p_ccb->ertm_info.fcr_rx_pool_id = HCI_ACL_POOL_ID; + p_ccb->ertm_info.fcr_tx_pool_id = HCI_ACL_POOL_ID; + p_ccb->ertm_info.user_rx_pool_id = HCI_ACL_POOL_ID; + p_ccb->ertm_info.user_tx_pool_id = HCI_ACL_POOL_ID; + + p_ccb->fcrb.max_held_acks = p_fcr->tx_win_sz / 3; + } + + /* Link ccb to lcb and lcb to ccb */ + p_lcb->p_fixed_ccbs[fixed_cid - L2CAP_FIRST_FIXED_CHNL] = p_ccb; + p_ccb->p_lcb = p_lcb; + + /* There is no configuration, so if the link is up, the channel is up */ + if (p_lcb->link_state == LST_CONNECTED) + p_ccb->chnl_state = CST_OPEN; + + /* Set the default idle timeout value to use */ + p_ccb->fixed_chnl_idle_tout = l2cb.fixed_reg[fixed_cid - L2CAP_FIRST_FIXED_CHNL].default_idle_tout; +#endif + return (TRUE); +} + +/******************************************************************************* +** +** Function l2cu_no_dynamic_ccbs +** +** Description Handles the case when there are no more dynamic CCBs. If there +** are any fixed CCBs, start the longest of the fixed CCB timeouts, +** otherwise start the default link idle timeout or disconnect. +** +** Returns void +** +*******************************************************************************/ +void l2cu_no_dynamic_ccbs (tL2C_LCB *p_lcb) +{ + tBTM_STATUS rc; + UINT16 timeout = p_lcb->idle_timeout; + +#if (L2CAP_NUM_FIXED_CHNLS > 0) + int xx; + + for (xx = 0; xx < L2CAP_NUM_FIXED_CHNLS; xx++) + { + if ( (p_lcb->p_fixed_ccbs[xx] != NULL) && (p_lcb->p_fixed_ccbs[xx]->fixed_chnl_idle_tout > timeout) ) + timeout = p_lcb->p_fixed_ccbs[xx]->fixed_chnl_idle_tout; + } +#endif + + /* If the link is pairing, do not mess with the timeouts */ + if (p_lcb->is_bonding) + return; + + if (timeout == 0) + { + L2CAP_TRACE_DEBUG ("l2cu_no_dynamic_ccbs() IDLE timer 0, disconnecting link"); + + rc = btm_sec_disconnect (p_lcb->handle, HCI_ERR_PEER_USER); + if (rc == BTM_CMD_STARTED) + { + l2cu_process_fixed_disc_cback(p_lcb); + p_lcb->link_state = LST_DISCONNECTING; + timeout = L2CAP_LINK_DISCONNECT_TOUT; + } + else if (rc == BTM_SUCCESS) + { + l2cu_process_fixed_disc_cback(p_lcb); + /* BTM SEC will make sure that link is release (probably after pairing is done) */ + p_lcb->link_state = LST_DISCONNECTING; + timeout = 0xFFFF; + } + else if ( (p_lcb->is_bonding) + && (btsnd_hcic_disconnect (p_lcb->handle, HCI_ERR_PEER_USER)) ) + { + l2cu_process_fixed_disc_cback(p_lcb); + p_lcb->link_state = LST_DISCONNECTING; + timeout = L2CAP_LINK_DISCONNECT_TOUT; + } + else + { + /* probably no buffer to send disconnect */ + timeout = BT_1SEC_TIMEOUT; + } + } + + if (timeout != 0xFFFF) + { + L2CAP_TRACE_DEBUG ("l2cu_no_dynamic_ccbs() starting IDLE timeout: %d", timeout); + btu_start_timer (&p_lcb->timer_entry, BTU_TTYPE_L2CAP_LINK, timeout); + } + else + { + btu_stop_timer(&p_lcb->timer_entry); + } +} + +#if (L2CAP_NUM_FIXED_CHNLS > 0) +/******************************************************************************* +** +** Function l2cu_process_fixed_chnl_resp +** +** Description handle a fixed channel response (or lack thereof) +** if the link failed, or a fixed channel response was +** not received, the bitfield is all zeros. +** +*******************************************************************************/ +void l2cu_process_fixed_chnl_resp (tL2C_LCB *p_lcb) +{ +#if (BLE_INCLUDED == TRUE) + if (p_lcb->transport == BT_TRANSPORT_BR_EDR) + { + /* ignore all not assigned BR/EDR channels */ + p_lcb->peer_chnl_mask[0] &= (L2CAP_FIXED_CHNL_SIG_BIT| \ + L2CAP_FIXED_CHNL_CNCTLESS_BIT| \ + L2CAP_FIXED_CHNL_SMP_BR_BIT); + } + else + p_lcb->peer_chnl_mask[0] = l2cb.l2c_ble_fixed_chnls_mask; +#endif + + /* Tell all registered fixed channels about the connection */ + for (int xx = 0; xx < L2CAP_NUM_FIXED_CHNLS; xx++) + { +#if BLE_INCLUDED == TRUE + /* skip sending LE fix channel callbacks on BR/EDR links */ + if (p_lcb->transport == BT_TRANSPORT_BR_EDR && + xx + L2CAP_FIRST_FIXED_CHNL >= L2CAP_ATT_CID && + xx + L2CAP_FIRST_FIXED_CHNL <= L2CAP_SMP_CID) + continue; +#endif + if (l2cb.fixed_reg[xx].pL2CA_FixedConn_Cb != NULL) + { + if (p_lcb->peer_chnl_mask[(xx + L2CAP_FIRST_FIXED_CHNL) / 8] + & (1 << ((xx + L2CAP_FIRST_FIXED_CHNL) % 8))) + { + if (p_lcb->p_fixed_ccbs[xx]) + p_lcb->p_fixed_ccbs[xx]->chnl_state = CST_OPEN; +#if BLE_INCLUDED == TRUE + (*l2cb.fixed_reg[xx].pL2CA_FixedConn_Cb)(xx + L2CAP_FIRST_FIXED_CHNL, + p_lcb->remote_bd_addr, TRUE, 0, p_lcb->transport); +#else + (*l2cb.fixed_reg[xx].pL2CA_FixedConn_Cb)(xx + L2CAP_FIRST_FIXED_CHNL, + p_lcb->remote_bd_addr, TRUE, 0, BT_TRANSPORT_BR_EDR); +#endif + } + else + { +#if BLE_INCLUDED == TRUE + (*l2cb.fixed_reg[xx].pL2CA_FixedConn_Cb)(xx + L2CAP_FIRST_FIXED_CHNL, + p_lcb->remote_bd_addr, FALSE, p_lcb->disc_reason, p_lcb->transport); +#else + (*l2cb.fixed_reg[xx].pL2CA_FixedConn_Cb)(xx + L2CAP_FIRST_FIXED_CHNL, + p_lcb->remote_bd_addr, FALSE, p_lcb->disc_reason, BT_TRANSPORT_BR_EDR); +#endif + + if (p_lcb->p_fixed_ccbs[xx]) + { + l2cu_release_ccb (p_lcb->p_fixed_ccbs[xx]); + p_lcb->p_fixed_ccbs[xx] = NULL; + } + } + } + } +} +#endif + + +/******************************************************************************* +** +** Function l2cu_process_fixed_disc_cback +** +** Description send l2cap fixed channel disconnection callback to application +** +** +** Returns void +** +*******************************************************************************/ +void l2cu_process_fixed_disc_cback (tL2C_LCB *p_lcb) +{ +#if (L2CAP_NUM_FIXED_CHNLS > 0) + + /* Select peer channels mask to use depending on transport */ + UINT8 peer_channel_mask = p_lcb->peer_chnl_mask[0]; + + // For LE, reset the stored peer channel mask + if (p_lcb->transport == BT_TRANSPORT_LE) + p_lcb->peer_chnl_mask[0] = 0; + + for (int xx = 0; xx < L2CAP_NUM_FIXED_CHNLS; xx++) + { + if (p_lcb->p_fixed_ccbs[xx]) + { + if (p_lcb->p_fixed_ccbs[xx] != p_lcb->p_pending_ccb) + { + tL2C_CCB *p_l2c_chnl_ctrl_block; + p_l2c_chnl_ctrl_block = p_lcb->p_fixed_ccbs[xx]; + p_lcb->p_fixed_ccbs[xx] = NULL; + l2cu_release_ccb(p_l2c_chnl_ctrl_block); +#if BLE_INCLUDED == TRUE + (*l2cb.fixed_reg[xx].pL2CA_FixedConn_Cb)(xx + L2CAP_FIRST_FIXED_CHNL, + p_lcb->remote_bd_addr, FALSE, p_lcb->disc_reason, p_lcb->transport); +#else + (*l2cb.fixed_reg[xx].pL2CA_FixedConn_Cb)(xx + L2CAP_FIRST_FIXED_CHNL, + p_lcb->remote_bd_addr, FALSE, p_lcb->disc_reason, BT_TRANSPORT_BR_EDR); +#endif + } + } + else if ( (peer_channel_mask & (1 << (xx + L2CAP_FIRST_FIXED_CHNL))) + && (l2cb.fixed_reg[xx].pL2CA_FixedConn_Cb != NULL) ) +#if BLE_INCLUDED == TRUE + (*l2cb.fixed_reg[xx].pL2CA_FixedConn_Cb)(xx + L2CAP_FIRST_FIXED_CHNL, + p_lcb->remote_bd_addr, FALSE, p_lcb->disc_reason, p_lcb->transport); +#else + (*l2cb.fixed_reg[xx].pL2CA_FixedConn_Cb)(xx + L2CAP_FIRST_FIXED_CHNL, + p_lcb->remote_bd_addr, FALSE, p_lcb->disc_reason, BT_TRANSPORT_BR_EDR); +#endif + } +#endif +} + +#if (BLE_INCLUDED == TRUE) +/******************************************************************************* +** +** Function l2cu_send_peer_ble_par_req +** +** Description Build and send a BLE parameter update request message +** to the peer. +** +** Returns void +** +*******************************************************************************/ +void l2cu_send_peer_ble_par_req (tL2C_LCB *p_lcb, UINT16 min_int, UINT16 max_int, + UINT16 latency, UINT16 timeout) +{ + BT_HDR *p_buf; + UINT8 *p; + + /* Create an identifier for this packet */ + p_lcb->id++; + l2cu_adj_id (p_lcb, L2CAP_ADJ_ID); + + if ((p_buf = l2cu_build_header (p_lcb, L2CAP_CMD_BLE_UPD_REQ_LEN, + L2CAP_CMD_BLE_UPDATE_REQ, p_lcb->id)) == NULL ) + { + L2CAP_TRACE_WARNING ("l2cu_send_peer_ble_par_req - no buffer"); + return; + } + + p = (UINT8 *)(p_buf + 1) + L2CAP_SEND_CMD_OFFSET + HCI_DATA_PREAMBLE_SIZE + + L2CAP_PKT_OVERHEAD + L2CAP_CMD_OVERHEAD; + + UINT16_TO_STREAM (p, min_int); + UINT16_TO_STREAM (p, max_int); + UINT16_TO_STREAM (p, latency); + UINT16_TO_STREAM (p, timeout); + + l2c_link_check_send_pkts (p_lcb, NULL, p_buf); +} + +/******************************************************************************* +** +** Function l2cu_send_peer_ble_par_rsp +** +** Description Build and send a BLE parameter update response message +** to the peer. +** +** Returns void +** +*******************************************************************************/ +void l2cu_send_peer_ble_par_rsp (tL2C_LCB *p_lcb, UINT16 reason, UINT8 rem_id) +{ + BT_HDR *p_buf; + UINT8 *p; + + if ((p_buf = l2cu_build_header (p_lcb, L2CAP_CMD_BLE_UPD_RSP_LEN, + L2CAP_CMD_BLE_UPDATE_RSP, rem_id)) == NULL ) + { + L2CAP_TRACE_WARNING ("l2cu_send_peer_ble_par_rsp - no buffer"); + return; + } + + p = (UINT8 *)(p_buf + 1) + L2CAP_SEND_CMD_OFFSET + HCI_DATA_PREAMBLE_SIZE + + L2CAP_PKT_OVERHEAD + L2CAP_CMD_OVERHEAD; + + UINT16_TO_STREAM (p, reason); + + l2c_link_check_send_pkts (p_lcb, NULL, p_buf); +} + +#endif /* BLE_INCLUDED == TRUE */ + + +/******************************************************************************* +** Functions used by both Full and Light Stack +********************************************************************************/ + +/******************************************************************************* +** +** Function l2cu_find_lcb_by_handle +** +** Description Look through all active LCBs for a match based on the +** HCI handle. +** +** Returns pointer to matched LCB, or NULL if no match +** +*******************************************************************************/ +tL2C_LCB *l2cu_find_lcb_by_handle (UINT16 handle) +{ + int xx; + tL2C_LCB *p_lcb = &l2cb.lcb_pool[0]; + + for (xx = 0; xx < MAX_L2CAP_LINKS; xx++, p_lcb++) + { + if ((p_lcb->in_use) && (p_lcb->handle == handle)) + { + return (p_lcb); + } + } + + /* If here, no match found */ + return (NULL); +} + +/******************************************************************************* +** +** Function l2cu_find_ccb_by_cid +** +** Description Look through all active CCBs on a link for a match based +** on the local CID. If passed the link pointer is NULL, all +** active links are searched. +** +** Returns pointer to matched CCB, or NULL if no match +** +*******************************************************************************/ +tL2C_CCB *l2cu_find_ccb_by_cid (tL2C_LCB *p_lcb, UINT16 local_cid) +{ + tL2C_CCB *p_ccb = NULL; +#if (L2CAP_UCD_INCLUDED == TRUE) + UINT8 xx; +#endif + + if (local_cid >= L2CAP_BASE_APPL_CID) + { + /* find the associated CCB by "index" */ + local_cid -= L2CAP_BASE_APPL_CID; + + if (local_cid >= MAX_L2CAP_CHANNELS) + return NULL; + + p_ccb = l2cb.ccb_pool + local_cid; + + /* make sure the CCB is in use */ + if (!p_ccb->in_use) + { + p_ccb = NULL; + } + /* make sure it's for the same LCB */ + else if (p_lcb && p_lcb != p_ccb->p_lcb) + { + p_ccb = NULL; + } + } +#if (L2CAP_UCD_INCLUDED == TRUE) + else + { + /* searching fixed channel */ + p_ccb = l2cb.ccb_pool; + for ( xx = 0; xx < MAX_L2CAP_CHANNELS; xx++ ) + { + if ((p_ccb->local_cid == local_cid) + &&(p_ccb->in_use) + &&(p_lcb == p_ccb->p_lcb)) + break; + else + p_ccb++; + } + if ( xx >= MAX_L2CAP_CHANNELS ) + return NULL; + } +#endif + + return (p_ccb); +} + +#if (L2CAP_ROUND_ROBIN_CHANNEL_SERVICE == TRUE) + +/****************************************************************************** +** +** Function l2cu_get_next_channel_in_rr +** +** Description get the next channel to send on a link. It also adjusts the +** CCB queue to do a basic priority and round-robin scheduling. +** +** Returns pointer to CCB or NULL +** +*******************************************************************************/ +static tL2C_CCB *l2cu_get_next_channel_in_rr(tL2C_LCB *p_lcb) +{ + tL2C_CCB *p_serve_ccb = NULL; + tL2C_CCB *p_ccb; + + int i, j; + + /* scan all of priority until finding a channel to serve */ + for ( i = 0; (i < L2CAP_NUM_CHNL_PRIORITY)&&(!p_serve_ccb); i++ ) + { + /* scan all channel within serving priority group until finding a channel to serve */ + for ( j = 0; (j < p_lcb->rr_serv[p_lcb->rr_pri].num_ccb)&&(!p_serve_ccb); j++) + { + /* scaning from next serving channel */ + p_ccb = p_lcb->rr_serv[p_lcb->rr_pri].p_serve_ccb; + + if (!p_ccb) + { + L2CAP_TRACE_ERROR("p_serve_ccb is NULL, rr_pri=%d", p_lcb->rr_pri); + return NULL; + } + + L2CAP_TRACE_DEBUG("RR scan pri=%d, lcid=0x%04x, q_cout=%d", + p_ccb->ccb_priority, p_ccb->local_cid, GKI_queue_length(&p_ccb->xmit_hold_q)); + + /* store the next serving channel */ + /* this channel is the last channel of its priority group */ + if (( p_ccb->p_next_ccb == NULL ) + ||( p_ccb->p_next_ccb->ccb_priority != p_ccb->ccb_priority )) + { + /* next serving channel is set to the first channel in the group */ + p_lcb->rr_serv[p_lcb->rr_pri].p_serve_ccb = p_lcb->rr_serv[p_lcb->rr_pri].p_first_ccb; + } + else + { + /* next serving channel is set to the next channel in the group */ + p_lcb->rr_serv[p_lcb->rr_pri].p_serve_ccb = p_ccb->p_next_ccb; + } + + if (p_ccb->chnl_state != CST_OPEN) + continue; + + /* eL2CAP option in use */ + if (p_ccb->peer_cfg.fcr.mode != L2CAP_FCR_BASIC_MODE) + { + if (p_ccb->fcrb.wait_ack || p_ccb->fcrb.remote_busy) + continue; + + if ( GKI_queue_is_empty(&p_ccb->fcrb.retrans_q)) + { + if ( GKI_queue_is_empty(&p_ccb->xmit_hold_q)) + continue; + + /* If using the common pool, should be at least 10% free. */ + if ( (p_ccb->ertm_info.fcr_tx_pool_id == HCI_ACL_POOL_ID) && (GKI_poolutilization (HCI_ACL_POOL_ID) > 90) ) + continue; + + /* If in eRTM mode, check for window closure */ + if ( (p_ccb->peer_cfg.fcr.mode == L2CAP_FCR_ERTM_MODE) && (l2c_fcr_is_flow_controlled (p_ccb)) ) + continue; + } + } + else + { + if (GKI_queue_is_empty(&p_ccb->xmit_hold_q)) + continue; + } + + /* found a channel to serve */ + p_serve_ccb = p_ccb; + /* decrease quota of its priority group */ + p_lcb->rr_serv[p_lcb->rr_pri].quota--; + } + + /* if there is no more quota of the priority group or no channel to have data to send */ + if ((p_lcb->rr_serv[p_lcb->rr_pri].quota == 0)||(!p_serve_ccb)) + { + /* serve next priority group */ + p_lcb->rr_pri = (p_lcb->rr_pri + 1) % L2CAP_NUM_CHNL_PRIORITY; + /* initialize its quota */ + p_lcb->rr_serv[p_lcb->rr_pri].quota = L2CAP_GET_PRIORITY_QUOTA(p_lcb->rr_pri); + } + } + + if (p_serve_ccb) + { + L2CAP_TRACE_DEBUG("RR service pri=%d, quota=%d, lcid=0x%04x", + p_serve_ccb->ccb_priority, + p_lcb->rr_serv[p_serve_ccb->ccb_priority].quota, + p_serve_ccb->local_cid ); + } + + return p_serve_ccb; +} + +#else /* (L2CAP_ROUND_ROBIN_CHANNEL_SERVICE == TRUE) */ + +/****************************************************************************** +** +** Function l2cu_get_next_channel +** +** Description get the next channel to send on a link bassed on priority +** scheduling. +** +** Returns pointer to CCB or NULL +** +*******************************************************************************/ +static tL2C_CCB *l2cu_get_next_channel(tL2C_LCB *p_lcb) +{ + tL2C_CCB *p_ccb; + + /* Get the first CCB with data to send. + */ + for (p_ccb = p_lcb->ccb_queue.p_first_ccb; p_ccb; p_ccb = p_ccb->p_next_ccb) + { + if (p_ccb->chnl_state != CST_OPEN) + continue; + + if (p_ccb->fcrb.wait_ack || p_ccb->fcrb.remote_busy) + continue; + + if (p_ccb->fcrb.retrans_q.count != 0) + return p_ccb; + + if (p_ccb->xmit_hold_q.count == 0) + continue; + + /* If using the common pool, should be at least 10% free. */ + if ( (p_ccb->ertm_info.fcr_tx_pool_id == HCI_ACL_POOL_ID) && (GKI_poolutilization (HCI_ACL_POOL_ID) > 90) ) + continue; + + /* If in eRTM mode, check for window closure */ + if ( (p_ccb->peer_cfg.fcr.mode == L2CAP_FCR_ERTM_MODE) && (l2c_fcr_is_flow_controlled (p_ccb)) ) + continue; + + /* If here, we found someone */ + return p_ccb; + } + + return NULL; +} +#endif /* (L2CAP_ROUND_ROBIN_CHANNEL_SERVICE == TRUE) */ + +/****************************************************************************** +** +** Function l2cu_get_next_buffer_to_send +** +** Description get the next buffer to send on a link. It also adjusts the +** CCB queue to do a basic priority and round-robin scheduling. +** +** Returns pointer to buffer or NULL +** +*******************************************************************************/ +BT_HDR *l2cu_get_next_buffer_to_send (tL2C_LCB *p_lcb) +{ + tL2C_CCB *p_ccb; + BT_HDR *p_buf; + + /* Highest priority are fixed channels */ +#if (L2CAP_NUM_FIXED_CHNLS > 0) + int xx; + + for (xx = 0; xx < L2CAP_NUM_FIXED_CHNLS; xx++) + { + if ((p_ccb = p_lcb->p_fixed_ccbs[xx]) == NULL) + continue; + + /* eL2CAP option in use */ + if (p_ccb->peer_cfg.fcr.mode != L2CAP_FCR_BASIC_MODE) + { + if (p_ccb->fcrb.wait_ack || p_ccb->fcrb.remote_busy) + continue; + + /* No more checks needed if sending from the reatransmit queue */ + if (GKI_queue_is_empty(&p_ccb->fcrb.retrans_q)) + { + if (GKI_queue_is_empty(&p_ccb->xmit_hold_q)) + continue; + + /* If using the common pool, should be at least 10% free. */ + if ( (p_ccb->ertm_info.fcr_tx_pool_id == HCI_ACL_POOL_ID) && (GKI_poolutilization (HCI_ACL_POOL_ID) > 90) ) + continue; + + /* If in eRTM mode, check for window closure */ + if ( (p_ccb->peer_cfg.fcr.mode == L2CAP_FCR_ERTM_MODE) && (l2c_fcr_is_flow_controlled (p_ccb)) ) + continue; + } + + if ((p_buf = l2c_fcr_get_next_xmit_sdu_seg(p_ccb, 0)) != NULL) + { + l2cu_check_channel_congestion (p_ccb); + l2cu_set_acl_hci_header (p_buf, p_ccb); + return (p_buf); + } + } + else + { + if (!GKI_queue_is_empty(&p_ccb->xmit_hold_q)) + { + p_buf = (BT_HDR *)GKI_dequeue (&p_ccb->xmit_hold_q); + if(NULL == p_buf) + { + L2CAP_TRACE_ERROR("l2cu_get_buffer_to_send: No data to be sent"); + return (NULL); + } + /* send tx complete */ + if (l2cb.fixed_reg[xx].pL2CA_FixedTxComplete_Cb) + (*l2cb.fixed_reg[xx].pL2CA_FixedTxComplete_Cb)(p_ccb->local_cid, 1); + + l2cu_check_channel_congestion (p_ccb); + l2cu_set_acl_hci_header (p_buf, p_ccb); + return (p_buf); + } + } + } +#endif + +#if (L2CAP_ROUND_ROBIN_CHANNEL_SERVICE == TRUE) + /* get next serving channel in round-robin */ + p_ccb = l2cu_get_next_channel_in_rr( p_lcb ); +#else + p_ccb = l2cu_get_next_channel( p_lcb ); +#endif + + /* Return if no buffer */ + if (p_ccb == NULL) + return (NULL); + + if (p_ccb->peer_cfg.fcr.mode != L2CAP_FCR_BASIC_MODE) + { + if ((p_buf = l2c_fcr_get_next_xmit_sdu_seg(p_ccb, 0)) == NULL) + return (NULL); + } + else + { + p_buf = (BT_HDR *)GKI_dequeue (&p_ccb->xmit_hold_q); + if(NULL == p_buf) + { + L2CAP_TRACE_ERROR("l2cu_get_buffer_to_send() #2: No data to be sent"); + return (NULL); + } + } + + if ( p_ccb->p_rcb && p_ccb->p_rcb->api.pL2CA_TxComplete_Cb && (p_ccb->peer_cfg.fcr.mode != L2CAP_FCR_ERTM_MODE) ) + (*p_ccb->p_rcb->api.pL2CA_TxComplete_Cb)(p_ccb->local_cid, 1); + + + l2cu_check_channel_congestion (p_ccb); + + l2cu_set_acl_hci_header (p_buf, p_ccb); + + return (p_buf); +} + +/****************************************************************************** +** +** Function l2cu_set_acl_hci_header +** +** Description Set HCI handle for ACL packet +** +** Returns None +** +*******************************************************************************/ +void l2cu_set_acl_hci_header (BT_HDR *p_buf, tL2C_CCB *p_ccb) +{ + UINT8 *p; + + /* Set the pointer to the beginning of the data minus 4 bytes for the packet header */ + p = (UINT8 *)(p_buf + 1) + p_buf->offset - HCI_DATA_PREAMBLE_SIZE; + +#if (BLE_INCLUDED == TRUE) + if (p_ccb->p_lcb->transport == BT_TRANSPORT_LE) + { + UINT16_TO_STREAM (p, p_ccb->p_lcb->handle | (L2CAP_PKT_START_NON_FLUSHABLE << L2CAP_PKT_TYPE_SHIFT)); + + uint16_t acl_data_size = controller_get_interface()->get_acl_data_size_ble(); + /* The HCI transport will segment the buffers. */ + if (p_buf->len > acl_data_size) + { + UINT16_TO_STREAM (p, acl_data_size); + } + else + { + UINT16_TO_STREAM (p, p_buf->len); + } + } /* (BLE_INCLUDED == TRUE) */ + else +#endif + { +#if (L2CAP_NON_FLUSHABLE_PB_INCLUDED == TRUE) + if ( (((p_buf->layer_specific & L2CAP_FLUSHABLE_MASK) == L2CAP_FLUSHABLE_CH_BASED) && (p_ccb->is_flushable)) + || ((p_buf->layer_specific & L2CAP_FLUSHABLE_MASK) == L2CAP_FLUSHABLE_PKT) ) + { + UINT16_TO_STREAM (p, p_ccb->p_lcb->handle | (L2CAP_PKT_START << L2CAP_PKT_TYPE_SHIFT)); + } + else + { + UINT16_TO_STREAM (p, p_ccb->p_lcb->handle | l2cb.non_flushable_pbf); + } +#else + UINT16_TO_STREAM (p, p_ccb->p_lcb->handle | (L2CAP_PKT_START << L2CAP_PKT_TYPE_SHIFT)); +#endif + + uint16_t acl_data_size = controller_get_interface()->get_acl_data_size_classic(); + /* The HCI transport will segment the buffers. */ + if (p_buf->len > acl_data_size) + { + UINT16_TO_STREAM (p, acl_data_size); + } + else + { + UINT16_TO_STREAM (p, p_buf->len); + } + } + p_buf->offset -= HCI_DATA_PREAMBLE_SIZE; + p_buf->len += HCI_DATA_PREAMBLE_SIZE; +} + +/****************************************************************************** +** +** Function l2cu_check_channel_congestion +** +** Description check if any change in congestion status +** +** Returns None +** +*******************************************************************************/ +void l2cu_check_channel_congestion (tL2C_CCB *p_ccb) +{ + UINT16 q_count = GKI_queue_length(&p_ccb->xmit_hold_q); + +#if (L2CAP_UCD_INCLUDED == TRUE) + if ( p_ccb->local_cid == L2CAP_CONNECTIONLESS_CID ) + { + q_count += p_ccb->p_lcb->ucd_out_sec_pending_q.count; + } +#endif + /* If the CCB queue limit is subject to a quota, check for congestion */ + /* if this channel has outgoing traffic */ + if (p_ccb->buff_quota != 0) + { + /* If this channel was congested */ + if ( p_ccb->cong_sent ) + { + /* If the channel is not congested now, tell the app */ + if (q_count <= (p_ccb->buff_quota / 2)) + { + p_ccb->cong_sent = FALSE; + if (p_ccb->p_rcb && p_ccb->p_rcb->api.pL2CA_CongestionStatus_Cb) + { + L2CAP_TRACE_DEBUG ("L2CAP - Calling CongestionStatus_Cb (FALSE), CID: 0x%04x xmit_hold_q.count: %u buff_quota: %u", + p_ccb->local_cid, q_count, p_ccb->buff_quota); + + /* Prevent recursive calling */ + l2cb.is_cong_cback_context = TRUE; + (*p_ccb->p_rcb->api.pL2CA_CongestionStatus_Cb)(p_ccb->local_cid, FALSE); + l2cb.is_cong_cback_context = FALSE; + } +#if (L2CAP_UCD_INCLUDED == TRUE) + else if ( p_ccb->p_rcb && p_ccb->local_cid == L2CAP_CONNECTIONLESS_CID ) + { + if ( p_ccb->p_rcb->ucd.cb_info.pL2CA_UCD_Congestion_Status_Cb ) + { + L2CAP_TRACE_DEBUG ("L2CAP - Calling UCD CongestionStatus_Cb (FALSE), SecPendingQ:%u,XmitQ:%u,Quota:%u", + p_ccb->p_lcb->ucd_out_sec_pending_q.count, + p_ccb->xmit_hold_q.count, p_ccb->buff_quota); + p_ccb->p_rcb->ucd.cb_info.pL2CA_UCD_Congestion_Status_Cb( p_ccb->p_lcb->remote_bd_addr, FALSE ); + } + } +#endif +#if (L2CAP_NUM_FIXED_CHNLS > 0) + else + { + UINT8 xx; + for (xx = 0; xx < L2CAP_NUM_FIXED_CHNLS; xx ++) + { + if (p_ccb->p_lcb->p_fixed_ccbs[xx] == p_ccb) + { + if (l2cb.fixed_reg[xx].pL2CA_FixedCong_Cb != NULL) + (* l2cb.fixed_reg[xx].pL2CA_FixedCong_Cb)(p_ccb->p_lcb->remote_bd_addr, FALSE); + break; + } + } + } +#endif + } + } + else + { + /* If this channel was not congested but it is congested now, tell the app */ + if (q_count > p_ccb->buff_quota) + { + p_ccb->cong_sent = TRUE; + if (p_ccb->p_rcb && p_ccb->p_rcb->api.pL2CA_CongestionStatus_Cb) + { + L2CAP_TRACE_DEBUG ("L2CAP - Calling CongestionStatus_Cb (TRUE),CID:0x%04x,XmitQ:%u,Quota:%u", + p_ccb->local_cid, q_count, p_ccb->buff_quota); + + (*p_ccb->p_rcb->api.pL2CA_CongestionStatus_Cb)(p_ccb->local_cid, TRUE); + } +#if (L2CAP_UCD_INCLUDED == TRUE) + else if ( p_ccb->p_rcb && p_ccb->local_cid == L2CAP_CONNECTIONLESS_CID ) + { + if ( p_ccb->p_rcb->ucd.cb_info.pL2CA_UCD_Congestion_Status_Cb ) + { + L2CAP_TRACE_DEBUG ("L2CAP - Calling UCD CongestionStatus_Cb (TRUE), SecPendingQ:%u,XmitQ:%u,Quota:%u", + p_ccb->p_lcb->ucd_out_sec_pending_q.count, + p_ccb->xmit_hold_q.count, p_ccb->buff_quota); + p_ccb->p_rcb->ucd.cb_info.pL2CA_UCD_Congestion_Status_Cb( p_ccb->p_lcb->remote_bd_addr, TRUE ); + } + } +#endif +#if (L2CAP_NUM_FIXED_CHNLS > 0) + else + { + UINT8 xx; + for (xx = 0; xx < L2CAP_NUM_FIXED_CHNLS; xx ++) + { + if (p_ccb->p_lcb->p_fixed_ccbs[xx] == p_ccb) + { + if (l2cb.fixed_reg[xx].pL2CA_FixedCong_Cb != NULL) + (* l2cb.fixed_reg[xx].pL2CA_FixedCong_Cb)(p_ccb->p_lcb->remote_bd_addr, TRUE); + break; + } + } + } +#endif + } + } + } +} + diff --git a/components/bt/bluedroid/stack/l2cap/l2cap_client.c b/components/bt/bluedroid/stack/l2cap/l2cap_client.c new file mode 100755 index 0000000000..4b64e11983 --- /dev/null +++ b/components/bt/bluedroid/stack/l2cap/l2cap_client.c @@ -0,0 +1,434 @@ +/****************************************************************************** + * + * Copyright (C) 2014 Google, Inc. + * + * 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. + * + ******************************************************************************/ +#if (defined(L2CAP_CLIENT_INCLUDED) && L2CAP_CLIENT_INCLUDED == TRUE) +#include +#include "bt_trace.h" +#include "bt_defs.h" +#include "bdaddr.h" +#include "gki.h" +#include "allocator.h" +#include "buffer.h" +#include "list.h" +#include "osi.h" +#include "l2cap_client.h" +#include "l2c_api.h" + +struct l2cap_client_t { + l2cap_client_callbacks_t callbacks; + void *context; + + uint16_t local_channel_id; + uint16_t remote_mtu; + bool configured_self; + bool configured_peer; + bool is_congested; + list_t *outbound_fragments; +}; + +static void connect_completed_cb(uint16_t local_channel_id, uint16_t error_code); +static void config_request_cb(uint16_t local_channel_id, tL2CAP_CFG_INFO *requested_parameters); +static void config_completed_cb(uint16_t local_channel_id, tL2CAP_CFG_INFO *negotiated_parameters); +static void disconnect_request_cb(uint16_t local_channel_id, bool ack_required); +static void disconnect_completed_cb(uint16_t local_channel_id, uint16_t error_code); +static void congestion_cb(uint16_t local_channel_id, bool is_congested); +static void read_ready_cb(uint16_t local_channel_id, BT_HDR *packet); +static void write_completed_cb(uint16_t local_channel_id, uint16_t packets_completed); + +static void fragment_packet(l2cap_client_t *client, buffer_t *packet); +static void dispatch_fragments(l2cap_client_t *client); +static l2cap_client_t *find(uint16_t local_channel_id); + +// From the Bluetooth Core specification. +static const uint16_t L2CAP_MTU_DEFAULT = 672; +static const uint16_t L2CAP_MTU_MINIMUM = 48; + +static const tL2CAP_APPL_INFO l2cap_callbacks = { + .pL2CA_ConnectCfm_Cb = connect_completed_cb, + .pL2CA_ConfigInd_Cb = config_request_cb, + .pL2CA_ConfigCfm_Cb = config_completed_cb, + .pL2CA_DisconnectInd_Cb = disconnect_request_cb, + .pL2CA_DisconnectCfm_Cb = disconnect_completed_cb, + .pL2CA_CongestionStatus_Cb = congestion_cb, + .pL2CA_DataInd_Cb = read_ready_cb, + .pL2CA_TxComplete_Cb = write_completed_cb, +}; + +static list_t *l2cap_clients; // A list of l2cap_client_t. Container does not own objects. + +buffer_t *l2cap_buffer_new(size_t size) { + buffer_t *buf = buffer_new(size + L2CAP_MIN_OFFSET); + buffer_t *slice = NULL; + if (buf) + slice = buffer_new_slice(buf, size); + buffer_free(buf); + return slice; +} + +l2cap_client_t *l2cap_client_new(const l2cap_client_callbacks_t *callbacks, void *context) { + assert(callbacks != NULL); + assert(callbacks->connected != NULL); + assert(callbacks->disconnected != NULL); + assert(callbacks->read_ready != NULL); + assert(callbacks->write_ready != NULL); + + if (!l2cap_clients) { + l2cap_clients = list_new(NULL); + if (!l2cap_clients) { + LOG_ERROR("%s unable to allocate space for L2CAP client list.", __func__); + return NULL; + } + } + + l2cap_client_t *ret = (l2cap_client_t *)osi_calloc(sizeof(l2cap_client_t)); + if (!ret) { + LOG_ERROR("%s unable to allocate L2CAP client.", __func__); + goto error; + } + + ret->callbacks = *callbacks; + ret->context = context; + + ret->remote_mtu = L2CAP_MTU_DEFAULT; + ret->outbound_fragments = list_new(NULL); + if (!ret) { + LOG_ERROR("%s unable to allocate outbound L2CAP fragment list.", __func__); + goto error; + } + + list_append(l2cap_clients, ret); + + return ret; + +error:; + osi_free(ret); + return NULL; +} + +void l2cap_client_free(l2cap_client_t *client) { + if (!client) + return; + + list_remove(l2cap_clients, client); + l2cap_client_disconnect(client); + list_free(client->outbound_fragments); + osi_free(client); +} + +bool l2cap_client_connect(l2cap_client_t *client, const bt_bdaddr_t *remote_bdaddr, uint16_t psm) { + assert(client != NULL); + assert(remote_bdaddr != NULL); + assert(psm != 0); + assert(!bdaddr_is_empty(remote_bdaddr)); + assert(client->local_channel_id == 0); + assert(!client->configured_self); + assert(!client->configured_peer); + assert(!L2C_INVALID_PSM(psm)); + + client->local_channel_id = L2CA_ConnectReq(psm, (uint8_t *)remote_bdaddr); + if (!client->local_channel_id) { + LOG_ERROR("%s unable to create L2CAP connection.", __func__); + return false; + } + + L2CA_SetConnectionCallbacks(client->local_channel_id, &l2cap_callbacks); + return true; +} + +void l2cap_client_disconnect(l2cap_client_t *client) { + assert(client != NULL); + + if (client->local_channel_id && !L2CA_DisconnectReq(client->local_channel_id)) + LOG_ERROR("%s unable to send disconnect message for LCID 0x%04x.", __func__, client->local_channel_id); + + client->local_channel_id = 0; + client->remote_mtu = L2CAP_MTU_DEFAULT; + client->configured_self = false; + client->configured_peer = false; + client->is_congested = false; + + for (const list_node_t *node = list_begin(client->outbound_fragments); node != list_end(client->outbound_fragments); node = list_next(node)) + GKI_freebuf(list_node(node)); + + list_clear(client->outbound_fragments); +} + +bool l2cap_client_is_connected(const l2cap_client_t *client) { + assert(client != NULL); + + return client->local_channel_id != 0 && client->configured_self && client->configured_peer; +} + +bool l2cap_client_write(l2cap_client_t *client, buffer_t *packet) { + assert(client != NULL); + assert(packet != NULL); + assert(l2cap_client_is_connected(client)); + + if (client->is_congested) + return false; + + fragment_packet(client, packet); + dispatch_fragments(client); + return true; +} + +static void connect_completed_cb(uint16_t local_channel_id, uint16_t error_code) { + assert(local_channel_id != 0); + + l2cap_client_t *client = find(local_channel_id); + if (!client) { + LOG_ERROR("%s unable to find L2CAP client for LCID 0x%04x.", __func__, local_channel_id); + return; + } + + if (error_code != L2CAP_CONN_OK) { + LOG_ERROR("%s error connecting L2CAP channel: %d.", __func__, error_code); + client->callbacks.disconnected(client, client->context); + return; + } + + // Use default L2CAP parameters. + tL2CAP_CFG_INFO desired_parameters = { 0 }; + if (!L2CA_ConfigReq(local_channel_id, &desired_parameters)) { + LOG_ERROR("%s error sending L2CAP config parameters.", __func__); + client->callbacks.disconnected(client, client->context); + } +} + +static void config_request_cb(uint16_t local_channel_id, tL2CAP_CFG_INFO *requested_parameters) { + tL2CAP_CFG_INFO response = { 0 }; + l2cap_client_t *client = find(local_channel_id); + + if (!client) { + LOG_ERROR("%s unable to find L2CAP client matching LCID 0x%04x.", __func__, local_channel_id); + return; + } + + response.result = L2CAP_CFG_OK; + + if (requested_parameters->mtu_present) { + // Make sure the peer chose an MTU at least as large as the minimum L2CAP MTU defined + // by the Bluetooth Core spec. + if (requested_parameters->mtu < L2CAP_MTU_MINIMUM) { + response.mtu = L2CAP_MTU_MINIMUM; + response.mtu_present = true; + response.result = L2CAP_CFG_UNACCEPTABLE_PARAMS; + } else { + client->remote_mtu = requested_parameters->mtu; + } + } + + if (requested_parameters->fcr_present) { + if (requested_parameters->fcr.mode != L2CAP_FCR_BASIC_MODE) { + response.fcr_present = true; + response.fcr = requested_parameters->fcr; + response.fcr.mode = L2CAP_FCR_BASIC_MODE; + response.result = L2CAP_CFG_UNACCEPTABLE_PARAMS; + } + } + + if (!L2CA_ConfigRsp(local_channel_id, &response)) { + LOG_ERROR("%s unable to send config response for LCID 0x%04x.", __func__, local_channel_id); + l2cap_client_disconnect(client); + return; + } + + // If we've configured both endpoints, let the listener know we've connected. + client->configured_peer = true; + if (l2cap_client_is_connected(client)) + client->callbacks.connected(client, client->context); +} + +static void config_completed_cb(uint16_t local_channel_id, tL2CAP_CFG_INFO *negotiated_parameters) { + l2cap_client_t *client = find(local_channel_id); + + if (!client) { + LOG_ERROR("%s unable to find L2CAP client matching LCID 0x%04x.", __func__, local_channel_id); + return; + } + + switch (negotiated_parameters->result) { + // We'll get another configuration response later. + case L2CAP_CFG_PENDING: + break; + + case L2CAP_CFG_UNACCEPTABLE_PARAMS: + // TODO: see if we can renegotiate parameters instead of dropping the connection. + LOG_WARN("%s dropping L2CAP connection due to unacceptable config parameters.", __func__); + l2cap_client_disconnect(client); + break; + + case L2CAP_CFG_OK: + // If we've configured both endpoints, let the listener know we've connected. + client->configured_self = true; + if (l2cap_client_is_connected(client)) + client->callbacks.connected(client, client->context); + break; + + // Failure, no further parameter negotiation possible. + default: + LOG_WARN("%s L2CAP parameter negotiation failed with error code %d.", __func__, negotiated_parameters->result); + l2cap_client_disconnect(client); + break; + } +} + +static void disconnect_request_cb(uint16_t local_channel_id, bool ack_required) { + l2cap_client_t *client = find(local_channel_id); + if (!client) { + LOG_ERROR("%s unable to find L2CAP client with LCID 0x%04x.", __func__, local_channel_id); + return; + } + + if (ack_required) + L2CA_DisconnectRsp(local_channel_id); + + // We already sent a disconnect response so this LCID is now invalid. + client->local_channel_id = 0; + l2cap_client_disconnect(client); + + client->callbacks.disconnected(client, client->context); +} + +static void disconnect_completed_cb(uint16_t local_channel_id, UNUSED_ATTR uint16_t error_code) { + assert(local_channel_id != 0); + + l2cap_client_t *client = find(local_channel_id); + if (!client) { + LOG_ERROR("%s unable to find L2CAP client with LCID 0x%04x.", __func__, local_channel_id); + return; + } + + client->local_channel_id = 0; + l2cap_client_disconnect(client); + + client->callbacks.disconnected(client, client->context); +} + +static void congestion_cb(uint16_t local_channel_id, bool is_congested) { + assert(local_channel_id != 0); + + l2cap_client_t *client = find(local_channel_id); + if (!client) { + LOG_ERROR("%s unable to find L2CAP client matching LCID 0x%04x.", __func__, local_channel_id); + return; + } + + client->is_congested = is_congested; + + if (!is_congested) { + // If we just decongested, dispatch whatever we have left over in our queue. + // Once that's done, if we're still decongested, notify the listener so it + // can start writing again. + dispatch_fragments(client); + if (!client->is_congested) + client->callbacks.write_ready(client, client->context); + } +} + +static void read_ready_cb(uint16_t local_channel_id, BT_HDR *packet) { + assert(local_channel_id != 0); + + l2cap_client_t *client = find(local_channel_id); + if (!client) { + LOG_ERROR("%s unable to find L2CAP client matching LCID 0x%04x.", __func__, local_channel_id); + return; + } + + // TODO(sharvil): eliminate copy from BT_HDR. + buffer_t *buffer = buffer_new(packet->len); + memcpy(buffer_ptr(buffer), packet->data + packet->offset, packet->len); + GKI_freebuf(packet); + + client->callbacks.read_ready(client, buffer, client->context); + buffer_free(buffer); +} + +static void write_completed_cb(UNUSED_ATTR uint16_t local_channel_id, UNUSED_ATTR uint16_t packets_completed) { + // Do nothing. We update congestion state based on the congestion callback + // and we've already removed items from outbound_fragments list so we don't + // really care how many packets were successfully dispatched. +} + +static void fragment_packet(l2cap_client_t *client, buffer_t *packet) { + assert(client != NULL); + assert(packet != NULL); + + // TODO(sharvil): eliminate copy into BT_HDR. + BT_HDR *bt_packet = GKI_getbuf(buffer_length(packet) + L2CAP_MIN_OFFSET); + bt_packet->offset = L2CAP_MIN_OFFSET; + bt_packet->len = buffer_length(packet); + memcpy(bt_packet->data + bt_packet->offset, buffer_ptr(packet), buffer_length(packet)); + + for (;;) { + if (bt_packet->len <= client->remote_mtu) { + if (bt_packet->len > 0) + list_append(client->outbound_fragments, bt_packet); + else + GKI_freebuf(bt_packet); + break; + } + + BT_HDR *fragment = GKI_getbuf(client->remote_mtu + L2CAP_MIN_OFFSET); + fragment->offset = L2CAP_MIN_OFFSET; + fragment->len = client->remote_mtu; + memcpy(fragment->data + fragment->offset, bt_packet->data + bt_packet->offset, client->remote_mtu); + + list_append(client->outbound_fragments, fragment); + + bt_packet->offset += client->remote_mtu; + bt_packet->len -= client->remote_mtu; + } +} + +static void dispatch_fragments(l2cap_client_t *client) { + assert(client != NULL); + assert(!client->is_congested); + + while (!list_is_empty(client->outbound_fragments)) { + BT_HDR *packet = (BT_HDR *)list_front(client->outbound_fragments); + list_remove(client->outbound_fragments, packet); + + switch (L2CA_DataWrite(client->local_channel_id, packet)) { + case L2CAP_DW_CONGESTED: + client->is_congested = true; + return; + + case L2CAP_DW_FAILED: + LOG_ERROR("%s error writing data to L2CAP connection LCID 0x%04x; disconnecting.", __func__, client->local_channel_id); + l2cap_client_disconnect(client); + return; + + case L2CAP_DW_SUCCESS: + break; + } + } +} + +static l2cap_client_t *find(uint16_t local_channel_id) { + assert(local_channel_id != 0); + + for (const list_node_t *node = list_begin(l2cap_clients); node != list_end(l2cap_clients); node = list_next(node)) { + l2cap_client_t *client = (l2cap_client_t *)list_node(node); + if (client->local_channel_id == local_channel_id) + return client; + } + + return NULL; +} + +#endif /*L2CAP_CLIENT_INCLUDED*/ diff --git a/components/bt/bluedroid/stack/rfcomm/include/port_int.h b/components/bt/bluedroid/stack/rfcomm/include/port_int.h new file mode 100755 index 0000000000..2313ace2a5 --- /dev/null +++ b/components/bt/bluedroid/stack/rfcomm/include/port_int.h @@ -0,0 +1,252 @@ +/****************************************************************************** + * + * Copyright (C) 1999-2012 Broadcom Corporation + * + * 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 definitions internal to the PORT unit + * + *****************************************************************************/ + +#ifndef PORT_INT_H +#define PORT_INT_H + +#include "bt_target.h" +#include "gki.h" +#include "rfcdefs.h" +#include "port_api.h" + +/* Local events passed when application event is sent from the api to PORT */ +/* ???*/ +#define PORT_EVENT_OPEN (1 | BT_EVT_TO_BTU_SP_EVT) +#define PORT_EVENT_CONTROL (2 | BT_EVT_TO_BTU_SP_EVT) +#define PORT_EVENT_SET_STATE (3 | BT_EVT_TO_BTU_SP_EVT) +#define PORT_EVENT_SET_CALLBACK (5 | BT_EVT_TO_BTU_SP_EVT) +#define PORT_EVENT_WRITE (6 | BT_EVT_TO_BTU_SP_EVT) +#define PORT_EVENT_PURGE (7 | BT_EVT_TO_BTU_SP_EVT) +#define PORT_EVENT_SEND_ERROR (8 | BT_EVT_TO_BTU_SP_EVT) +#define PORT_EVENT_FLOW_CONTROL (9 | BT_EVT_TO_BTU_SP_EVT) + +/* +** Flow control configuration values for the mux +*/ +#define PORT_FC_UNDEFINED 0 /* mux flow control mechanism not defined yet */ +#define PORT_FC_TS710 1 /* use TS 07.10 flow control */ +#define PORT_FC_CREDIT 2 /* use RFCOMM credit based flow control */ + +/* +** Define Port Data Transfere control block +*/ +typedef struct +{ + BUFFER_Q queue; /* Queue of buffers waiting to be sent */ + BOOLEAN peer_fc; /* TRUE if flow control is set based on peer's request */ + BOOLEAN user_fc; /* TRUE if flow control is set based on user's request */ + UINT32 queue_size; /* Number of data bytes in the queue */ + tPORT_CALLBACK *p_callback; /* Address of the callback function */ +} tPORT_DATA; + +/* +** Port control structure used to pass modem info +*/ +typedef struct +{ +#define MODEM_SIGNAL_DTRDSR 0x01 +#define MODEM_SIGNAL_RTSCTS 0x02 +#define MODEM_SIGNAL_RI 0x04 +#define MODEM_SIGNAL_DCD 0x08 + + UINT8 modem_signal; /* [DTR/DSR | RTS/CTS | RI | DCD ] */ + + UINT8 break_signal; /* 0-3 s in steps of 200 ms */ + + UINT8 discard_buffers; /* 0 - do not discard, 1 - discard */ + +#define RFCOMM_CTRL_BREAK_ASAP 0 +#define RFCOMM_CTRL_BREAK_IN_SEQ 1 + + UINT8 break_signal_seq; /* as soon as possible | in sequence (default) */ + + BOOLEAN fc; /* TRUE when the device is unable to accept frames */ +} tPORT_CTRL; + + +/* +** RFCOMM multiplexer Control Block +*/ +typedef struct +{ + TIMER_LIST_ENT tle; /* Timer list entry */ + BUFFER_Q cmd_q; /* Queue for command messages on this mux */ + UINT8 port_inx[RFCOMM_MAX_DLCI + 1]; /* Array for quick access to */ + /* tPORT based on dlci */ + BD_ADDR bd_addr; /* BD ADDR of the peer if initiator */ + UINT16 lcid; /* Local cid used for this channel */ + UINT16 peer_l2cap_mtu; /* Max frame that can be sent to peer L2CAP */ + UINT8 state; /* Current multiplexer channel state */ + UINT8 is_initiator; /* TRUE if this side sends SABME (dlci=0) */ + BOOLEAN local_cfg_sent; + BOOLEAN peer_cfg_rcvd; + BOOLEAN restart_required; /* TRUE if has to restart channel after disc */ + BOOLEAN peer_ready; /* True if other side can accept frames */ + UINT8 flow; /* flow control mechanism for this mux */ + BOOLEAN l2cap_congested; /* TRUE if L2CAP is congested */ + BOOLEAN is_disc_initiator; /* TRUE if initiated disc of port */ + UINT16 pending_lcid; /* store LCID for incoming connection while connecting */ + UINT8 pending_id; /* store l2cap ID for incoming connection while connecting */ +} tRFC_MCB; + + +/* +** RFCOMM Port Connection Control Block +*/ +struct t_rfc_port +{ +#define RFC_PORT_STATE_IDLE 0 +#define RFC_PORT_STATE_WAIT_START 1 +#define RFC_PORT_STATE_OPENING 2 +#define RFC_PORT_STATE_OPENED 3 +#define RFC_PORT_STATE_CLOSING 4 + + UINT8 state; /* Current state of the connection */ + +#define RFC_RSP_PN 0x01 +#define RFC_RSP_RPN_REPLY 0x02 +#define RFC_RSP_RPN 0x04 +#define RFC_RSP_MSC 0x08 +#define RFC_RSP_RLS 0x10 + + UINT8 expected_rsp; + + tRFC_MCB *p_mcb; + + TIMER_LIST_ENT tle; /* Timer list entry */ +}; +typedef struct t_rfc_port tRFC_PORT; + + +/* +** Define control block containing information about PORT connection +*/ +struct t_port_info +{ + UINT8 inx; /* Index of this control block in the port_info array */ + BOOLEAN in_use; /* True when structure is allocated */ + +#define PORT_STATE_CLOSED 0 +#define PORT_STATE_OPENING 1 +#define PORT_STATE_OPENED 2 +#define PORT_STATE_CLOSING 3 + + UINT8 state; /* State of the application */ + + UINT8 scn; /* Service channel number */ + UINT16 uuid; /* Service UUID */ + + BD_ADDR bd_addr; /* BD ADDR of the device for the multiplexer channel */ + BOOLEAN is_server; /* TRUE if the server application */ + UINT8 dlci; /* DLCI of the connection */ + + UINT8 error; /* Last error detected */ + + UINT8 line_status; /* Line status as reported by peer */ + + UINT8 default_signal_state; /* Initial signal state depending on uuid */ + + UINT16 mtu; /* Max MTU that port can receive */ + UINT16 peer_mtu; /* Max MTU that port can send */ + + tPORT_DATA tx; /* Control block for data from app to peer */ + tPORT_DATA rx; /* Control block for data from peer to app */ + + tPORT_STATE user_port_pars; /* Port parameters for user connection */ + tPORT_STATE peer_port_pars; /* Port parameters for user connection */ + + tPORT_CTRL local_ctrl; + tPORT_CTRL peer_ctrl; + +#define PORT_CTRL_REQ_SENT 0x01 +#define PORT_CTRL_REQ_CONFIRMED 0x02 +#define PORT_CTRL_IND_RECEIVED 0x04 +#define PORT_CTRL_IND_RESPONDED 0x08 + + UINT8 port_ctrl; /* Modem Status Command */ + + BOOLEAN rx_flag_ev_pending; /* RXFLAG Character is received */ + + tRFC_PORT rfc; /* RFCOMM port control block */ + + UINT32 ev_mask; /* Event mask for the callback */ + tPORT_CALLBACK *p_callback; /* Pointer to users callback function */ + tPORT_CALLBACK *p_mgmt_callback; /* Callback function to receive connection up/down */ + tPORT_DATA_CALLBACK *p_data_callback; /* Callback function to receive data indications */ + tPORT_DATA_CO_CALLBACK *p_data_co_callback; /* Callback function with callouts and flowctrl */ + UINT16 credit_tx; /* Flow control credits for tx path */ + UINT16 credit_rx; /* Flow control credits for rx path, this is */ + /* number of buffers peer is allowed to sent */ + UINT16 credit_rx_max; /* Max number of credits we will allow this guy to sent */ + UINT16 credit_rx_low; /* Number of credits when we send credit update */ + UINT16 rx_buf_critical; /* port receive queue critical watermark level */ + BOOLEAN keep_port_handle; /* TRUE if port is not deallocated when closing */ + /* it is set to TRUE for server when allocating port */ + UINT16 keep_mtu; /* Max MTU that port can receive by server */ +}; +typedef struct t_port_info tPORT; + + +/* Define the PORT/RFCOMM control structure +*/ +typedef struct +{ + tPORT port[MAX_RFC_PORTS]; /* Port info pool */ + tRFC_MCB rfc_mcb[MAX_BD_CONNECTIONS]; /* RFCOMM bd_connections pool */ +} tPORT_CB; + +#ifdef __cplusplus +extern "C" { +#endif + +/* +** Functions provided by the port_utils.c +*/ +extern tPORT *port_allocate_port (UINT8 dlci, BD_ADDR bd_addr); +extern void port_set_defaults (tPORT *p_port); +extern void port_select_mtu (tPORT *p_port); +extern void port_release_port (tPORT *p_port); +extern tPORT *port_find_mcb_dlci_port (tRFC_MCB *p_mcb, UINT8 dlci); +extern tRFC_MCB *port_find_mcb (BD_ADDR bd_addr); +extern tPORT *port_find_dlci_port (UINT8 dlci); +extern tPORT *port_find_port (UINT8 dlci, BD_ADDR bd_addr); +extern UINT32 port_get_signal_changes (tPORT *p_port, UINT8 old_signals, UINT8 signal); +extern UINT32 port_flow_control_user (tPORT *p_port); +extern void port_flow_control_peer(tPORT *p_port, BOOLEAN enable, UINT16 count); + +/* +** Functions provided by the port_rfc.c +*/ +extern int port_open_continue (tPORT *p_port); +extern void port_start_port_open (tPORT *p_port); +extern void port_start_par_neg (tPORT *p_port); +extern void port_start_control (tPORT *p_port); +extern void port_start_close (tPORT *p_port); +extern void port_rfc_closed (tPORT *p_port, UINT8 res); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/components/bt/bluedroid/stack/rfcomm/include/rfc_int.h b/components/bt/bluedroid/stack/rfcomm/include/rfc_int.h new file mode 100755 index 0000000000..719a99df85 --- /dev/null +++ b/components/bt/bluedroid/stack/rfcomm/include/rfc_int.h @@ -0,0 +1,386 @@ +/****************************************************************************** + * + * Copyright (C) 1999-2012 Broadcom Corporation + * + * 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 definitions internal to the RFC unit + * + *****************************************************************************/ + +#ifndef RFC_INT_H +#define RFC_INT_H + +#include "l2c_api.h" +#include "port_int.h" + +/* +** Define RFCOMM result codes +*/ +#define RFCOMM_SUCCESS 0 +#define RFCOMM_ERROR 1 +#define RFCOMM_LOW_RESOURCES 2 +#define RFCOMM_TRY_LATER 3 + +#define RFCOMM_USER_ERR 111 +#define RFCOMM_SECURITY_ERR 112 + +/* +** Define max and min RFCOMM MTU (N1) +*/ +#define RFCOMM_MIN_MTU 23 +#define RFCOMM_MAX_MTU 32767 + +extern void RFCOMM_StartReq (tRFC_MCB *p_mcb); +extern void RFCOMM_StartRsp (tRFC_MCB *p_mcb, UINT16 result); + +extern void RFCOMM_DlcEstablishReq (tRFC_MCB *p_mcb, UINT8 dlci, UINT16 mtu); +extern void RFCOMM_DlcEstablishRsp (tRFC_MCB *p_mcb, UINT8 dlci, UINT16 mtu, UINT16 result); + +extern void RFCOMM_DataReq (tRFC_MCB *p_mcb, UINT8 dlci, BT_HDR *p_buf); + +extern void RFCOMM_DlcReleaseReq (tRFC_MCB *p_mcb, UINT8 dlci); + +extern void RFCOMM_ParNegReq (tRFC_MCB *p_mcb, UINT8 dlci, UINT16 mtu); +extern void RFCOMM_ParNegRsp (tRFC_MCB *p_mcb, UINT8 dlci, UINT16 mtu, UINT8 cl, UINT8 k); + +extern void RFCOMM_TestReq (UINT8 *p_data, UINT16 len); + +#define RFCOMM_FLOW_STATE_DISABLE 0 +#define RFCOMM_FLOW_STATE_ENABLE 1 + +extern void RFCOMM_FlowReq (tRFC_MCB *p_mcb, UINT8 dlci, UINT8 state); + +extern void RFCOMM_PortNegReq (tRFC_MCB *p_mcb, UINT8 dlci, tPORT_STATE *p_pars); +extern void RFCOMM_PortNegRsp (tRFC_MCB *p_mcb, UINT8 dlci, tPORT_STATE *p_pars, UINT16 param_mask); + +extern void RFCOMM_ControlReq (tRFC_MCB *p_mcb, UINT8 dlci, tPORT_CTRL *p_pars); +extern void RFCOMM_ControlRsp (tRFC_MCB *p_mcb, UINT8 dlci, tPORT_CTRL *p_pars); + +extern void RFCOMM_LineStatusReq (tRFC_MCB *p_mcb, UINT8 dlci, UINT8 line_status); +/* +** Define logical struct used for sending and decoding MX frames +*/ +typedef struct +{ + UINT8 dlci; + UINT8 type; + UINT8 cr; + UINT8 ea; + UINT8 pf; + UINT8 credit; + + union + { + struct + { + UINT8 dlci; + UINT8 frame_type; + UINT8 conv_layer; + UINT8 priority; + UINT8 t1; + UINT16 mtu; + UINT8 n2; + UINT8 k; + } pn; + struct + { + UINT8 *p_data; + UINT16 data_len; + } test; + struct + { + UINT8 dlci; + UINT8 signals; + UINT8 break_present; + UINT8 break_duration; + } msc; + struct + { + UINT8 ea; + UINT8 cr; + UINT8 type; + } nsc; + struct + { + UINT8 dlci; + UINT8 is_request; + UINT8 baud_rate; + UINT8 byte_size; + UINT8 stop_bits; + UINT8 parity; + UINT8 parity_type; + UINT8 fc_type; + UINT8 xon_char; + UINT8 xoff_char; + UINT16 param_mask; + } rpn; + struct + { + UINT8 dlci; + UINT8 line_status; + } rls; + } u; +} MX_FRAME; + +#define LINE_STATUS_NO_ERROR 0x00 +#define LINE_STATUS_OVERRUN 0x02 /* Receive Overrun Error */ +#define LINE_STATUS_RXPARITY 0x04 /* Receive Parity Error */ +#define LINE_STATUS_FRAME 0x08 /* Receive Framing error */ +#define LINE_STATUS_FAILED 0x10 /* Connection Failed */ + +/* +** Define states and events for the RFC multiplexer state machine +*/ +#define RFC_MX_STATE_IDLE 0 +#define RFC_MX_STATE_WAIT_CONN_CNF 1 +#define RFC_MX_STATE_CONFIGURE 2 +#define RFC_MX_STATE_SABME_WAIT_UA 3 +#define RFC_MX_STATE_WAIT_SABME 4 +#define RFC_MX_STATE_CONNECTED 5 +#define RFC_MX_STATE_DISC_WAIT_UA 6 + +/* +** Define port states +*/ +#define RFC_STATE_CLOSED 0 +#define RFC_STATE_SABME_WAIT_UA 1 +#define RFC_STATE_ORIG_WAIT_SEC_CHECK 2 +#define RFC_STATE_TERM_WAIT_SEC_CHECK 3 +#define RFC_STATE_OPENED 4 +#define RFC_STATE_DISC_WAIT_UA 5 + +/* +** Events that can be received by multiplexer as well as port state machines +*/ +#define RFC_EVENT_SABME 0 +#define RFC_EVENT_UA 1 +#define RFC_EVENT_DM 2 +#define RFC_EVENT_DISC 3 +#define RFC_EVENT_UIH 4 +#define RFC_EVENT_TIMEOUT 5 +#define RFC_EVENT_BAD_FRAME 50 +/* +** Multiplexer events +*/ +#define RFC_MX_EVENT_START_REQ 6 +#define RFC_MX_EVENT_START_RSP 7 +#define RFC_MX_EVENT_CLOSE_REQ 8 +#define RFC_MX_EVENT_CONN_CNF 9 +#define RFC_MX_EVENT_CONN_IND 10 +#define RFC_MX_EVENT_CONF_CNF 11 +#define RFC_MX_EVENT_CONF_IND 12 +#define RFC_MX_EVENT_QOS_VIOLATION_IND 13 +#define RFC_MX_EVENT_DISC_IND 14 +#define RFC_MX_EVENT_TEST_CMD 15 +#define RFC_MX_EVENT_TEST_RSP 16 +#define RFC_MX_EVENT_FCON_CMD 17 +#define RFC_MX_EVENT_FCOFF_CMD 18 +#define RFC_MX_EVENT_NSC 19 +#define RFC_MX_EVENT_NSC_RSP 20 + +/* +** Port events +*/ +#define RFC_EVENT_OPEN 9 +#define RFC_EVENT_ESTABLISH_RSP 11 +#define RFC_EVENT_CLOSE 12 +#define RFC_EVENT_CLEAR 13 +#define RFC_EVENT_DATA 14 +#define RFC_EVENT_SEC_COMPLETE 15 + +// btla-specific ++ +#define RFC_T1_TIMEOUT 20 /* seconds to wait for reply with Poll bit */ +#define RFC_PORT_T1_TIMEOUT 60 /* seconds to wait for reply with Poll bit other than MX */ +#define RFC_T2_TIMEOUT 20 /* timeout to wait for Mx UIH */ +// btla-specific -- +#define RFC_DISC_TIMEOUT 3 /* If something goes wrong and we send DISC we should not wait for min */ +#define RFC_CLOSE_TIMEOUT 10 +#define RFCOMM_CONN_TIMEOUT 120 /* first connection to be established on Mx */ + + +/* Define RFComm control block +*/ +typedef struct +{ + MX_FRAME rx_frame; + tL2CAP_APPL_INFO reg_info; /* L2CAP Registration info */ + tRFC_MCB *p_rfc_lcid_mcb[MAX_L2CAP_CHANNELS]; /* MCB based on the L2CAP's lcid */ + BOOLEAN peer_rx_disabled; /* If TRUE peer sent FCOFF */ + UINT8 last_mux; /* Last mux allocated */ + UINT8 last_port; /* Last port allocated */ +} tRFCOMM_CB; + +/* Main Control Block for the RFCOMM Layer (PORT and RFC) */ +typedef struct +{ + tRFCOMM_CB rfc; + tPORT_CB port; + UINT8 trace_level; +} tRFC_CB; + + +#if RFC_DYNAMIC_MEMORY == FALSE +extern tRFC_CB rfc_cb; +#else +extern tRFC_CB *rfc_cb_ptr; +#define rfc_cb (*rfc_cb_ptr) +#endif + +/* Timer running on the multiplexor channel while no DLCI connection is opened */ +#define RFC_MCB_INIT_INACT_TIMER 60 /* in seconds */ + +/* Timer running on the multiplexor channel after last DLCI is released */ +#define RFC_MCB_RELEASE_INACT_TIMER 2 /* in seconds */ + +/* +** Define RFCOMM frame processing errors +*/ +#define RFCOMM_ERR_BAD_SABME 1 +#define RFCOMM_ERR_BAD_UA 2 +#define RFCOMM_ERR_BAD_DM 3 +#define RFCOMM_ERR_BAD_DISC 4 +#define RFCOMM_ERR_BAD_UIH 5 + +#ifdef RFCOMM_PRECALC_FCS + +#define RFCOMM_SABME_FCS(p_data, cr, dlci) rfc_sabme_fcs[cr][dlci] +#define RFCOMM_UA_FCS(p_data, cr, dlci) rfc_ua_fcs[cr][dlci] +#define RFCOMM_DM_FCS(p_data, cr, dlci) rfc_dm_fcs[cr][dlci] +#define RFCOMM_DISC_FCS(p_data, cr, dlci) rfc_disc_fcs[cr][dlci] +#define RFCOMM_UIH_FCS(p_data, dlci) rfc_uih_fcs[dlci] + +#else + +extern UINT8 rfc_calc_fcs (UINT16 len, UINT8 *p); + +#define RFCOMM_SABME_FCS(p_data, cr, dlci) rfc_calc_fcs(3, p_data) +#define RFCOMM_UA_FCS(p_data, cr, dlci) rfc_calc_fcs(3, p_data) +#define RFCOMM_DM_FCS(p_data, cr, dlci) rfc_calc_fcs(3, p_data) +#define RFCOMM_DISC_FCS(p_data, cr, dlci) rfc_calc_fcs(3, p_data) +#define RFCOMM_UIH_FCS(p_data, dlci) rfc_calc_fcs(2, p_data) + +#endif + + +#ifdef __cplusplus +extern "C" { +#endif + +extern void rfc_mx_sm_execute (tRFC_MCB *p_mcb, UINT16 event, void *p_data); + +/* +** Functions provided by the rfc_port_fsm.c +*/ +extern void rfc_port_sm_execute (tPORT *p_port, UINT16 event, void *p_data); + + +extern void rfc_process_pn (tRFC_MCB *p_rfc_mcb, BOOLEAN is_command, MX_FRAME *p_frame); +extern void rfc_process_msc (tRFC_MCB *p_rfc_mcb, BOOLEAN is_command, MX_FRAME *p_frame); +extern void rfc_process_rpn (tRFC_MCB *p_rfc_mcb, BOOLEAN is_command, BOOLEAN is_request, MX_FRAME *p_frame); +extern void rfc_process_rls (tRFC_MCB *p_rfc_mcb, BOOLEAN is_command, MX_FRAME *p_frame); +extern void rfc_process_nsc (tRFC_MCB *p_rfc_mcb, MX_FRAME *p_frame); +extern void rfc_process_test_rsp (tRFC_MCB *p_rfc_mcb, BT_HDR *p_buf); +extern void rfc_process_fcon (tRFC_MCB *p_rfc_mcb, BOOLEAN is_command); +extern void rfc_process_fcoff (tRFC_MCB *p_rfc_mcb, BOOLEAN is_command); +extern void rfc_process_l2cap_congestion (tRFC_MCB *p_mcb, BOOLEAN is_congested); + +/* +** Functions provided by the rfc_utils.c +*/ +tRFC_MCB *rfc_alloc_multiplexer_channel (BD_ADDR bd_addr, BOOLEAN is_initiator); +extern void rfc_release_multiplexer_channel (tRFC_MCB *p_rfc_mcb); +extern void rfc_timer_start (tRFC_MCB *p_rfc_mcb, UINT16 timeout); +extern void rfc_timer_stop (tRFC_MCB *p_rfc_mcb); +extern void rfc_port_timer_start (tPORT *p_port, UINT16 tout); +extern void rfc_port_timer_stop (tPORT *p_port); + +BOOLEAN rfc_check_uih_fcs (UINT8 dlci, UINT8 received_fcs); +BOOLEAN rfc_check_fcs (UINT16 len, UINT8 *p, UINT8 received_fcs); +tRFC_MCB *rfc_find_lcid_mcb (UINT16 lcid); +extern void rfc_save_lcid_mcb (tRFC_MCB *p_rfc_mcb, UINT16 lcid); +extern void rfc_check_mcb_active (tRFC_MCB *p_mcb); +extern void rfc_port_closed (tPORT *p_port); +extern void rfc_sec_check_complete (BD_ADDR bd_addr, tBT_TRANSPORT transport,void *p_ref_data, UINT8 res); +extern void rfc_inc_credit (tPORT *p_port, UINT8 credit); +extern void rfc_dec_credit (tPORT *p_port); +extern void rfc_check_send_cmd(tRFC_MCB *p_mcb, BT_HDR *p_buf); + +/* +** Functions provided by the rfc_ts_frames.c +*/ +extern void rfc_send_sabme (tRFC_MCB *p_rfc_mcb, UINT8 dlci); +extern void rfc_send_ua (tRFC_MCB *p_rfc_mcb, UINT8 dlci); +extern void rfc_send_dm (tRFC_MCB *p_rfc_mcb, UINT8 dlci, BOOLEAN pf); +extern void rfc_send_disc (tRFC_MCB *p_rfc_mcb, UINT8 dlci); +extern void rfc_send_pn (tRFC_MCB *p_mcb, UINT8 dlci, BOOLEAN is_command, UINT16 mtu, + UINT8 cl, UINT8 k); +extern void rfc_send_test (tRFC_MCB *p_rfc_mcb, BOOLEAN is_command, BT_HDR *p_buf); +extern void rfc_send_msc (tRFC_MCB *p_mcb, UINT8 dlci, BOOLEAN is_command, + tPORT_CTRL *p_pars); +extern void rfc_send_rls (tRFC_MCB *p_mcb, UINT8 dlci, BOOLEAN is_command, UINT8 status); +extern void rfc_send_rpn (tRFC_MCB *p_mcb, UINT8 dlci, BOOLEAN is_command, + tPORT_STATE *p_pars, UINT16 mask); +extern void rfc_send_fcon (tRFC_MCB *p_mcb, BOOLEAN is_command); +extern void rfc_send_fcoff (tRFC_MCB *p_mcb, BOOLEAN is_command); +extern void rfc_send_buf_uih (tRFC_MCB *p_rfc_mcb, UINT8 dlci, BT_HDR *p_buf); +extern void rfc_send_credit(tRFC_MCB *p_mcb, UINT8 dlci, UINT8 credit); +extern void rfc_process_mx_message (tRFC_MCB *p_rfc_mcb, BT_HDR *p_buf); +extern UINT8 rfc_parse_data (tRFC_MCB *p_rfc_mcb, MX_FRAME *p_frame, BT_HDR *p_buf); + +/* +** Functions provided by the rfc_disp.c +*/ + + + +/* Call back functions from RFCOMM */ +extern void rfcomm_l2cap_if_init (void); + +extern void PORT_StartInd (tRFC_MCB *p_mcb); +extern void PORT_StartCnf (tRFC_MCB *p_mcb, UINT16 result); + +extern void PORT_CloseInd (tRFC_MCB *p_mcb); +extern void Port_TimeOutCloseMux (tRFC_MCB *p_mcb); + +extern void PORT_DlcEstablishInd (tRFC_MCB *p_mcb, UINT8 dlci, UINT16 mtu); +extern void PORT_DlcEstablishCnf (tRFC_MCB *p_mcb, UINT8 dlci, UINT16 mtu, UINT16 result); + +extern void PORT_DataInd (tRFC_MCB *p_mcb, UINT8 dlci, BT_HDR *p_buf); + +extern void PORT_DlcReleaseInd (tRFC_MCB *p_mcb, UINT8 dlci); + +extern void PORT_ParNegInd (tRFC_MCB *p_mcb, UINT8 dlci, UINT16 mtu, UINT8 cl, UINT8 k); +extern void PORT_ParNegCnf (tRFC_MCB *p_mcb, UINT8 dlci, UINT16 mtu, UINT8 cl, UINT8 k); + +extern void PORT_TestCnf (tRFC_MCB *p_mcb, UINT8 *p_data, UINT16 len); + +extern void PORT_FlowInd (tRFC_MCB *p_mcb, UINT8 dlci, BOOLEAN fc); + +extern void PORT_PortNegInd (tRFC_MCB *p_mcb, UINT8 dlci, tPORT_STATE *p_pars, UINT16 param_mask); +extern void PORT_PortNegCnf (tRFC_MCB *p_mcb, UINT8 dlci, tPORT_STATE *p_pars, UINT16 result); + +extern void PORT_ControlInd (tRFC_MCB *p_mcb, UINT8 dlci, tPORT_CTRL *p_pars); +extern void PORT_ControlCnf (tRFC_MCB *p_mcb, UINT8 dlci, tPORT_CTRL *p_pars); + +extern void PORT_LineStatusInd (tRFC_MCB *p_mcb, UINT8 dlci, UINT8 line_status); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/components/bt/bluedroid/stack/rfcomm/port_api.c b/components/bt/bluedroid/stack/rfcomm/port_api.c new file mode 100755 index 0000000000..94e49bcb72 --- /dev/null +++ b/components/bt/bluedroid/stack/rfcomm/port_api.c @@ -0,0 +1,1884 @@ +/****************************************************************************** + * + * Copyright (C) 1999-2012 Broadcom Corporation + * + * 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 Serial Port API code + * + ******************************************************************************/ + +#include +#include "bt_target.h" +#include "gki.h" +#include "rfcdefs.h" +#include "port_api.h" +#include "port_int.h" +#include "btm_int.h" +#include "btm_api.h" +#include "rfc_int.h" +#include "l2c_api.h" +#include "sdp_api.h" + +/* duration of break in 200ms units */ +#define PORT_BREAK_DURATION 1 + +/* Mapping from PORT_* result codes to human readable strings. */ +static const char *result_code_strings[] = { + "Success", + "Unknown error", + "Already opened", + "Command pending", + "App not registered", + "No memory", + "No resources", + "Bad BD address", + "Unspecified error", + "Bad handle", + "Not opened", + "Line error", + "Start failed", + "Parameter negotiation failed", + "Port negotiation failed", + "Sec failed", + "Peer connection failed", + "Peer failed", + "Peer timeout", + "Closed", + "TX full", + "Local closed", + "Local timeout", + "TX queue disabled", + "Page timeout", + "Invalid SCN", + "Unknown result code" +}; + +/******************************************************************************* +** +** Function RFCOMM_CreateConnection +** +** Description RFCOMM_CreateConnection function is used from the application +** to establish serial port connection to the peer device, +** or allow RFCOMM to accept a connection from the peer +** application. +** +** Parameters: scn - Service Channel Number as registered with +** the SDP (server) or obtained using SDP from +** the peer device (client). +** is_server - TRUE if requesting application is a server +** mtu - Maximum frame size the application can accept +** bd_addr - BD_ADDR of the peer (client) +** mask - specifies events to be enabled. A value +** of zero disables all events. +** p_handle - OUT pointer to the handle. +** p_mgmt_cb - pointer to callback function to receive +** connection up/down events. +** Notes: +** +** Server can call this function with the same scn parameter multiple times if +** it is ready to accept multiple simulteneous connections. +** +** DLCI for the connection is (scn * 2 + 1) if client originates connection on +** existing none initiator multiplexer channel. Otherwise it is (scn * 2). +** For the server DLCI can be changed later if client will be calling it using +** (scn * 2 + 1) dlci. +** +*******************************************************************************/ +int RFCOMM_CreateConnection (UINT16 uuid, UINT8 scn, BOOLEAN is_server, + UINT16 mtu, BD_ADDR bd_addr, UINT16 *p_handle, + tPORT_CALLBACK *p_mgmt_cb) +{ + tPORT *p_port; + int i; + UINT8 dlci; + tRFC_MCB *p_mcb = port_find_mcb (bd_addr); + UINT16 rfcomm_mtu; + + RFCOMM_TRACE_API ("RFCOMM_CreateConnection() BDA: %02x-%02x-%02x-%02x-%02x-%02x", + bd_addr[0], bd_addr[1], bd_addr[2], bd_addr[3], bd_addr[4], bd_addr[5]); + + *p_handle = 0; + + if (( scn == 0 )||(scn >= PORT_MAX_RFC_PORTS )) + { + /* Server Channel Number(SCN) should be in range 1...30 */ + RFCOMM_TRACE_ERROR ("RFCOMM_CreateConnection - invalid SCN"); + return (PORT_INVALID_SCN); + } + + /* For client that originate connection on the existing none initiator */ + /* multiplexer channel DLCI should be odd */ + if (p_mcb && !p_mcb->is_initiator && !is_server) + dlci = (scn << 1) + 1; + else + dlci = (scn << 1); + RFCOMM_TRACE_API("RFCOMM_CreateConnection(): scn:%d, dlci:%d, is_server:%d mtu:%d, p_mcb:%p", + scn, dlci, is_server, mtu, p_mcb); + + /* For the server side always allocate a new port. On the client side */ + /* do not allow the same (dlci, bd_addr) to be opened twice by application */ + if (!is_server && ((p_port = port_find_port (dlci, bd_addr)) != NULL)) + { + /* if existing port is also a client port */ + if (p_port->is_server == FALSE) + { + RFCOMM_TRACE_ERROR ("RFCOMM_CreateConnection - already opened state:%d, RFC state:%d, MCB state:%d", + p_port->state, p_port->rfc.state, p_port->rfc.p_mcb ? p_port->rfc.p_mcb->state : 0); + return (PORT_ALREADY_OPENED); + } + } + + if ((p_port = port_allocate_port (dlci, bd_addr)) == NULL) + { + RFCOMM_TRACE_WARNING ("RFCOMM_CreateConnection - no resources"); + return (PORT_NO_RESOURCES); + } + RFCOMM_TRACE_API("RFCOMM_CreateConnection(): scn:%d, dlci:%d, is_server:%d mtu:%d, p_mcb:%p, p_port:%p", + scn, dlci, is_server, mtu, p_mcb, p_port); + + p_port->default_signal_state = (PORT_DTRDSR_ON | PORT_CTSRTS_ON | PORT_DCD_ON); + + switch (uuid) + { + case UUID_PROTOCOL_OBEX: + p_port->default_signal_state = PORT_OBEX_DEFAULT_SIGNAL_STATE; + break; + case UUID_SERVCLASS_SERIAL_PORT: + p_port->default_signal_state = PORT_SPP_DEFAULT_SIGNAL_STATE; + break; + case UUID_SERVCLASS_LAN_ACCESS_USING_PPP: + p_port->default_signal_state = PORT_PPP_DEFAULT_SIGNAL_STATE; + break; + case UUID_SERVCLASS_DIALUP_NETWORKING: + case UUID_SERVCLASS_FAX: + p_port->default_signal_state = PORT_DUN_DEFAULT_SIGNAL_STATE; + break; + } + + RFCOMM_TRACE_EVENT ("RFCOMM_CreateConnection dlci:%d signal state:0x%x", dlci, p_port->default_signal_state); + + *p_handle = p_port->inx; + + p_port->state = PORT_STATE_OPENING; + p_port->uuid = uuid; + p_port->is_server = is_server; + p_port->scn = scn; + p_port->ev_mask = 0; + + /* If the MTU is not specified (0), keep MTU decision until the + * PN frame has to be send + * at that time connection should be established and we + * will know for sure our prefered MTU + */ + + rfcomm_mtu = L2CAP_MTU_SIZE - RFCOMM_DATA_OVERHEAD; + + if (mtu) + p_port->mtu = (mtu < rfcomm_mtu) ? mtu : rfcomm_mtu; + else + p_port->mtu = rfcomm_mtu; + + /* server doesn't need to release port when closing */ + if( is_server ) + { + p_port->keep_port_handle = TRUE; + + /* keep mtu that user asked, p_port->mtu could be updated during param negotiation */ + p_port->keep_mtu = p_port->mtu; + } + + p_port->local_ctrl.modem_signal = p_port->default_signal_state; + p_port->local_ctrl.fc = FALSE; + + p_port->p_mgmt_callback = p_mgmt_cb; + + for (i = 0; i < BD_ADDR_LEN; i++) + p_port->bd_addr[i] = bd_addr[i]; + + /* If this is not initiator of the connection need to just wait */ + if (p_port->is_server) + { + return (PORT_SUCCESS); + } + + /* Open will be continued after security checks are passed */ + return port_open_continue (p_port); +} + + +/******************************************************************************* +** +** Function RFCOMM_RemoveConnection +** +** Description This function is called to close the specified connection. +** +** Parameters: handle - Handle returned in the RFCOMM_CreateConnection +** +*******************************************************************************/ +int RFCOMM_RemoveConnection (UINT16 handle) +{ + tPORT *p_port; + + RFCOMM_TRACE_API ("RFCOMM_RemoveConnection() handle:%d", handle); + + /* Check if handle is valid to avoid crashing */ + if ((handle == 0) || (handle > MAX_RFC_PORTS)) + { + RFCOMM_TRACE_ERROR ("RFCOMM_RemoveConnection() BAD handle:%d", handle); + return (PORT_BAD_HANDLE); + } + p_port = &rfc_cb.port.port[handle - 1]; + + if (!p_port->in_use || (p_port->state == PORT_STATE_CLOSED)) + { + RFCOMM_TRACE_EVENT ("RFCOMM_RemoveConnection() Not opened:%d", handle); + return (PORT_SUCCESS); + } + + p_port->state = PORT_STATE_CLOSING; + + port_start_close (p_port); + + return (PORT_SUCCESS); +} + +/******************************************************************************* +** +** Function RFCOMM_RemoveServer +** +** Description This function is called to close the server port. +** +** Parameters: handle - Handle returned in the RFCOMM_CreateConnection +** +*******************************************************************************/ +int RFCOMM_RemoveServer (UINT16 handle) +{ + tPORT *p_port; + + RFCOMM_TRACE_API ("RFCOMM_RemoveServer() handle:%d", handle); + + /* Check if handle is valid to avoid crashing */ + if ((handle == 0) || (handle > MAX_RFC_PORTS)) + { + RFCOMM_TRACE_ERROR ("RFCOMM_RemoveServer() BAD handle:%d", handle); + return (PORT_BAD_HANDLE); + } + p_port = &rfc_cb.port.port[handle - 1]; + + /* Do not report any events to the client any more. */ + p_port->p_mgmt_callback = NULL; + + if (!p_port->in_use || (p_port->state == PORT_STATE_CLOSED)) + { + RFCOMM_TRACE_EVENT ("RFCOMM_RemoveServer() Not opened:%d", handle); + return (PORT_SUCCESS); + } + + /* this port will be deallocated after closing */ + p_port->keep_port_handle = FALSE; + p_port->state = PORT_STATE_CLOSING; + + port_start_close (p_port); + + return (PORT_SUCCESS); +} + +/******************************************************************************* +** +** Function PORT_SetEventCallback +** +** Description This function is called to provide an address of the +** function which will be called when one of the events +** specified in the mask occures. +** +** Parameters: handle - Handle returned in the RFCOMM_CreateConnection +** p_callback - address of the callback function which should +** be called from the RFCOMM when an event +** specified in the mask occures. +** +** +*******************************************************************************/ +int PORT_SetEventCallback (UINT16 port_handle, tPORT_CALLBACK *p_port_cb) +{ + tPORT *p_port; + + /* Check if handle is valid to avoid crashing */ + if ((port_handle == 0) || (port_handle > MAX_RFC_PORTS)) + { + return (PORT_BAD_HANDLE); + } + + p_port = &rfc_cb.port.port[port_handle - 1]; + + if (!p_port->in_use || (p_port->state == PORT_STATE_CLOSED)) + { + return (PORT_NOT_OPENED); + } + + RFCOMM_TRACE_API ("PORT_SetEventCallback() handle:%d", port_handle); + + p_port->p_callback = p_port_cb; + + return (PORT_SUCCESS); +} +/******************************************************************************* +** +** Function PORT_ClearKeepHandleFlag +** +** Description This function is called to clear the keep handle flag +** which will cause not to keep the port handle open when closed +** Parameters: handle - Handle returned in the RFCOMM_CreateConnection +** +*******************************************************************************/ + +int PORT_ClearKeepHandleFlag (UINT16 port_handle) +{ + tPORT *p_port; + + /* Check if handle is valid to avoid crashing */ + if ((port_handle == 0) || (port_handle > MAX_RFC_PORTS)) + { + return (PORT_BAD_HANDLE); + } + + p_port = &rfc_cb.port.port[port_handle - 1]; + p_port->keep_port_handle = 0; + return (PORT_SUCCESS); +} + +/******************************************************************************* +** +** Function PORT_SetDataCallback +** +** Description This function is when a data packet is received +** +** Parameters: handle - Handle returned in the RFCOMM_CreateConnection +** p_callback - address of the callback function which should +** be called from the RFCOMM when data packet +** is received. +** +** +*******************************************************************************/ +int PORT_SetDataCallback (UINT16 port_handle, tPORT_DATA_CALLBACK *p_port_cb) +{ + tPORT *p_port; + + RFCOMM_TRACE_API ("PORT_SetDataCallback() handle:%d cb 0x%x", port_handle, p_port_cb); + + /* Check if handle is valid to avoid crashing */ + if ((port_handle == 0) || (port_handle > MAX_RFC_PORTS)) + { + return (PORT_BAD_HANDLE); + } + + p_port = &rfc_cb.port.port[port_handle - 1]; + + if (!p_port->in_use || (p_port->state == PORT_STATE_CLOSED)) + { + return (PORT_NOT_OPENED); + } + + p_port->p_data_callback = p_port_cb; + + return (PORT_SUCCESS); +} +/******************************************************************************* +** +** Function PORT_SetCODataCallback +** +** Description This function is when a data packet is received +** +** Parameters: handle - Handle returned in the RFCOMM_CreateConnection +** p_callback - address of the callback function which should +** be called from the RFCOMM when data packet +** is received. +** +** +*******************************************************************************/ +int PORT_SetDataCOCallback (UINT16 port_handle, tPORT_DATA_CO_CALLBACK *p_port_cb) +{ + tPORT *p_port; + + RFCOMM_TRACE_API ("PORT_SetDataCOCallback() handle:%d cb 0x%x", port_handle, p_port_cb); + + /* Check if handle is valid to avoid crashing */ + if ((port_handle == 0) || (port_handle > MAX_RFC_PORTS)) + { + return (PORT_BAD_HANDLE); + } + + p_port = &rfc_cb.port.port[port_handle - 1]; + + if (!p_port->in_use || (p_port->state == PORT_STATE_CLOSED)) + { + return (PORT_NOT_OPENED); + } + + p_port->p_data_co_callback = p_port_cb; + + return (PORT_SUCCESS); +} + + + +/******************************************************************************* +** +** Function PORT_SetEventMask +** +** Description This function is called to close the specified connection. +** +** Parameters: handle - Handle returned in the RFCOMM_CreateConnection +** mask - Bitmask of the events the host is interested in +** +*******************************************************************************/ +int PORT_SetEventMask (UINT16 port_handle, UINT32 mask) +{ + tPORT *p_port; + + RFCOMM_TRACE_API ("PORT_SetEventMask() handle:%d mask:0x%x", port_handle, mask); + + /* Check if handle is valid to avoid crashing */ + if ((port_handle == 0) || (port_handle > MAX_RFC_PORTS)) + { + return (PORT_BAD_HANDLE); + } + + p_port = &rfc_cb.port.port[port_handle - 1]; + + if (!p_port->in_use || (p_port->state == PORT_STATE_CLOSED)) + { + return (PORT_NOT_OPENED); + } + + p_port->ev_mask = mask; + + return (PORT_SUCCESS); +} + + +/******************************************************************************* +** +** Function PORT_CheckConnection +** +** Description This function returns PORT_SUCCESS if connection referenced +** by handle is up and running +** +** Parameters: handle - Handle returned in the RFCOMM_CreateConnection +** bd_addr - OUT bd_addr of the peer +** p_lcid - OUT L2CAP's LCID +** +*******************************************************************************/ +int PORT_CheckConnection (UINT16 handle, BD_ADDR bd_addr, UINT16 *p_lcid) +{ + tPORT *p_port; + + RFCOMM_TRACE_API ("PORT_CheckConnection() handle:%d", handle); + + /* Check if handle is valid to avoid crashing */ + if ((handle == 0) || (handle > MAX_RFC_PORTS)) + { + return (PORT_BAD_HANDLE); + } + + p_port = &rfc_cb.port.port[handle - 1]; + + if (!p_port->in_use || (p_port->state == PORT_STATE_CLOSED)) + { + return (PORT_NOT_OPENED); + } + + if (!p_port->rfc.p_mcb + || !p_port->rfc.p_mcb->peer_ready + || (p_port->rfc.state != RFC_STATE_OPENED)) + { + return (PORT_LINE_ERR); + } + + memcpy (bd_addr, p_port->rfc.p_mcb->bd_addr, BD_ADDR_LEN); + if (p_lcid) + *p_lcid = p_port->rfc.p_mcb->lcid; + + return (PORT_SUCCESS); +} + +/******************************************************************************* +** +** Function PORT_IsOpening +** +** Description This function returns TRUE if there is any RFCOMM connection +** opening in process. +** +** Parameters: TRUE if any connection opening is found +** bd_addr - bd_addr of the peer +** +*******************************************************************************/ +BOOLEAN PORT_IsOpening (BD_ADDR bd_addr) +{ + UINT8 xx, yy; + tRFC_MCB *p_mcb = NULL; + tPORT *p_port; + BOOLEAN found_port; + + /* Check for any rfc_mcb which is in the middle of opening. */ + for (xx = 0; xx < MAX_BD_CONNECTIONS; xx++) + { + if ((rfc_cb.port.rfc_mcb[xx].state > RFC_MX_STATE_IDLE) && + (rfc_cb.port.rfc_mcb[xx].state < RFC_MX_STATE_CONNECTED)) + { + memcpy (bd_addr, rfc_cb.port.rfc_mcb[xx].bd_addr, BD_ADDR_LEN); + return TRUE; + } + + if (rfc_cb.port.rfc_mcb[xx].state == RFC_MX_STATE_CONNECTED) + { + found_port = FALSE; + p_mcb = &rfc_cb.port.rfc_mcb[xx]; + p_port = &rfc_cb.port.port[0]; + + for (yy = 0; yy < MAX_RFC_PORTS; yy++, p_port++) + { + if (p_port->rfc.p_mcb == p_mcb) + { + found_port = TRUE; + break; + } + } + + if ((!found_port) || + (found_port && (p_port->rfc.state < RFC_STATE_OPENED))) + { + /* Port is not established yet. */ + memcpy (bd_addr, rfc_cb.port.rfc_mcb[xx].bd_addr, BD_ADDR_LEN); + return TRUE; + } + } + } + + return FALSE; +} + +/******************************************************************************* +** +** Function PORT_SetState +** +** Description This function configures connection according to the +** specifications in the tPORT_STATE structure. +** +** Parameters: handle - Handle returned in the RFCOMM_CreateConnection +** p_settings - Pointer to a tPORT_STATE structure containing +** configuration information for the connection. +** +** +*******************************************************************************/ +int PORT_SetState (UINT16 handle, tPORT_STATE *p_settings) +{ + tPORT *p_port; + UINT8 baud_rate; + + RFCOMM_TRACE_API ("PORT_SetState() handle:%d", handle); + + /* Check if handle is valid to avoid crashing */ + if ((handle == 0) || (handle > MAX_RFC_PORTS)) + { + return (PORT_BAD_HANDLE); + } + + p_port = &rfc_cb.port.port[handle - 1]; + + if (!p_port->in_use || (p_port->state == PORT_STATE_CLOSED)) + { + return (PORT_NOT_OPENED); + } + + if (p_port->line_status) + { + return (PORT_LINE_ERR); + } + + RFCOMM_TRACE_API ("PORT_SetState() handle:%d FC_TYPE:0x%x", handle, + p_settings->fc_type); + + baud_rate = p_port->user_port_pars.baud_rate; + p_port->user_port_pars = *p_settings; + + /* for now we've been asked to pass only baud rate */ + if (baud_rate != p_settings->baud_rate) + { + port_start_par_neg (p_port); + } + return (PORT_SUCCESS); +} + +/******************************************************************************* +** +** Function PORT_GetRxQueueCnt +** +** Description This function return number of buffers on the rx queue. +** +** Parameters: handle - Handle returned in the RFCOMM_CreateConnection +** p_rx_queue_count - Pointer to return queue count in. +** +*******************************************************************************/ +int PORT_GetRxQueueCnt (UINT16 handle, UINT16 *p_rx_queue_count) +{ + tPORT *p_port; + + RFCOMM_TRACE_API ("PORT_GetRxQueueCnt() handle:%d", handle); + + /* Check if handle is valid to avoid crashing */ + if ((handle == 0) || (handle > MAX_RFC_PORTS)) + { + return (PORT_BAD_HANDLE); + } + + p_port = &rfc_cb.port.port[handle - 1]; + + if (!p_port->in_use || (p_port->state == PORT_STATE_CLOSED)) + { + return (PORT_NOT_OPENED); + } + + if (p_port->line_status) + { + return (PORT_LINE_ERR); + } + + *p_rx_queue_count = p_port->rx.queue_size; + + RFCOMM_TRACE_API ("PORT_GetRxQueueCnt() p_rx_queue_count:%d, p_port->rx.queue.count = %d", + *p_rx_queue_count, p_port->rx.queue_size); + + return (PORT_SUCCESS); +} + +/******************************************************************************* +** +** Function PORT_GetState +** +** Description This function is called to fill tPORT_STATE structure +** with the curremt control settings for the port +** +** Parameters: handle - Handle returned in the RFCOMM_CreateConnection +** p_settings - Pointer to a tPORT_STATE structure in which +** configuration information is returned. +** +*******************************************************************************/ +int PORT_GetState (UINT16 handle, tPORT_STATE *p_settings) +{ + tPORT *p_port; + + RFCOMM_TRACE_API ("PORT_GetState() handle:%d", handle); + + /* Check if handle is valid to avoid crashing */ + if ((handle == 0) || (handle > MAX_RFC_PORTS)) + { + return (PORT_BAD_HANDLE); + } + + p_port = &rfc_cb.port.port[handle - 1]; + + if (!p_port->in_use || (p_port->state == PORT_STATE_CLOSED)) + { + return (PORT_NOT_OPENED); + } + + if (p_port->line_status) + { + return (PORT_LINE_ERR); + } + + *p_settings = p_port->user_port_pars; + return (PORT_SUCCESS); +} + + +/******************************************************************************* +** +** Function PORT_Control +** +** Description This function directs a specified connection to pass control +** control information to the peer device. +** +** Parameters: handle - Handle returned in the RFCOMM_CreateConnection +** signal = specify the function to be passed +** +*******************************************************************************/ +int PORT_Control (UINT16 handle, UINT8 signal) +{ + tPORT *p_port; + UINT8 old_modem_signal; + + RFCOMM_TRACE_API ("PORT_Control() handle:%d signal:0x%x", handle, signal); + + /* Check if handle is valid to avoid crashing */ + if ((handle == 0) || (handle > MAX_RFC_PORTS)) + { + return (PORT_BAD_HANDLE); + } + + p_port = &rfc_cb.port.port[handle - 1]; + + if (!p_port->in_use || (p_port->state == PORT_STATE_CLOSED)) + { + return (PORT_NOT_OPENED); + } + + old_modem_signal = p_port->local_ctrl.modem_signal; + p_port->local_ctrl.break_signal = 0; + + switch (signal) + { + case PORT_SET_CTSRTS: + p_port->local_ctrl.modem_signal |= PORT_CTSRTS_ON; + break; + + case PORT_CLR_CTSRTS: + p_port->local_ctrl.modem_signal &= ~PORT_CTSRTS_ON; + break; + + case PORT_SET_DTRDSR: + p_port->local_ctrl.modem_signal |= PORT_DTRDSR_ON; + break; + + case PORT_CLR_DTRDSR: + p_port->local_ctrl.modem_signal &= ~PORT_DTRDSR_ON; + break; + + case PORT_SET_RI: + p_port->local_ctrl.modem_signal |= PORT_RING_ON; + break; + + case PORT_CLR_RI: + p_port->local_ctrl.modem_signal &= ~PORT_RING_ON; + break; + + case PORT_SET_DCD: + p_port->local_ctrl.modem_signal |= PORT_DCD_ON; + break; + + case PORT_CLR_DCD: + p_port->local_ctrl.modem_signal &= ~PORT_DCD_ON; + break; + } + + if (signal == PORT_BREAK) + p_port->local_ctrl.break_signal = PORT_BREAK_DURATION; + else if (p_port->local_ctrl.modem_signal == old_modem_signal) + return (PORT_SUCCESS); + + port_start_control (p_port); + + RFCOMM_TRACE_EVENT ("PORT_Control DTR_DSR : %d, RTS_CTS : %d, RI : %d, DCD : %d", + ((p_port->local_ctrl.modem_signal & MODEM_SIGNAL_DTRDSR) ? 1 : 0), + ((p_port->local_ctrl.modem_signal & MODEM_SIGNAL_RTSCTS) ? 1 : 0), + ((p_port->local_ctrl.modem_signal & MODEM_SIGNAL_RI) ? 1 : 0), + ((p_port->local_ctrl.modem_signal & MODEM_SIGNAL_DCD) ? 1 : 0)); + + return (PORT_SUCCESS); +} + + +/******************************************************************************* +** +** Function PORT_FlowControl +** +** Description This function directs a specified connection to pass +** flow control message to the peer device. Enable flag passed +** shows if port can accept more data. +** +** Parameters: handle - Handle returned in the RFCOMM_CreateConnection +** enable - enables data flow +** +*******************************************************************************/ +int PORT_FlowControl (UINT16 handle, BOOLEAN enable) +{ + tPORT *p_port; + BOOLEAN old_fc; + UINT32 events; + + RFCOMM_TRACE_API ("PORT_FlowControl() handle:%d enable: %d", handle, enable); + + /* Check if handle is valid to avoid crashing */ + if ((handle == 0) || (handle > MAX_RFC_PORTS)) + { + return (PORT_BAD_HANDLE); + } + + p_port = &rfc_cb.port.port[handle - 1]; + + if (!p_port->in_use || (p_port->state == PORT_STATE_CLOSED)) + { + return (PORT_NOT_OPENED); + } + + if (!p_port->rfc.p_mcb) + { + return (PORT_NOT_OPENED); + } + + p_port->rx.user_fc = !enable; + + if (p_port->rfc.p_mcb->flow == PORT_FC_CREDIT) + { + if (!p_port->rx.user_fc) + { + port_flow_control_peer(p_port, TRUE, 0); + } + } + else + { + old_fc = p_port->local_ctrl.fc; + + /* FC is set if user is set or peer is set */ + p_port->local_ctrl.fc = (p_port->rx.user_fc | p_port->rx.peer_fc); + + if (p_port->local_ctrl.fc != old_fc) + port_start_control (p_port); + } + + /* Need to take care of the case when we could not deliver events */ + /* to the application because we were flow controlled */ + if (enable && (p_port->rx.queue_size != 0)) + { + events = PORT_EV_RXCHAR; + if (p_port->rx_flag_ev_pending) + { + p_port->rx_flag_ev_pending = FALSE; + events |= PORT_EV_RXFLAG; + } + + events &= p_port->ev_mask; + if (p_port->p_callback && events) + { + p_port->p_callback (events, p_port->inx); + } + } + return (PORT_SUCCESS); +} +/******************************************************************************* +** +** Function PORT_FlowControl_MaxCredit +** +** Description This function directs a specified connection to pass +** flow control message to the peer device. Enable flag passed +** shows if port can accept more data. It also sends max credit +** when data flow enabled +** +** Parameters: handle - Handle returned in the RFCOMM_CreateConnection +** enable - enables data flow +** +*******************************************************************************/ + +int PORT_FlowControl_MaxCredit (UINT16 handle, BOOLEAN enable) +{ + tPORT *p_port; + BOOLEAN old_fc; + UINT32 events; + + RFCOMM_TRACE_API ("PORT_FlowControl() handle:%d enable: %d", handle, enable); + + /* Check if handle is valid to avoid crashing */ + if ((handle == 0) || (handle > MAX_RFC_PORTS)) + { + return (PORT_BAD_HANDLE); + } + + p_port = &rfc_cb.port.port[handle - 1]; + + if (!p_port->in_use || (p_port->state == PORT_STATE_CLOSED)) + { + return (PORT_NOT_OPENED); + } + + if (!p_port->rfc.p_mcb) + { + return (PORT_NOT_OPENED); + } + + p_port->rx.user_fc = !enable; + + if (p_port->rfc.p_mcb->flow == PORT_FC_CREDIT) + { + if (!p_port->rx.user_fc) + { + port_flow_control_peer(p_port, TRUE, p_port->credit_rx); + } + } + else + { + old_fc = p_port->local_ctrl.fc; + + /* FC is set if user is set or peer is set */ + p_port->local_ctrl.fc = (p_port->rx.user_fc | p_port->rx.peer_fc); + + if (p_port->local_ctrl.fc != old_fc) + port_start_control (p_port); + } + + /* Need to take care of the case when we could not deliver events */ + /* to the application because we were flow controlled */ + if (enable && (p_port->rx.queue_size != 0)) + { + events = PORT_EV_RXCHAR; + if (p_port->rx_flag_ev_pending) + { + p_port->rx_flag_ev_pending = FALSE; + events |= PORT_EV_RXFLAG; + } + + events &= p_port->ev_mask; + if (p_port->p_callback && events) + { + p_port->p_callback (events, p_port->inx); + } + } + return (PORT_SUCCESS); +} + + +/******************************************************************************* +** +** Function PORT_GetModemStatus +** +** Description This function retrieves modem control signals. Normally +** application will call this function after a callback +** function is called with notification that one of signals +** has been changed. +** +** Parameters: handle - Handle returned in the RFCOMM_CreateConnection +** p_signal - specify the pointer to control signals info +** +*******************************************************************************/ +int PORT_GetModemStatus (UINT16 handle, UINT8 *p_signal) +{ + tPORT *p_port; + + if ((handle == 0) || (handle > MAX_RFC_PORTS)) + { + return (PORT_BAD_HANDLE); + } + + p_port = &rfc_cb.port.port[handle - 1]; + + if (!p_port->in_use || (p_port->state == PORT_STATE_CLOSED)) + { + return (PORT_NOT_OPENED); + } + + *p_signal = p_port->peer_ctrl.modem_signal; + + RFCOMM_TRACE_API ("PORT_GetModemStatus() handle:%d signal:%x", handle, *p_signal); + + return (PORT_SUCCESS); +} + + +/******************************************************************************* +** +** Function PORT_ClearError +** +** Description This function retreives information about a communications +** error and reports current status of a connection. The +** function should be called when an error occures to clear +** the connection error flag and to enable additional read +** and write operations. +** +** Parameters: handle - Handle returned in the RFCOMM_CreateConnection +** p_errors - pointer of the variable to receive error codes +** p_status - pointer to the tPORT_STATUS structur to receive +** connection status +** +*******************************************************************************/ +int PORT_ClearError (UINT16 handle, UINT16 *p_errors, tPORT_STATUS *p_status) +{ + tPORT *p_port; + + RFCOMM_TRACE_API ("PORT_ClearError() handle:%d", handle); + + if ((handle == 0) || (handle > MAX_RFC_PORTS)) + { + return (PORT_BAD_HANDLE); + } + + p_port = &rfc_cb.port.port[handle - 1]; + + if (!p_port->in_use || (p_port->state == PORT_STATE_CLOSED)) + { + return (PORT_NOT_OPENED); + } + + *p_errors = p_port->line_status; + + /* This is the only call to clear error status. We can not clear */ + /* connection failed status. To clean it port should be closed and reopened */ + p_port->line_status = (p_port->line_status & LINE_STATUS_FAILED); + + PORT_GetQueueStatus (handle, p_status); + return (PORT_SUCCESS); +} + + +/******************************************************************************* +** +** Function PORT_SendError +** +** Description This function send a communications error to the peer device +** +** Parameters: handle - Handle returned in the RFCOMM_CreateConnection +** errors - receive error codes +** +*******************************************************************************/ +int PORT_SendError (UINT16 handle, UINT8 errors) +{ + tPORT *p_port; + + RFCOMM_TRACE_API ("PORT_SendError() handle:%d errors:0x%x", handle, errors); + + if ((handle == 0) || (handle > MAX_RFC_PORTS)) + { + return (PORT_BAD_HANDLE); + } + + p_port = &rfc_cb.port.port[handle - 1]; + + if (!p_port->in_use || (p_port->state == PORT_STATE_CLOSED)) + { + return (PORT_NOT_OPENED); + } + + if (!p_port->rfc.p_mcb) + { + return (PORT_NOT_OPENED); + } + + RFCOMM_LineStatusReq (p_port->rfc.p_mcb, p_port->dlci, errors); + return (PORT_SUCCESS); +} + + +/******************************************************************************* +** +** Function PORT_GetQueueStatus +** +** Description This function reports current status of a connection. +** +** Parameters: handle - Handle returned in the RFCOMM_CreateConnection +** p_status - pointer to the tPORT_STATUS structur to receive +** connection status +** +*******************************************************************************/ +int PORT_GetQueueStatus (UINT16 handle, tPORT_STATUS *p_status) +{ + tPORT *p_port; + + /* RFCOMM_TRACE_API ("PORT_GetQueueStatus() handle:%d", handle); */ + + if ((handle == 0) || (handle > MAX_RFC_PORTS)) + { + return (PORT_BAD_HANDLE); + } + + p_port = &rfc_cb.port.port[handle - 1]; + + if (!p_port->in_use || (p_port->state == PORT_STATE_CLOSED)) + { + return (PORT_NOT_OPENED); + } + + p_status->in_queue_size = (UINT16) p_port->rx.queue_size; + p_status->out_queue_size = (UINT16) p_port->tx.queue_size; + + p_status->mtu_size = (UINT16) p_port->peer_mtu; + + p_status->flags = 0; + + if (!(p_port->peer_ctrl.modem_signal & PORT_CTSRTS_ON)) + p_status->flags |= PORT_FLAG_CTS_HOLD; + + if (!(p_port->peer_ctrl.modem_signal & PORT_DTRDSR_ON)) + p_status->flags |= PORT_FLAG_DSR_HOLD; + + if (!(p_port->peer_ctrl.modem_signal & PORT_DCD_ON)) + p_status->flags |= PORT_FLAG_RLSD_HOLD; + + return (PORT_SUCCESS); +} + + +/******************************************************************************* +** +** Function PORT_Purge +** +** Description This function discards all the data from the output or +** input queues of the specified connection. +** +** Parameters: handle - Handle returned in the RFCOMM_CreateConnection +** purge_flags - specify the action to take. +** +*******************************************************************************/ +int PORT_Purge (UINT16 handle, UINT8 purge_flags) +{ + tPORT *p_port; + BT_HDR *p_buf; + UINT16 count; + UINT32 events; + + RFCOMM_TRACE_API ("PORT_Purge() handle:%d flags:0x%x", handle, purge_flags); + + /* Check if handle is valid to avoid crashing */ + if ((handle == 0) || (handle > MAX_RFC_PORTS)) + { + return (PORT_BAD_HANDLE); + } + + p_port = &rfc_cb.port.port[handle - 1]; + + if (!p_port->in_use || (p_port->state == PORT_STATE_CLOSED)) + { + return (PORT_NOT_OPENED); + } + + if (purge_flags & PORT_PURGE_RXCLEAR) + { + PORT_SCHEDULE_LOCK; /* to prevent missing credit */ + + count = GKI_queue_length(&p_port->rx.queue); + + while ((p_buf = (BT_HDR *)GKI_dequeue (&p_port->rx.queue)) != NULL) + GKI_freebuf (p_buf); + + p_port->rx.queue_size = 0; + + PORT_SCHEDULE_UNLOCK; + + /* If we flowed controlled peer based on rx_queue size enable data again */ + if (count) + port_flow_control_peer (p_port, TRUE, count); + } + + if (purge_flags & PORT_PURGE_TXCLEAR) + { + PORT_SCHEDULE_LOCK; /* to prevent tx.queue_size from being negative */ + + while ((p_buf = (BT_HDR *)GKI_dequeue (&p_port->tx.queue)) != NULL) + GKI_freebuf (p_buf); + + p_port->tx.queue_size = 0; + + PORT_SCHEDULE_UNLOCK; + + events = PORT_EV_TXEMPTY; + + events |= port_flow_control_user (p_port); + + events &= p_port->ev_mask; + + if ((p_port->p_callback != NULL) && events) + (p_port->p_callback)(events, p_port->inx); + } + + return (PORT_SUCCESS); +} + + +/******************************************************************************* +** +** Function PORT_ReadData +** +** Description Normally not GKI aware application will call this function +** after receiving PORT_EV_RXCHAR event. +** +** Parameters: handle - Handle returned in the RFCOMM_CreateConnection +** p_data - Data area +** max_len - Byte count requested +** p_len - Byte count received +** +*******************************************************************************/ +int PORT_ReadData (UINT16 handle, char *p_data, UINT16 max_len, UINT16 *p_len) +{ + tPORT *p_port; + BT_HDR *p_buf; + UINT16 count; + + RFCOMM_TRACE_API ("PORT_ReadData() handle:%d max_len:%d", handle, max_len); + + /* Initialize this in case of an error */ + *p_len = 0; + + /* Check if handle is valid to avoid crashing */ + if ((handle == 0) || (handle > MAX_RFC_PORTS)) + { + return (PORT_BAD_HANDLE); + } + + p_port = &rfc_cb.port.port[handle - 1]; + + if (!p_port->in_use || (p_port->state == PORT_STATE_CLOSED)) + { + return (PORT_NOT_OPENED); + } + + if (p_port->line_status) + { + return (PORT_LINE_ERR); + } + + p_buf = (BT_HDR *)GKI_getfirst (&p_port->rx.queue); + if (!p_buf) + return (PORT_SUCCESS); + + count = 0; + + while (max_len && p_buf) + { + if (p_buf->len > max_len) + { + memcpy (p_data, (UINT8 *)(p_buf + 1) + p_buf->offset, max_len); + p_buf->offset += max_len; + p_buf->len -= max_len; + + *p_len += max_len; + + PORT_SCHEDULE_LOCK; + + p_port->rx.queue_size -= max_len; + + PORT_SCHEDULE_UNLOCK; + + break; + } + else + { + memcpy (p_data, (UINT8 *)(p_buf + 1) + p_buf->offset, p_buf->len); + + *p_len += p_buf->len; + max_len -= p_buf->len; + + PORT_SCHEDULE_LOCK; + + p_port->rx.queue_size -= p_buf->len; + + if (max_len) + { + p_data += p_buf->len; + p_buf = (BT_HDR *)GKI_getnext (p_buf); + } + + GKI_freebuf (GKI_dequeue (&p_port->rx.queue)); + + PORT_SCHEDULE_UNLOCK; + + count++; + } + } + + if (*p_len == 1) + { + RFCOMM_TRACE_EVENT ("PORT_ReadData queue:%d returned:%d %x", p_port->rx.queue_size, *p_len, (p_data[0])); + } + else + { + RFCOMM_TRACE_EVENT ("PORT_ReadData queue:%d returned:%d", p_port->rx.queue_size, *p_len); + } + + /* If rfcomm suspended traffic from the peer based on the rx_queue_size */ + /* check if it can be resumed now */ + port_flow_control_peer (p_port, TRUE, count); + + return (PORT_SUCCESS); +} + + +/******************************************************************************* +** +** Function PORT_Read +** +** Description Normally application will call this function after receiving +** PORT_EV_RXCHAR event. +** +** Parameters: handle - Handle returned in the RFCOMM_CreateConnection +** pp_buf - pointer to address of buffer with data, +** +*******************************************************************************/ +int PORT_Read (UINT16 handle, BT_HDR **pp_buf) +{ + tPORT *p_port; + BT_HDR *p_buf; + + RFCOMM_TRACE_API ("PORT_Read() handle:%d", handle); + + /* Check if handle is valid to avoid crashing */ + if ((handle == 0) || (handle > MAX_RFC_PORTS)) + { + return (PORT_BAD_HANDLE); + } + p_port = &rfc_cb.port.port[handle - 1]; + + if (!p_port->in_use || (p_port->state == PORT_STATE_CLOSED)) + { + return (PORT_NOT_OPENED); + } + + if (p_port->line_status) + { + return (PORT_LINE_ERR); + } + + PORT_SCHEDULE_LOCK; + + p_buf = (BT_HDR *)GKI_dequeue (&p_port->rx.queue); + if (p_buf) + { + p_port->rx.queue_size -= p_buf->len; + + PORT_SCHEDULE_UNLOCK; + + /* If rfcomm suspended traffic from the peer based on the rx_queue_size */ + /* check if it can be resumed now */ + port_flow_control_peer (p_port, TRUE, 1); + } + else + { + PORT_SCHEDULE_UNLOCK; + } + + *pp_buf = p_buf; + return (PORT_SUCCESS); +} + + +/******************************************************************************* +** +** Function port_write +** +** Description This function when a data packet is received from the apper +** layer task. +** +** Parameters: p_port - pointer to address of port control block +** p_buf - pointer to address of buffer with data, +** +*******************************************************************************/ +static int port_write (tPORT *p_port, BT_HDR *p_buf) +{ + /* We should not allow to write data in to server port when connection is not opened */ + if (p_port->is_server && (p_port->rfc.state != RFC_STATE_OPENED)) + { + GKI_freebuf (p_buf); + return (PORT_CLOSED); + } + + /* Keep the data in pending queue if peer does not allow data, or */ + /* Peer is not ready or Port is not yet opened or initial port control */ + /* command has not been sent */ + if (p_port->tx.peer_fc + || !p_port->rfc.p_mcb + || !p_port->rfc.p_mcb->peer_ready + || (p_port->rfc.state != RFC_STATE_OPENED) + || ((p_port->port_ctrl & (PORT_CTRL_REQ_SENT | PORT_CTRL_IND_RECEIVED)) != + (PORT_CTRL_REQ_SENT | PORT_CTRL_IND_RECEIVED))) + { + if ((p_port->tx.queue_size > PORT_TX_CRITICAL_WM) + || (GKI_queue_length(&p_port->tx.queue) > PORT_TX_BUF_CRITICAL_WM)) + { + RFCOMM_TRACE_WARNING ("PORT_Write: Queue size: %d", + p_port->tx.queue_size); + + GKI_freebuf (p_buf); + + if ((p_port->p_callback != NULL) && (p_port->ev_mask & PORT_EV_ERR)) + p_port->p_callback (PORT_EV_ERR, p_port->inx); + + return (PORT_TX_FULL); + } + + RFCOMM_TRACE_EVENT ("PORT_Write : Data is enqued. flow disabled %d peer_ready %d state %d ctrl_state %x", + p_port->tx.peer_fc, + (p_port->rfc.p_mcb && p_port->rfc.p_mcb->peer_ready), + p_port->rfc.state, + p_port->port_ctrl); + + GKI_enqueue (&p_port->tx.queue, p_buf); + p_port->tx.queue_size += p_buf->len; + + return (PORT_CMD_PENDING); + } + else + { + RFCOMM_TRACE_EVENT ("PORT_Write : Data is being sent"); + + RFCOMM_DataReq (p_port->rfc.p_mcb, p_port->dlci, p_buf); + return (PORT_SUCCESS); + } +} + +/******************************************************************************* +** +** Function PORT_Write +** +** Description This function when a data packet is received from the apper +** layer task. +** +** Parameters: handle - Handle returned in the RFCOMM_CreateConnection +** pp_buf - pointer to address of buffer with data, +** +*******************************************************************************/ +int PORT_Write (UINT16 handle, BT_HDR *p_buf) +{ + tPORT *p_port; + UINT32 event = 0; + int rc; + + RFCOMM_TRACE_API ("PORT_Write() handle:%d", handle); + + /* Check if handle is valid to avoid crashing */ + if ((handle == 0) || (handle > MAX_RFC_PORTS)) + { + GKI_freebuf (p_buf); + return (PORT_BAD_HANDLE); + } + + p_port = &rfc_cb.port.port[handle - 1]; + + if (!p_port->in_use || (p_port->state == PORT_STATE_CLOSED)) + { + GKI_freebuf (p_buf); + return (PORT_NOT_OPENED); + } + + if (p_port->line_status) + { + RFCOMM_TRACE_WARNING ("PORT_Write: Data dropped line_status:0x%x", + p_port->line_status); + GKI_freebuf (p_buf); + return (PORT_LINE_ERR); + } + + rc = port_write (p_port, p_buf); + event |= port_flow_control_user (p_port); + + switch (rc) + { + case PORT_TX_FULL: + event |= PORT_EV_ERR; + break; + + case PORT_SUCCESS: + event |= (PORT_EV_TXCHAR | PORT_EV_TXEMPTY); + break; + } + /* Mask out all events that are not of interest to user */ + event &= p_port->ev_mask; + + /* Send event to the application */ + if (p_port->p_callback && event) + (p_port->p_callback)(event, p_port->inx); + + return (PORT_SUCCESS); +} +/******************************************************************************* +** +** Function PORT_WriteDataCO +** +** Description Normally not GKI aware application will call this function +** to send data to the port by callout functions +** +** Parameters: handle - Handle returned in the RFCOMM_CreateConnection +** fd - socket fd +** p_len - Byte count returned +** +*******************************************************************************/ +int PORT_WriteDataCO (UINT16 handle, int* p_len) +{ + + tPORT *p_port; + BT_HDR *p_buf; + UINT32 event = 0; + int rc = 0; + UINT16 length; + + RFCOMM_TRACE_API ("PORT_WriteDataCO() handle:%d", handle); + *p_len = 0; + + /* Check if handle is valid to avoid crashing */ + if ((handle == 0) || (handle > MAX_RFC_PORTS)) + { + return (PORT_BAD_HANDLE); + } + p_port = &rfc_cb.port.port[handle - 1]; + + if (!p_port->in_use || (p_port->state == PORT_STATE_CLOSED)) + { + RFCOMM_TRACE_WARNING ("PORT_WriteDataByFd() no port state:%d", p_port->state); + return (PORT_NOT_OPENED); + } + + if (!p_port->peer_mtu) + { + RFCOMM_TRACE_ERROR ("PORT_WriteDataByFd() peer_mtu:%d", p_port->peer_mtu); + return (PORT_UNKNOWN_ERROR); + } + int available = 0; + //if(ioctl(fd, FIONREAD, &available) < 0) + if(p_port->p_data_co_callback(handle, (UINT8*)&available, sizeof(available), + DATA_CO_CALLBACK_TYPE_OUTGOING_SIZE) == FALSE) + { + RFCOMM_TRACE_ERROR("p_data_co_callback DATA_CO_CALLBACK_TYPE_INCOMING_SIZE failed, available:%d", available); + return (PORT_UNKNOWN_ERROR); + } + if(available == 0) + return PORT_SUCCESS; + /* Length for each buffer is the smaller of GKI buffer, peer MTU, or max_len */ + length = RFCOMM_DATA_POOL_BUF_SIZE - + (UINT16)(sizeof(BT_HDR) + L2CAP_MIN_OFFSET + RFCOMM_DATA_OVERHEAD); + + /* If there are buffers scheduled for transmission check if requested */ + /* data fits into the end of the queue */ + PORT_SCHEDULE_LOCK; + + if (((p_buf = (BT_HDR *)GKI_getlast(&p_port->tx.queue)) != NULL) + && (((int)p_buf->len + available) <= (int)p_port->peer_mtu) + && (((int)p_buf->len + available) <= (int)length)) + { + //if(recv(fd, (UINT8 *)(p_buf + 1) + p_buf->offset + p_buf->len, available, 0) != available) + if(p_port->p_data_co_callback(handle, (UINT8 *)(p_buf + 1) + p_buf->offset + p_buf->len, + available, DATA_CO_CALLBACK_TYPE_OUTGOING) == FALSE) + + { + RFCOMM_TRACE_ERROR("p_data_co_callback DATA_CO_CALLBACK_TYPE_OUTGOING failed, available:%d", available); + PORT_SCHEDULE_UNLOCK; + return (PORT_UNKNOWN_ERROR); + } + //memcpy ((UINT8 *)(p_buf + 1) + p_buf->offset + p_buf->len, p_data, max_len); + p_port->tx.queue_size += (UINT16)available; + + *p_len = available; + p_buf->len += (UINT16)available; + + PORT_SCHEDULE_UNLOCK; + + return (PORT_SUCCESS); + } + + PORT_SCHEDULE_UNLOCK; + + //int max_read = length < p_port->peer_mtu ? length : p_port->peer_mtu; + + //max_read = available < max_read ? available : max_read; + + while (available) + { + /* if we're over buffer high water mark, we're done */ + if ((p_port->tx.queue_size > PORT_TX_HIGH_WM) + || (GKI_queue_length(&p_port->tx.queue) > PORT_TX_BUF_HIGH_WM)) + { + port_flow_control_user(p_port); + event |= PORT_EV_FC; + RFCOMM_TRACE_EVENT ("tx queue is full,tx.queue_size:%d,tx.queue.count:%d,available:%d", + p_port->tx.queue_size, GKI_queue_length(&p_port->tx.queue), available); + break; + } + + /* continue with rfcomm data write */ + p_buf = (BT_HDR *)GKI_getpoolbuf (RFCOMM_DATA_POOL_ID); + if (!p_buf) + break; + + p_buf->offset = L2CAP_MIN_OFFSET + RFCOMM_MIN_OFFSET; + p_buf->layer_specific = handle; + + if (p_port->peer_mtu < length) + length = p_port->peer_mtu; + if (available < (int)length) + length = (UINT16)available; + p_buf->len = length; + p_buf->event = BT_EVT_TO_BTU_SP_DATA; + + //memcpy ((UINT8 *)(p_buf + 1) + p_buf->offset, p_data, length); + //if(recv(fd, (UINT8 *)(p_buf + 1) + p_buf->offset, (int)length, 0) != (int)length) + if(p_port->p_data_co_callback(handle, (UINT8 *)(p_buf + 1) + p_buf->offset, length, + DATA_CO_CALLBACK_TYPE_OUTGOING) == FALSE) + { + RFCOMM_TRACE_ERROR("p_data_co_callback DATA_CO_CALLBACK_TYPE_OUTGOING failed, length:%d", length); + return (PORT_UNKNOWN_ERROR); + } + + + RFCOMM_TRACE_EVENT ("PORT_WriteData %d bytes", length); + + rc = port_write (p_port, p_buf); + + /* If queue went below the threashold need to send flow control */ + event |= port_flow_control_user (p_port); + + if (rc == PORT_SUCCESS) + event |= PORT_EV_TXCHAR; + + if ((rc != PORT_SUCCESS) && (rc != PORT_CMD_PENDING)) + break; + + *p_len += length; + available -= (int)length; + } + if (!available && (rc != PORT_CMD_PENDING) && (rc != PORT_TX_QUEUE_DISABLED)) + event |= PORT_EV_TXEMPTY; + + /* Mask out all events that are not of interest to user */ + event &= p_port->ev_mask; + + /* Send event to the application */ + if (p_port->p_callback && event) + (p_port->p_callback)(event, p_port->inx); + + return (PORT_SUCCESS); +} + + + +/******************************************************************************* +** +** Function PORT_WriteData +** +** Description Normally not GKI aware application will call this function +** to send data to the port. +** +** Parameters: handle - Handle returned in the RFCOMM_CreateConnection +** p_data - Data area +** max_len - Byte count requested +** p_len - Byte count received +** +*******************************************************************************/ +int PORT_WriteData (UINT16 handle, char *p_data, UINT16 max_len, UINT16 *p_len) +{ + tPORT *p_port; + BT_HDR *p_buf; + UINT32 event = 0; + int rc = 0; + UINT16 length; + + RFCOMM_TRACE_API ("PORT_WriteData() max_len:%d", max_len); + + *p_len = 0; + + /* Check if handle is valid to avoid crashing */ + if ((handle == 0) || (handle > MAX_RFC_PORTS)) + { + return (PORT_BAD_HANDLE); + } + p_port = &rfc_cb.port.port[handle - 1]; + + if (!p_port->in_use || (p_port->state == PORT_STATE_CLOSED)) + { + RFCOMM_TRACE_WARNING ("PORT_WriteData() no port state:%d", p_port->state); + return (PORT_NOT_OPENED); + } + + if (!max_len || !p_port->peer_mtu) + { + RFCOMM_TRACE_ERROR ("PORT_WriteData() peer_mtu:%d", p_port->peer_mtu); + return (PORT_UNKNOWN_ERROR); + } + + /* Length for each buffer is the smaller of GKI buffer, peer MTU, or max_len */ + length = RFCOMM_DATA_POOL_BUF_SIZE - + (UINT16)(sizeof(BT_HDR) + L2CAP_MIN_OFFSET + RFCOMM_DATA_OVERHEAD); + + /* If there are buffers scheduled for transmission check if requested */ + /* data fits into the end of the queue */ + PORT_SCHEDULE_LOCK; + + if (((p_buf = (BT_HDR *)GKI_getlast(&p_port->tx.queue)) != NULL) + && ((p_buf->len + max_len) <= p_port->peer_mtu) + && ((p_buf->len + max_len) <= length)) + { + memcpy ((UINT8 *)(p_buf + 1) + p_buf->offset + p_buf->len, p_data, max_len); + p_port->tx.queue_size += max_len; + + *p_len = max_len; + p_buf->len += max_len; + + PORT_SCHEDULE_UNLOCK; + + return (PORT_SUCCESS); + } + + PORT_SCHEDULE_UNLOCK; + + while (max_len) + { + /* if we're over buffer high water mark, we're done */ + if ((p_port->tx.queue_size > PORT_TX_HIGH_WM) + || (GKI_queue_length(&p_port->tx.queue) > PORT_TX_BUF_HIGH_WM)) + break; + + /* continue with rfcomm data write */ + p_buf = (BT_HDR *)GKI_getpoolbuf (RFCOMM_DATA_POOL_ID); + if (!p_buf) + break; + + p_buf->offset = L2CAP_MIN_OFFSET + RFCOMM_MIN_OFFSET; + p_buf->layer_specific = handle; + + if (p_port->peer_mtu < length) + length = p_port->peer_mtu; + if (max_len < length) + length = max_len; + p_buf->len = length; + p_buf->event = BT_EVT_TO_BTU_SP_DATA; + + memcpy ((UINT8 *)(p_buf + 1) + p_buf->offset, p_data, length); + + RFCOMM_TRACE_EVENT ("PORT_WriteData %d bytes", length); + + rc = port_write (p_port, p_buf); + + /* If queue went below the threashold need to send flow control */ + event |= port_flow_control_user (p_port); + + if (rc == PORT_SUCCESS) + event |= PORT_EV_TXCHAR; + + if ((rc != PORT_SUCCESS) && (rc != PORT_CMD_PENDING)) + break; + + *p_len += length; + max_len -= length; + p_data += length; + + } + if (!max_len && (rc != PORT_CMD_PENDING) && (rc != PORT_TX_QUEUE_DISABLED)) + event |= PORT_EV_TXEMPTY; + + /* Mask out all events that are not of interest to user */ + event &= p_port->ev_mask; + + /* Send event to the application */ + if (p_port->p_callback && event) + (p_port->p_callback)(event, p_port->inx); + + return (PORT_SUCCESS); +} + + +/******************************************************************************* +** +** Function PORT_Test +** +** Description Application can call this function to send RFCOMM Test frame +** +** Parameters: handle - Handle returned in the RFCOMM_CreateConnection +** p_data - Data area +** max_len - Byte count requested +** +*******************************************************************************/ +int PORT_Test (UINT16 handle, UINT8 *p_data, UINT16 len) +{ + BT_HDR *p_buf; + tPORT *p_port; + + RFCOMM_TRACE_API ("PORT_Test() len:%d", len); + + if ((handle == 0) || (handle > MAX_RFC_PORTS)) + { + return (PORT_BAD_HANDLE); + } + p_port = &rfc_cb.port.port[handle - 1]; + + if (!p_port->in_use || (p_port->state == PORT_STATE_CLOSED)) + { + return (PORT_NOT_OPENED); + } + + if (len > ((p_port->mtu == 0) ? RFCOMM_DEFAULT_MTU : p_port->mtu)) + { + return (PORT_UNKNOWN_ERROR); + } + + if ((p_buf = (BT_HDR *)GKI_getpoolbuf (RFCOMM_CMD_POOL_ID)) != NULL) + { + + p_buf->offset = L2CAP_MIN_OFFSET + RFCOMM_MIN_OFFSET + 2; + p_buf->len = len; + + memcpy ((UINT8 *)(p_buf + 1) + p_buf->offset, p_data, p_buf->len); + + rfc_send_test (p_port->rfc.p_mcb, TRUE, p_buf); + return (PORT_SUCCESS); + } + else + { + return (PORT_NO_MEM); + } +} + +/******************************************************************************* +** +** Function RFCOMM_Init +** +** Description This function is called to initialize RFCOMM layer +** +*******************************************************************************/ +void RFCOMM_Init (void) +{ + memset (&rfc_cb, 0, sizeof (tRFC_CB)); /* Init RFCOMM control block */ + + rfc_cb.rfc.last_mux = MAX_BD_CONNECTIONS; + +#if defined(RFCOMM_INITIAL_TRACE_LEVEL) + rfc_cb.trace_level = RFCOMM_INITIAL_TRACE_LEVEL; +#else + rfc_cb.trace_level = BT_TRACE_LEVEL_NONE; /* No traces */ +#endif + + rfcomm_l2cap_if_init (); +} + +/******************************************************************************* +** +** Function PORT_SetTraceLevel +** +** Description This function sets the trace level for RFCOMM. If called with +** a value of 0xFF, it simply reads the current trace level. +** +** Returns the new (current) trace level +** +*******************************************************************************/ +UINT8 PORT_SetTraceLevel (UINT8 new_level) +{ + if (new_level != 0xFF) + rfc_cb.trace_level = new_level; + + return (rfc_cb.trace_level); +} + +/******************************************************************************* +** +** Function PORT_GetResultString +** +** Description This function returns the human-readable string for a given +** result code. +** +** Returns a pointer to the human-readable string for the given result. +** +*******************************************************************************/ +const char *PORT_GetResultString (const uint8_t result_code) { + if (result_code > PORT_ERR_MAX) { + return result_code_strings[PORT_ERR_MAX]; + } + + return result_code_strings[result_code]; +} diff --git a/components/bt/bluedroid/stack/rfcomm/port_rfc.c b/components/bt/bluedroid/stack/rfcomm/port_rfc.c new file mode 100755 index 0000000000..7ef8b461c6 --- /dev/null +++ b/components/bt/bluedroid/stack/rfcomm/port_rfc.c @@ -0,0 +1,1120 @@ +/****************************************************************************** + * + * Copyright (C) 1999-2012 Broadcom Corporation + * + * 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 module contains functions for port emulation entity and RFCOMM + * communications + * + ******************************************************************************/ +#include + +#include "bt_target.h" +#include "gki.h" +#include "rfcdefs.h" +#include "port_api.h" +#include "btm_int.h" +#include "btm_api.h" +#include "port_int.h" +#include "rfc_int.h" +#include "bt_defs.h" + +/* +** Local function definitions +*/ +UINT32 port_rfc_send_tx_data (tPORT *p_port); +void port_rfc_closed (tPORT *p_port, UINT8 res); +void port_get_credits (tPORT *p_port, UINT8 k); + + +/******************************************************************************* +** +** Function port_open_continue +** +** Description This function is called after security manager completes +** required security checks. +** +** Returns void +** +*******************************************************************************/ +int port_open_continue (tPORT *p_port) +{ + tRFC_MCB *p_mcb; + + RFCOMM_TRACE_EVENT ("port_open_continue, p_port:%p", p_port); + + /* Check if multiplexer channel has already been established */ + if ((p_mcb = rfc_alloc_multiplexer_channel (p_port->bd_addr, TRUE)) == NULL) + { + RFCOMM_TRACE_WARNING ("port_open_continue no mx channel"); + port_release_port (p_port); + return (PORT_NO_RESOURCES); + } + + p_port->rfc.p_mcb = p_mcb; + + p_mcb->port_inx[p_port->dlci] = p_port->inx; + + /* Connection is up and we know local and remote features, select MTU */ + port_select_mtu (p_port); + + if (p_mcb->state == RFC_MX_STATE_CONNECTED) + { + RFCOMM_ParNegReq (p_mcb, p_port->dlci, p_port->mtu); + } + else if ((p_mcb->state == RFC_MX_STATE_IDLE) + ||(p_mcb->state == RFC_MX_STATE_DISC_WAIT_UA)) + { + /* In RFC_MX_STATE_IDLE state, MX state machine will create connection */ + /* In RFC_MX_STATE_DISC_WAIT_UA state, MX state machine will recreate connection */ + /* after disconnecting is completed */ + RFCOMM_StartReq (p_mcb); + } + else + { + /* MX state machine ignores RFC_MX_EVENT_START_REQ in these states */ + /* When it enters RFC_MX_STATE_CONNECTED, it will check any openning ports */ + RFCOMM_TRACE_DEBUG ("port_open_continue: mx state(%d) mx channel is openning", p_mcb->state); + } + return (PORT_SUCCESS); +} + + +/******************************************************************************* +** +** Function port_start_control +** +** Description This function is called in the BTU_TASK context to +** send control information +** +** Returns void +** +*******************************************************************************/ +void port_start_control (tPORT *p_port) +{ + tRFC_MCB *p_mcb = p_port->rfc.p_mcb; + + if (p_mcb == NULL) + return; + + RFCOMM_ControlReq (p_mcb, p_port->dlci, &p_port->local_ctrl); +} + + +/******************************************************************************* +** +** Function port_start_par_neg +** +** Description This function is called in the BTU_TASK context to +** send configuration information +** +** Returns void +** +*******************************************************************************/ +void port_start_par_neg (tPORT *p_port) +{ + tRFC_MCB *p_mcb = p_port->rfc.p_mcb; + + if (p_mcb == NULL) + return; + + RFCOMM_PortNegReq (p_mcb, p_port->dlci, &p_port->user_port_pars); +} + + +/******************************************************************************* +** +** Function port_start_close +** +** Description This function is called in the BTU_TASK context to +** release DLC +** +** Returns void +** +*******************************************************************************/ +void port_start_close (tPORT *p_port) +{ + tRFC_MCB *p_mcb = p_port->rfc.p_mcb; + UINT8 old_signals; + UINT32 events = 0; + + /* At first indicate to the user that signals on the connection were dropped */ + p_port->line_status |= LINE_STATUS_FAILED; + old_signals = p_port->peer_ctrl.modem_signal; + + p_port->peer_ctrl.modem_signal &= ~(PORT_DTRDSR_ON | PORT_CTSRTS_ON | PORT_DCD_ON); + + events |= port_get_signal_changes (p_port, old_signals, p_port->peer_ctrl.modem_signal); + + if(p_port->ev_mask & PORT_EV_CONNECT_ERR) + events |= PORT_EV_CONNECT_ERR; + + if(p_port->ev_mask & PORT_EV_ERR) + events |= PORT_EV_ERR; + + if ((p_port->p_callback != NULL) && events) + p_port->p_callback (events, p_port->inx); + + + /* Check if RFCOMM side has been closed while the message was queued */ + if ((p_mcb == NULL) || (p_port->rfc.state == RFC_STATE_CLOSED)) + { + /* Call management callback function before calling port_release_port() to clear tPort */ + if (p_port->p_mgmt_callback) + p_port->p_mgmt_callback (PORT_CLOSED, p_port->inx); + + port_release_port (p_port); + } + else + { + RFCOMM_DlcReleaseReq (p_mcb, p_port->dlci); + } +} + + +/******************************************************************************* +** +** Function PORT_StartCnf +** +** Description This function is called from the RFCOMM layer when +** establishing of the multiplexer channel is completed. +** Continue establishing of the connection for all ports that +** are in the OPENING state +** +*******************************************************************************/ +void PORT_StartCnf (tRFC_MCB *p_mcb, UINT16 result) +{ + tPORT *p_port; + int i; + BOOLEAN no_ports_up = TRUE; + + RFCOMM_TRACE_EVENT ("PORT_StartCnf result:%d", result); + + p_port = &rfc_cb.port.port[0]; + for (i = 0; i < MAX_RFC_PORTS; i++, p_port++) + { + if (p_port->rfc.p_mcb == p_mcb) + { + no_ports_up = FALSE; + + if (result == RFCOMM_SUCCESS) + RFCOMM_ParNegReq (p_mcb, p_port->dlci, p_port->mtu); + else + { + RFCOMM_TRACE_WARNING ("PORT_StartCnf failed result:%d", result); + + /* Warning: result is also set to 4 when l2cap connection + fails due to l2cap connect cnf (no_resources) */ + if( result == HCI_ERR_PAGE_TIMEOUT ) + p_port->error = PORT_PAGE_TIMEOUT; + else + p_port->error = PORT_START_FAILED; + + rfc_release_multiplexer_channel (p_mcb); + p_port->rfc.p_mcb = NULL; + + /* Send event to the application */ + if (p_port->p_callback && (p_port->ev_mask & PORT_EV_CONNECT_ERR)) + (p_port->p_callback)(PORT_EV_CONNECT_ERR, p_port->inx); + + if (p_port->p_mgmt_callback) + p_port->p_mgmt_callback (PORT_START_FAILED, p_port->inx); + + port_release_port (p_port); + } + } + } + + /* There can be a situation when after starting connection, user closes the */ + /* port, we can catch it here to close multiplexor channel */ + if (no_ports_up) + { + rfc_check_mcb_active (p_mcb); + } +} + + +/******************************************************************************* +** +** Function PORT_StartInd +** +** Description This function is called from the RFCOMM layer when +** some peer device wants to establish a multiplexer +** connection. Check if there are any ports open with this +** or not assigned multiplexer. +** +*******************************************************************************/ +void PORT_StartInd (tRFC_MCB *p_mcb) +{ + tPORT *p_port; + int i; + + RFCOMM_TRACE_EVENT ("PORT_StartInd"); + + p_port = &rfc_cb.port.port[0]; + for (i = 0; i < MAX_RFC_PORTS; i++, p_port++) + { + if ((p_port->rfc.p_mcb == NULL) + || (p_port->rfc.p_mcb == p_mcb)) + { + RFCOMM_TRACE_DEBUG("PORT_StartInd, RFCOMM_StartRsp RFCOMM_SUCCESS: p_mcb:%p", p_mcb); + RFCOMM_StartRsp (p_mcb, RFCOMM_SUCCESS); + return; + } + } + RFCOMM_StartRsp (p_mcb, RFCOMM_ERROR); +} + + +/******************************************************************************* +** +** Function PORT_ParNegInd +** +** Description This function is called from the RFCOMM layer to change +** DLCI parameters (currently only MTU is negotiated). +** If can not find the port do not accept the request. +** Otherwise save the MTU size supported by the peer. +** +*******************************************************************************/ +void PORT_ParNegInd (tRFC_MCB *p_mcb, UINT8 dlci, UINT16 mtu, UINT8 cl, UINT8 k) +{ + tPORT *p_port = port_find_mcb_dlci_port (p_mcb, dlci); + UINT8 our_cl; + UINT8 our_k; + + RFCOMM_TRACE_EVENT ("PORT_ParNegInd dlci:%d mtu:%d", dlci, mtu); + + if (!p_port) + { + /* This can be a first request for this port */ + p_port = port_find_dlci_port (dlci); + if (!p_port) + { + /* If the port cannot be opened, send a DM. Per Errata 1205 */ + rfc_send_dm(p_mcb, dlci, FALSE); + /* check if this is the last port open, some headsets have + problem, they don't disconnect if we send DM */ + rfc_check_mcb_active( p_mcb ); + RFCOMM_TRACE_EVENT( "PORT_ParNegInd: port not found" ); + return; + } + p_mcb->port_inx[dlci] = p_port->inx; + } + + memcpy (p_port->bd_addr, p_mcb->bd_addr, BD_ADDR_LEN); + + /* Connection is up and we know local and remote features, select MTU */ + port_select_mtu (p_port); + + p_port->rfc.p_mcb = p_mcb; + p_port->mtu = (p_port->mtu < mtu) ? p_port->mtu : mtu; + p_port->peer_mtu = p_port->mtu; + + /* Negotiate the flow control mechanism. If flow control mechanism for */ + /* mux has not been set yet, set it now. If either we or peer wants TS 07.10, */ + /* use that. Otherwise both must want credit based, so use that. If flow is */ + /* already defined for this mux, we respond with that value. */ + if (p_mcb->flow == PORT_FC_UNDEFINED) + { + if ((PORT_FC_DEFAULT == PORT_FC_TS710) || (cl == RFCOMM_PN_CONV_LAYER_TYPE_1)) + { + p_mcb->flow = PORT_FC_TS710; + } + else + { + p_mcb->flow = PORT_FC_CREDIT; + } + } + + /* Regardless of our flow control mechanism, if the PN cl is zero, we must */ + /* respond with zero. "A responding implementation must set this field to 14 */ + /* if (and only if) the PN request was 15." This could happen if a PN is sent */ + /* after the DLCI is already established-- the PN in that case must have cl = 0. */ + /* See RFCOMM spec 5.5.3 */ + if (cl == RFCOMM_PN_CONV_LAYER_TYPE_1) + { + our_cl = RFCOMM_PN_CONV_LAYER_TYPE_1; + our_k = 0; + } + else if (p_mcb->flow == PORT_FC_CREDIT) + { + /* get credits */ + port_get_credits (p_port, k); + + /* Set convergence layer and number of credits (k) */ + our_cl = RFCOMM_PN_CONV_LAYER_CBFC_R; + our_k = (p_port->credit_rx_max < RFCOMM_K_MAX) ? p_port->credit_rx_max : RFCOMM_K_MAX; + p_port->credit_rx = our_k; + } + else + { + /* must not be using credit based flow control; use TS 7.10 */ + our_cl = RFCOMM_PN_CONV_LAYER_TYPE_1; + our_k = 0; + } + RFCOMM_ParNegRsp (p_mcb, dlci, p_port->mtu, our_cl, our_k); +} + + +/******************************************************************************* +** +** Function PORT_ParNegCnf +** +** Description This function is called from the RFCOMM layer to change +** DLCI parameters (currently only MTU is negotiated). +** Save the MTU size supported by the peer. +** If the confirmation is received during the port opening +** procedure send EstablishRequest to continue. +** +*******************************************************************************/ +void PORT_ParNegCnf (tRFC_MCB *p_mcb, UINT8 dlci, UINT16 mtu, UINT8 cl, UINT8 k) +{ + tPORT *p_port = port_find_mcb_dlci_port (p_mcb, dlci); + + RFCOMM_TRACE_EVENT ("PORT_ParNegCnf dlci:%d mtu:%d cl: %d k: %d", dlci, mtu, cl, k); + + if (!p_port) + return; + + /* Flow control mechanism not set yet. Negotiate flow control mechanism. */ + if (p_mcb->flow == PORT_FC_UNDEFINED) + { + /* Our stack is configured for TS07.10 and they responded with credit-based. */ + /* This is illegal-- negotiation fails. */ + if ((PORT_FC_DEFAULT == PORT_FC_TS710) && (cl == RFCOMM_PN_CONV_LAYER_CBFC_R)) + { + rfc_send_disc (p_mcb, p_port->dlci); + rfc_port_closed (p_port); + return; + } + /* Our stack is configured for credit-based and they responded with credit-based. */ + else if (cl == RFCOMM_PN_CONV_LAYER_CBFC_R) + { + p_mcb->flow = PORT_FC_CREDIT; + } + /* They responded with any other value. Treat this as negotiation to TS07.10. */ + else + { + p_mcb->flow = PORT_FC_TS710; + } + } + /* If mux flow control mechanism set, we honor that setting regardless of */ + /* the CL value in their response. This allows us to gracefully accept any */ + /* illegal PN negotiation scenarios. */ + + p_port->mtu = (p_port->mtu < mtu) ? p_port->mtu : mtu; + p_port->peer_mtu = p_port->mtu; + + if (p_mcb->flow == PORT_FC_CREDIT) + { + port_get_credits (p_port, k); + } + + if (p_port->state == PORT_STATE_OPENING) + RFCOMM_DlcEstablishReq (p_mcb, p_port->dlci, p_port->mtu); +} + + +/******************************************************************************* +** +** Function PORT_DlcEstablishInd +** +** Description This function is called from the RFCOMM layer when peer +** device wants to establish a new DLC. If this is not the +** first message in the establishment procedure port_handle +** has a handle to the port control block otherwise the control +** block should be found based on the muliplexer channel and +** dlci. The block should be allocated allocated before +** meaning that application already made open. +** +*******************************************************************************/ +void PORT_DlcEstablishInd (tRFC_MCB *p_mcb, UINT8 dlci, UINT16 mtu) +{ + tPORT *p_port = port_find_mcb_dlci_port (p_mcb, dlci); + + RFCOMM_TRACE_DEBUG ("PORT_DlcEstablishInd p_mcb:%p, dlci:%d mtu:%di, p_port:%p", p_mcb, dlci, mtu, p_port); + RFCOMM_TRACE_DEBUG ("PORT_DlcEstablishInd p_mcb addr:%02x:%02x:%02x:%02x:%02x:%02x", + p_mcb->bd_addr[0], p_mcb->bd_addr[1], p_mcb->bd_addr[2], + p_mcb->bd_addr[3], p_mcb->bd_addr[4], p_mcb->bd_addr[5]); + + if (!p_port) + { + /* This can be a first request for this port */ + p_port = port_find_dlci_port (dlci); + if (!p_port) + { + RFCOMM_DlcEstablishRsp (p_mcb, dlci, 0, RFCOMM_ERROR); + return; + } + p_mcb->port_inx[dlci] = p_port->inx; + } + + /* If L2CAP's mtu less then RFCOMM's take it */ + if (mtu && (mtu < p_port->peer_mtu)) + p_port->peer_mtu = mtu; + + /* If there was an inactivity timer running for MCB stop it */ + rfc_timer_stop (p_mcb); + + RFCOMM_DlcEstablishRsp (p_mcb, dlci, p_port->mtu, RFCOMM_SUCCESS); + + /* This is the server side. If application wants to know when connection */ + /* is established, thats the place */ + if (p_port->p_callback && (p_port->ev_mask & PORT_EV_CONNECTED)) + (p_port->p_callback)(PORT_EV_CONNECTED, p_port->inx); + + if (p_port->p_mgmt_callback) + p_port->p_mgmt_callback (PORT_SUCCESS, p_port->inx); + + p_port->state = PORT_STATE_OPENED; +} + + +/******************************************************************************* +** +** Function PORT_DlcEstablishCnf +** +** Description This function is called from the RFCOMM layer when peer +** acknowledges establish procedure (SABME/UA). Send reply +** to the user and set state to OPENED if result was +** successfull. +** +*******************************************************************************/ +void PORT_DlcEstablishCnf (tRFC_MCB *p_mcb, UINT8 dlci, UINT16 mtu, UINT16 result) +{ + tPORT *p_port = port_find_mcb_dlci_port (p_mcb, dlci); + + RFCOMM_TRACE_EVENT ("PORT_DlcEstablishCnf dlci:%d mtu:%d result:%d", dlci, mtu, result); + + if (!p_port) + return; + + if (result != RFCOMM_SUCCESS) + { + p_port->error = PORT_START_FAILED; + port_rfc_closed (p_port, PORT_START_FAILED); + return; + } + + /* If L2CAP's mtu less then RFCOMM's take it */ + if (mtu && (mtu < p_port->peer_mtu)) + p_port->peer_mtu = mtu; + + /* If there was an inactivity timer running for MCB stop it */ + rfc_timer_stop (p_mcb); + + if (p_port->p_callback && (p_port->ev_mask & PORT_EV_CONNECTED)) + (p_port->p_callback)(PORT_EV_CONNECTED, p_port->inx); + + if (p_port->p_mgmt_callback) + p_port->p_mgmt_callback (PORT_SUCCESS, p_port->inx); + + p_port->state = PORT_STATE_OPENED; + + /* RPN is required only if we want to tell DTE how the port should be opened */ + if ((p_port->uuid == UUID_SERVCLASS_DIALUP_NETWORKING) + || (p_port->uuid == UUID_SERVCLASS_FAX)) + RFCOMM_PortNegReq (p_port->rfc.p_mcb, p_port->dlci, NULL); + else + RFCOMM_ControlReq (p_port->rfc.p_mcb, p_port->dlci, &p_port->local_ctrl); +} + + +/******************************************************************************* +** +** Function PORT_PortNegInd +** +** Description This function is called from the RFCOMM layer when peer +** device wants to set parameters of the port. As per the spec +** this message has to be sent before the first data packet +** and can be sent before establish. The block should be +** allocated before meaning that application already made open. +** +*******************************************************************************/ +void PORT_PortNegInd (tRFC_MCB *p_mcb, UINT8 dlci, tPORT_STATE *p_pars, + UINT16 param_mask) +{ + tPORT *p_port = port_find_mcb_dlci_port (p_mcb, dlci); + + RFCOMM_TRACE_EVENT ("PORT_PortNegInd"); + + if (!p_port) + { + /* This can be a first request for this port */ + p_port = port_find_dlci_port (dlci); + if (!p_port) + { + RFCOMM_PortNegRsp (p_mcb, dlci, p_pars, 0); + return; + } + p_mcb->port_inx[dlci] = p_port->inx; + } + + /* Check if the flow control is acceptable on local side */ + p_port->peer_port_pars = *p_pars; + RFCOMM_PortNegRsp (p_mcb, dlci, p_pars, param_mask); +} + + +/******************************************************************************* +** +** Function PORT_PortNegCnf +** +** Description This function is called from the RFCOMM layer to change +** state for the port. Propagate change to the user. +** +*******************************************************************************/ +void PORT_PortNegCnf (tRFC_MCB *p_mcb, UINT8 dlci, tPORT_STATE *p_pars, UINT16 result) +{ + tPORT *p_port = port_find_mcb_dlci_port (p_mcb, dlci); + UNUSED(p_pars); + + RFCOMM_TRACE_EVENT ("PORT_PortNegCnf"); + + if (!p_port) + { + RFCOMM_TRACE_WARNING ("PORT_PortNegCnf no port"); + return; + } + /* Port negotiation failed. Drop the connection */ + if (result != RFCOMM_SUCCESS) + { + p_port->error = PORT_PORT_NEG_FAILED; + + RFCOMM_DlcReleaseReq (p_mcb, p_port->dlci); + + port_rfc_closed (p_port, PORT_PORT_NEG_FAILED); + return; + } + + if (!(p_port->port_ctrl & PORT_CTRL_REQ_SENT)) + { + RFCOMM_ControlReq (p_port->rfc.p_mcb, p_port->dlci, &p_port->local_ctrl); + } + else + { + RFCOMM_TRACE_WARNING ("PORT_PortNegCnf Control Already sent"); + } +} + + +/******************************************************************************* +** +** Function PORT_ControlInd +** +** Description This function is called from the RFCOMM layer on the modem +** signal change. Propagate change to the user. +** +*******************************************************************************/ +void PORT_ControlInd (tRFC_MCB *p_mcb, UINT8 dlci, tPORT_CTRL *p_pars) +{ + tPORT *p_port = port_find_mcb_dlci_port (p_mcb, dlci); + UINT32 event; + UINT8 old_signals; + + RFCOMM_TRACE_EVENT ("PORT_ControlInd"); + + if (!p_port) + return; + + old_signals = p_port->peer_ctrl.modem_signal; + + event = port_get_signal_changes (p_port, old_signals, p_pars->modem_signal); + + p_port->peer_ctrl = *p_pars; + + if (!(p_port->port_ctrl & PORT_CTRL_REQ_SENT)) + RFCOMM_ControlReq (p_port->rfc.p_mcb, p_port->dlci, &p_port->local_ctrl); + else + { + /* If this is the first time we received control RFCOMM is connected */ + if (!(p_port->port_ctrl & PORT_CTRL_IND_RECEIVED)) + { + event |= (PORT_EV_CONNECTED & p_port->ev_mask); + } + + if (p_port->port_ctrl & PORT_CTRL_REQ_CONFIRMED) + { + event |= port_rfc_send_tx_data(p_port); + } + } + + p_port->port_ctrl |= (PORT_CTRL_IND_RECEIVED | PORT_CTRL_IND_RESPONDED); + + if (p_pars->break_signal) + event |= (PORT_EV_BREAK & p_port->ev_mask); + + /* execute call back function only if the application is registered for events */ + if (event && p_port->p_callback) + (p_port->p_callback)(event, p_port->inx); + + RFCOMM_TRACE_EVENT ("PORT_ControlInd DTR_DSR : %d, RTS_CTS : %d, RI : %d, DCD : %d", + ((p_port->peer_ctrl.modem_signal & MODEM_SIGNAL_DTRDSR) ? 1 : 0), + ((p_port->peer_ctrl.modem_signal & MODEM_SIGNAL_RTSCTS) ? 1 : 0), + ((p_port->peer_ctrl.modem_signal & MODEM_SIGNAL_RI) ? 1 : 0), + ((p_port->peer_ctrl.modem_signal & MODEM_SIGNAL_DCD) ? 1 : 0)); + +} + + +/******************************************************************************* +** +** Function PORT_ControlCnf +** +** Description This function is called from the RFCOMM layer when +** peer acknowleges change of the modem signals. +** +*******************************************************************************/ +void PORT_ControlCnf (tRFC_MCB *p_mcb, UINT8 dlci, tPORT_CTRL *p_pars) +{ + tPORT *p_port = port_find_mcb_dlci_port (p_mcb, dlci); + UINT32 event = 0; + UNUSED(p_pars); + + RFCOMM_TRACE_EVENT ("PORT_ControlCnf"); + + if (!p_port) + return; + + if (!(p_port->port_ctrl & PORT_CTRL_REQ_CONFIRMED)) + { + p_port->port_ctrl |= PORT_CTRL_REQ_CONFIRMED; + + if (p_port->port_ctrl & PORT_CTRL_IND_RECEIVED) + event = (p_port->ev_mask & PORT_EV_CONNECTED); + } + + if (p_port->port_ctrl & PORT_CTRL_IND_RECEIVED) + { + event |= port_rfc_send_tx_data(p_port); + } + + /* execute call back function only if the application is registered for events */ + if (event && p_port->p_callback) + (p_port->p_callback)(event, p_port->inx); +} + + +/******************************************************************************* +** +** Function PORT_LineStatusInd +** +** Description This function is called from the RFCOMM layer when +** peer indicates change in the line status +** +*******************************************************************************/ +void PORT_LineStatusInd (tRFC_MCB *p_mcb, UINT8 dlci, UINT8 line_status) +{ + tPORT *p_port = port_find_mcb_dlci_port (p_mcb, dlci); + UINT32 event = 0; + + RFCOMM_TRACE_EVENT ("PORT_LineStatusInd"); + + if (!p_port) + return; + + p_port->line_status |= line_status; + + if (line_status & PORT_ERR_OVERRUN) + event |= PORT_EV_OVERRUN; + + if (line_status & PORT_ERR_BREAK) + event |= PORT_EV_BREAK; + + if (line_status & ~(PORT_ERR_OVERRUN | PORT_ERR_BREAK)) + event |= PORT_EV_ERR; + + if ((p_port->p_callback != NULL) && (p_port->ev_mask & event)) + p_port->p_callback ((p_port->ev_mask & event), p_port->inx); +} + + +/******************************************************************************* +** +** Function PORT_DlcReleaseInd +** +** Description This function is called from the RFCOMM layer when +** DLC connection is released. +** +*******************************************************************************/ +void PORT_DlcReleaseInd (tRFC_MCB *p_mcb, UINT8 dlci) +{ + tPORT *p_port = port_find_mcb_dlci_port (p_mcb, dlci); + + RFCOMM_TRACE_EVENT ("PORT_DlcReleaseInd"); + + if (!p_port) + return; + + port_rfc_closed (p_port, PORT_CLOSED); +} + + +/******************************************************************************* +** +** Function PORT_CloseInd +** +** Description This function is called from the RFCOMM layer when +** multiplexer connection is released. +** +*******************************************************************************/ +void PORT_CloseInd (tRFC_MCB *p_mcb) +{ + tPORT *p_port; + int i; + + RFCOMM_TRACE_EVENT ("PORT_CloseInd"); + + p_port = &rfc_cb.port.port[0]; + for (i = 0; i < MAX_RFC_PORTS; i++, p_port++) + { + if (p_port->rfc.p_mcb == p_mcb) + { + port_rfc_closed (p_port, PORT_PEER_CONNECTION_FAILED); + } + } + rfc_release_multiplexer_channel (p_mcb); +} + +/******************************************************************************* +** +** Function Port_TimeOutCloseMux +** +** Description This function is called when RFCOMM timesout on a command +** as a result multiplexer connection is closed. +** +*******************************************************************************/ +void Port_TimeOutCloseMux (tRFC_MCB *p_mcb) +{ + tPORT *p_port; + int i; + + RFCOMM_TRACE_EVENT ("Port_TimeOutCloseMux"); + + p_port = &rfc_cb.port.port[0]; + for (i = 0; i < MAX_RFC_PORTS; i++, p_port++) + { + if (p_port->rfc.p_mcb == p_mcb) + { + port_rfc_closed (p_port, PORT_PEER_TIMEOUT); + } + } +} + + +/******************************************************************************* +** +** Function PORT_DataInd +** +** Description This function is called from the RFCOMM layer when data +** buffer is received from the peer. +** +*******************************************************************************/ +void PORT_DataInd (tRFC_MCB *p_mcb, UINT8 dlci, BT_HDR *p_buf) +{ + tPORT *p_port = port_find_mcb_dlci_port (p_mcb, dlci); + UINT8 rx_char1; + UINT32 events = 0; + UINT8 *p; + int i; + + RFCOMM_TRACE_EVENT("PORT_DataInd with data length %d, p_mcb:%p,p_port:%p,dlci:%d", + p_buf->len, p_mcb, p_port, dlci); + if (!p_port) + { + GKI_freebuf (p_buf); + return; + } + /* If client registered callout callback with flow control we can just deliver receive data */ + if (p_port->p_data_co_callback) + { + /* Another packet is delivered to user. Send credits to peer if required */ + + if(p_port->p_data_co_callback(p_port->inx, (UINT8*)p_buf, -1, DATA_CO_CALLBACK_TYPE_INCOMING)) + port_flow_control_peer(p_port, TRUE, 1); + else port_flow_control_peer(p_port, FALSE, 0); + //GKI_freebuf (p_buf); + return; + } + else RFCOMM_TRACE_ERROR("PORT_DataInd, p_port:%p, p_data_co_callback is null", p_port); + /* If client registered callback we can just deliver receive data */ + if (p_port->p_data_callback) + { + /* Another packet is delivered to user. Send credits to peer if required */ + port_flow_control_peer(p_port, TRUE, 1); + + p_port->p_data_callback (p_port->inx, (UINT8 *)(p_buf + 1) + p_buf->offset, p_buf->len); + GKI_freebuf (p_buf); + return; + } + + /* Check if rx queue exceeds the limit */ + if ((p_port->rx.queue_size + p_buf->len > PORT_RX_CRITICAL_WM) + || (GKI_queue_length(&p_port->rx.queue) + 1 > p_port->rx_buf_critical)) + { + RFCOMM_TRACE_EVENT ("PORT_DataInd. Buffer over run. Dropping the buffer"); + GKI_freebuf (p_buf); + + RFCOMM_LineStatusReq (p_mcb, dlci, LINE_STATUS_OVERRUN); + return; + } + + /* If user registered to receive notification when a particular byte is */ + /* received we mast check all received bytes */ + if (((rx_char1 = p_port->user_port_pars.rx_char1) != 0) + && (p_port->ev_mask & PORT_EV_RXFLAG)) + { + for (i = 0, p = (UINT8 *)(p_buf + 1) + p_buf->offset; i < p_buf->len; i++) + { + if (*p++ == rx_char1) + { + events |= PORT_EV_RXFLAG; + break; + } + } + } + + PORT_SCHEDULE_LOCK; + + GKI_enqueue (&p_port->rx.queue, p_buf); + p_port->rx.queue_size += p_buf->len; + + PORT_SCHEDULE_UNLOCK; + + /* perform flow control procedures if necessary */ + port_flow_control_peer(p_port, FALSE, 0); + + /* If user indicated flow control can not deliver any notifications to him */ + if (p_port->rx.user_fc) + { + if (events & PORT_EV_RXFLAG) + p_port->rx_flag_ev_pending = TRUE; + + return; + } + + events |= PORT_EV_RXCHAR; + + /* Mask out all events that are not of interest to user */ + events &= p_port->ev_mask; + + if (p_port->p_callback && events) + p_port->p_callback (events, p_port->inx); +} + + +/******************************************************************************* +** +** Function PORT_FlowInd +** +** Description This function is called from the RFCOMM layer on the flow +** control signal change. Propagate change to the user. +** +*******************************************************************************/ +void PORT_FlowInd (tRFC_MCB *p_mcb, UINT8 dlci, BOOLEAN enable_data) +{ + tPORT *p_port = (tPORT *)NULL; + UINT32 events = 0; + int i; + + RFCOMM_TRACE_EVENT ("PORT_FlowInd fc:%d", enable_data); + + if (dlci == 0) + { + p_mcb->peer_ready = enable_data; + } + else + { + if ((p_port = port_find_mcb_dlci_port (p_mcb, dlci)) == NULL) + return; + + p_port->tx.peer_fc = !enable_data; + } + + for (i = 0; i < MAX_RFC_PORTS; i++) + { + /* If DLCI is 0 event applies to all ports */ + if (dlci == 0) + { + p_port = &rfc_cb.port.port[i]; + if (!p_port->in_use + || (p_port->rfc.p_mcb != p_mcb) + || (p_port->rfc.state != RFC_STATE_OPENED)) + continue; + } + events = 0; + + /* Check if flow of data is still enabled */ + events |= port_flow_control_user (p_port); + + /* Check if data can be sent and send it */ + events |= port_rfc_send_tx_data (p_port); + + /* Mask out all events that are not of interest to user */ + events &= p_port->ev_mask; + + /* Send event to the application */ + if (p_port->p_callback && events) + (p_port->p_callback)(events, p_port->inx); + + /* If DLCI is not 0 event applies to one port only */ + if (dlci != 0) + break; + } +} + + +/******************************************************************************* +** +** Function port_rfc_send_tx_data +** +** Description This function is when forward data can be sent to the peer +** +*******************************************************************************/ +UINT32 port_rfc_send_tx_data (tPORT *p_port) +{ + UINT32 events = 0; + BT_HDR *p_buf; + + /* if there is data to be sent */ + if (p_port->tx.queue_size > 0) + { + /* while the rfcomm peer is not flow controlling us, and peer is ready */ + while (!p_port->tx.peer_fc && p_port->rfc.p_mcb && p_port->rfc.p_mcb->peer_ready) + { + /* get data from tx queue and send it */ + PORT_SCHEDULE_LOCK; + + if ((p_buf = (BT_HDR *)GKI_dequeue (&p_port->tx.queue)) != NULL) + { + p_port->tx.queue_size -= p_buf->len; + + PORT_SCHEDULE_UNLOCK; + + RFCOMM_TRACE_DEBUG ("Sending RFCOMM_DataReq tx.queue_size=%d", p_port->tx.queue_size); + + RFCOMM_DataReq (p_port->rfc.p_mcb, p_port->dlci, p_buf); + + events |= PORT_EV_TXCHAR; + + if (p_port->tx.queue_size == 0) + { + events |= PORT_EV_TXEMPTY; + break; + } + } + /* queue is empty-- all data sent */ + else + { + PORT_SCHEDULE_UNLOCK; + + events |= PORT_EV_TXEMPTY; + break; + } + } + /* If we flow controlled user based on the queue size enable data again */ + events |= port_flow_control_user (p_port); + } + return (events & p_port->ev_mask); +} + + +/******************************************************************************* +** +** Function port_rfc_closed +** +** Description This function when RFCOMM side of port is closed +** +*******************************************************************************/ +void port_rfc_closed (tPORT *p_port, UINT8 res) +{ + UINT8 old_signals; + UINT32 events = 0; + tRFC_MCB *p_mcb = p_port->rfc.p_mcb; + + if ((p_port->state == PORT_STATE_OPENING) && (p_port->is_server)) + { + /* The servr side has not been informed that connection is up, ignore */ + RFCOMM_TRACE_EVENT ("port_rfc_closed in OPENING state ignored"); + + rfc_port_timer_stop (p_port); + p_port->rfc.state = RFC_STATE_CLOSED; + + if (p_mcb) + { + p_mcb->port_inx[p_port->dlci] = 0; + + /* If there are no more ports opened on this MCB release it */ + rfc_check_mcb_active (p_mcb); + p_port->rfc.p_mcb = NULL; + } + + /* Need to restore DLCI to listening state + * if the server was on the initiating RFC + */ + p_port->dlci &= 0xfe; + + return; + } + + if ((p_port->state != PORT_STATE_CLOSING) && (p_port->state != PORT_STATE_CLOSED)) + { + p_port->line_status |= LINE_STATUS_FAILED; + + old_signals = p_port->peer_ctrl.modem_signal; + + p_port->peer_ctrl.modem_signal &= ~(PORT_DTRDSR_ON | PORT_CTSRTS_ON | PORT_DCD_ON); + + events |= port_get_signal_changes (p_port, old_signals, p_port->peer_ctrl.modem_signal); + + if(p_port->ev_mask & PORT_EV_CONNECT_ERR) + events |= PORT_EV_CONNECT_ERR; + } + RFCOMM_TRACE_EVENT ("port_rfc_closed state:%d sending events:%x", p_port->state, events); + + if ((p_port->p_callback != NULL) && events) + p_port->p_callback (events, p_port->inx); + + if (p_port->p_mgmt_callback) + p_port->p_mgmt_callback (res, p_port->inx); + + p_port->rfc.state = RFC_STATE_CLOSED; + + RFCOMM_TRACE_WARNING ("%s RFCOMM connection in state %d closed: %s (res: %d)", + __func__, p_port->state, PORT_GetResultString(res), res); + + port_release_port (p_port); +} + + +/******************************************************************************* +** +** Function port_get_credits +** +** Description Set initial values for credits. +** Adjust max number of rx credits based on negotiated MTU. +** Check max allowed num of bytes, max allowed num buffers, +** should be less then 255 +** +*******************************************************************************/ +void port_get_credits (tPORT *p_port, UINT8 k) +{ + p_port->credit_tx = k; + if (p_port->credit_tx == 0) + p_port->tx.peer_fc = TRUE; +} diff --git a/components/bt/bluedroid/stack/rfcomm/port_utils.c b/components/bt/bluedroid/stack/rfcomm/port_utils.c new file mode 100755 index 0000000000..7d29336ddb --- /dev/null +++ b/components/bt/bluedroid/stack/rfcomm/port_utils.c @@ -0,0 +1,587 @@ +/****************************************************************************** + * + * Copyright (C) 1999-2012 Broadcom Corporation + * + * 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. + * + ******************************************************************************/ + +/****************************************************************************** + * + * Port Emulation entity utilities + * + ******************************************************************************/ +#include + +#include "bt_target.h" +#include "gki.h" +#include "rfcdefs.h" +#include "port_api.h" +#include "port_int.h" +#include "rfc_int.h" +#include "l2cdefs.h" +#include "btm_int.h" +#include "btu.h" + +static const tPORT_STATE default_port_pars = +{ + PORT_BAUD_RATE_9600, + PORT_8_BITS, + PORT_ONESTOPBIT, + PORT_PARITY_NO, + PORT_ODD_PARITY, + PORT_FC_OFF, + 0, /* No rx_char */ + PORT_XON_DC1, + PORT_XOFF_DC3, +}; + + + +/******************************************************************************* +** +** Function port_allocate_port +** +** Description Look through the Port Control Blocks for a free one. Note +** that one server can open several ports with the same SCN +** if it can support simulteneous requests from different +** clients. +** +** Returns Pointer to the PORT or NULL if not found +** +*******************************************************************************/ +tPORT *port_allocate_port (UINT8 dlci, BD_ADDR bd_addr) +{ + tPORT *p_port = &rfc_cb.port.port[0]; + UINT8 xx, yy; + + for (xx = 0, yy = rfc_cb.rfc.last_port + 1; xx < MAX_RFC_PORTS; xx++, yy++) + { + if (yy >= MAX_RFC_PORTS) + yy = 0; + + p_port = &rfc_cb.port.port[yy]; + if (!p_port->in_use) + { + memset (p_port, 0, sizeof (tPORT)); + + p_port->in_use = TRUE; + p_port->inx = yy + 1; + + p_port->dlci = dlci; + memcpy (p_port->bd_addr, bd_addr, BD_ADDR_LEN); + + /* During the open set default state for the port connection */ + port_set_defaults (p_port); + + rfc_cb.rfc.last_port = yy; + RFCOMM_TRACE_DEBUG("rfc_cb.port.port[%d]:%p allocated, last_port:%d", yy, p_port, rfc_cb.rfc.last_port); + RFCOMM_TRACE_DEBUG("port_allocate_port:bd_addr:%02x:%02x:%02x:%02x:%02x:%02x", + bd_addr[0], bd_addr[1], bd_addr[2], bd_addr[3], bd_addr[4], bd_addr[5]); + return (p_port); + } + } + + /* If here, no free PORT found */ + return (NULL); +} + + +/******************************************************************************* +** +** Function port_set_defaults +** +** Description Set defualt port parameters +** +** +*******************************************************************************/ +void port_set_defaults (tPORT *p_port) +{ + p_port->ev_mask = 0; + p_port->p_callback = NULL; + p_port->port_ctrl = 0; + p_port->error = 0; + p_port->line_status = 0; + p_port->rx_flag_ev_pending = FALSE; + p_port->peer_mtu = RFCOMM_DEFAULT_MTU; + + p_port->user_port_pars = default_port_pars; + p_port->peer_port_pars = default_port_pars; + + p_port->credit_tx = 0; + p_port->credit_rx = 0; +/* p_port->credit_rx_max = PORT_CREDIT_RX_MAX; Determined later */ +/* p_port->credit_rx_low = PORT_CREDIT_RX_LOW; Determined later */ + + memset (&p_port->local_ctrl, 0, sizeof (p_port->local_ctrl)); + memset (&p_port->peer_ctrl, 0, sizeof (p_port->peer_ctrl)); + memset (&p_port->rx, 0, sizeof (p_port->rx)); + memset (&p_port->tx, 0, sizeof (p_port->tx)); +} + +/******************************************************************************* +** +** Function port_select_mtu +** +** Description Select MTU which will best serve connection from our +** point of view. +** If our device is 1.2 or lower we calculate how many DH5s +** fit into 1 RFCOMM buffer. +** +** +*******************************************************************************/ +void port_select_mtu (tPORT *p_port) +{ + UINT16 packet_size; + + /* Will select MTU only if application did not setup something */ + if (p_port->mtu == 0) + { + /* find packet size which connection supports */ + packet_size = btm_get_max_packet_size (p_port->bd_addr); + if (packet_size == 0) + { + /* something is very wrong */ + RFCOMM_TRACE_WARNING ("port_select_mtu bad packet size"); + p_port->mtu = RFCOMM_DEFAULT_MTU; + } + else + { + /* We try to negotiate MTU that each packet can be split into whole + number of max packets. For example if link is 1.2 max packet size is 339 bytes. + At first calculate how many whole packets it is. MAX L2CAP is 1691 + 4 overhead. + 1695, that will be 5 Dh5 packets. Now maximum RFCOMM packet is + 5 * 339 = 1695. Minus 4 bytes L2CAP header 1691. Minus RFCOMM 6 bytes header overhead 1685 + + For EDR 2.0 packet size is 1027. So we better send RFCOMM packet as 1 3DH5 packet + 1 * 1027 = 1027. Minus 4 bytes L2CAP header 1023. Minus RFCOMM 6 bytes header overhead 1017 */ + if ((L2CAP_MTU_SIZE + L2CAP_PKT_OVERHEAD) >= packet_size) + { + p_port->mtu = ((L2CAP_MTU_SIZE + L2CAP_PKT_OVERHEAD) / packet_size * packet_size) - RFCOMM_DATA_OVERHEAD - L2CAP_PKT_OVERHEAD; + RFCOMM_TRACE_DEBUG ("port_select_mtu selected %d based on connection speed", p_port->mtu); + } + else + { + p_port->mtu = L2CAP_MTU_SIZE - RFCOMM_DATA_OVERHEAD; + RFCOMM_TRACE_DEBUG ("port_select_mtu selected %d based on l2cap PDU size", p_port->mtu); + } + } + } + else + { + RFCOMM_TRACE_DEBUG ("port_select_mtu application selected %d", p_port->mtu); + } + p_port->credit_rx_max = (PORT_RX_HIGH_WM / p_port->mtu); + if( p_port->credit_rx_max > PORT_RX_BUF_HIGH_WM ) + p_port->credit_rx_max = PORT_RX_BUF_HIGH_WM; + p_port->credit_rx_low = (PORT_RX_LOW_WM / p_port->mtu); + if( p_port->credit_rx_low > PORT_RX_BUF_LOW_WM ) + p_port->credit_rx_low = PORT_RX_BUF_LOW_WM; + p_port->rx_buf_critical = (PORT_RX_CRITICAL_WM / p_port->mtu); + if( p_port->rx_buf_critical > PORT_RX_BUF_CRITICAL_WM ) + p_port->rx_buf_critical = PORT_RX_BUF_CRITICAL_WM; + RFCOMM_TRACE_DEBUG ("port_select_mtu credit_rx_max %d, credit_rx_low %d, rx_buf_critical %d", + p_port->credit_rx_max, p_port->credit_rx_low, p_port->rx_buf_critical); +} + + +/******************************************************************************* +** +** Function port_release_port +** +** Description Release port infor control block. +** +** Returns Pointer to the PORT or NULL if not found +** +*******************************************************************************/ +void port_release_port (tPORT *p_port) +{ + BT_HDR *p_buf; + UINT32 mask; + tPORT_CALLBACK *p_port_cb; + tPORT_STATE user_port_pars; + + PORT_SCHEDULE_LOCK; + RFCOMM_TRACE_DEBUG("port_release_port, p_port:%p", p_port); + while ((p_buf = (BT_HDR *)GKI_dequeue (&p_port->rx.queue)) != NULL) + GKI_freebuf (p_buf); + + p_port->rx.queue_size = 0; + + while ((p_buf = (BT_HDR *)GKI_dequeue (&p_port->tx.queue)) != NULL) + GKI_freebuf (p_buf); + + p_port->tx.queue_size = 0; + + PORT_SCHEDULE_UNLOCK; + + p_port->state = PORT_STATE_CLOSED; + + if (p_port->rfc.state == RFC_STATE_CLOSED) + { + RFCOMM_TRACE_DEBUG ("rfc_port_closed DONE"); + if (p_port->rfc.p_mcb) + { + p_port->rfc.p_mcb->port_inx[p_port->dlci] = 0; + + /* If there are no more ports opened on this MCB release it */ + rfc_check_mcb_active (p_port->rfc.p_mcb); + } + rfc_port_timer_stop (p_port); + RFCOMM_TRACE_DEBUG ("port_release_port:p_port->keep_port_handle:%d", p_port->keep_port_handle); + if( p_port->keep_port_handle ) + { + RFCOMM_TRACE_DEBUG ("port_release_port:Initialize handle:%d", p_port->inx); + /* save event mask and callback */ + mask = p_port->ev_mask; + p_port_cb = p_port->p_callback; + user_port_pars = p_port->user_port_pars; + + port_set_defaults(p_port); + /* restore */ + p_port->ev_mask = mask; + p_port->p_callback = p_port_cb; + p_port->user_port_pars = user_port_pars; + p_port->mtu = p_port->keep_mtu; + + p_port->state = PORT_STATE_OPENING; + p_port->rfc.p_mcb = NULL; + if(p_port->is_server) + p_port->dlci &= 0xfe; + + p_port->local_ctrl.modem_signal = p_port->default_signal_state; + memcpy (p_port->bd_addr, BT_BD_ANY, BD_ADDR_LEN); + } + else + { + RFCOMM_TRACE_DEBUG ("port_release_port:Clean-up handle:%d", p_port->inx); + memset (p_port, 0, sizeof (tPORT)); + } + } +} + + +/******************************************************************************* +** +** Function port_find_mcb +** +** Description This function checks if connection exists to device with +** the BD_ADDR. +** +*******************************************************************************/ +tRFC_MCB *port_find_mcb (BD_ADDR bd_addr) +{ + int i; + + for (i = 0; i < MAX_BD_CONNECTIONS; i++) + { + if ((rfc_cb.port.rfc_mcb[i].state != RFC_MX_STATE_IDLE) + && !memcmp (rfc_cb.port.rfc_mcb[i].bd_addr, bd_addr, BD_ADDR_LEN)) + { + /* Multiplexer channel found do not change anything */ + RFCOMM_TRACE_DEBUG("port_find_mcb: found bd_addr:%02x:%02x:%02x:%02x:%02x:%02x", + bd_addr[0], bd_addr[1], bd_addr[2], bd_addr[3], bd_addr[4], bd_addr[5]); + RFCOMM_TRACE_DEBUG("port_find_mcb: rfc_cb.port.rfc_mcb:index:%d, %p, lcid:%d", + i, &rfc_cb.port.rfc_mcb[i], rfc_cb.port.rfc_mcb[i].lcid); + return (&rfc_cb.port.rfc_mcb[i]); + } + } + RFCOMM_TRACE_DEBUG("port_find_mcb: not found, bd_addr:%02x:%02x:%02x:%02x:%02x:%02x", + bd_addr[0], bd_addr[1], bd_addr[2], bd_addr[3], bd_addr[4], bd_addr[5]); + return (NULL); +} + + +/******************************************************************************* +** +** Function port_find_mcb_dlci_port +** +** Description Find port on the multiplexer channel based on DLCI. If +** this port with DLCI not found try to use even DLCI. This +** is for the case when client is establishing connection on +** none-initiator MCB. +** +** Returns Pointer to the PORT or NULL if not found +** +*******************************************************************************/ +tPORT *port_find_mcb_dlci_port (tRFC_MCB *p_mcb, UINT8 dlci) +{ + UINT8 inx; + + if (!p_mcb) + return (NULL); + + if (dlci > RFCOMM_MAX_DLCI) + return (NULL); + + inx = p_mcb->port_inx[dlci]; + if (inx == 0) + { + RFCOMM_TRACE_DEBUG("port_find_mcb_dlci_port: p_mcb:%p, port_inx[dlci:%d] is 0", p_mcb, dlci); + return (NULL); + } + else + return (&rfc_cb.port.port[inx - 1]); +} + + +/******************************************************************************* +** +** Function port_find_dlci_port +** +** Description Find port with DLCI not assigned to multiplexer channel +** +** Returns Pointer to the PORT or NULL if not found +** +*******************************************************************************/ +tPORT *port_find_dlci_port (UINT8 dlci) +{ + UINT16 i; + tPORT *p_port; + + for (i = 0; i < MAX_RFC_PORTS; i++) + { + p_port = &rfc_cb.port.port[i]; + + if (p_port->in_use && (p_port->rfc.p_mcb == NULL)) + { + if (p_port->dlci == dlci) + { + return (p_port); + } + else if ((dlci & 0x01) && (p_port->dlci == (dlci - 1))) + { + p_port->dlci++; + return (p_port); + } + } + } + return (NULL); +} + + +/******************************************************************************* +** +** Function port_find_port +** +** Description Find port with DLCI, BD_ADDR +** +** Returns Pointer to the PORT or NULL if not found +** +*******************************************************************************/ +tPORT *port_find_port (UINT8 dlci, BD_ADDR bd_addr) +{ + UINT16 i; + tPORT *p_port; + + for (i = 0; i < MAX_RFC_PORTS; i++) + { + p_port = &rfc_cb.port.port[i]; + if (p_port->in_use + && (p_port->dlci == dlci) + && !memcmp (p_port->bd_addr, bd_addr, BD_ADDR_LEN)) + { + return (p_port); + } + } + return (NULL); +} + + +/******************************************************************************* +** +** Function port_flow_control_user +** +** Description Check the current user flow control and if necessary return +** events to be send to the user based on the user's specified +** flow control type. +** +** Returns event mask to be returned to the application +** +*******************************************************************************/ +UINT32 port_flow_control_user (tPORT *p_port) +{ + UINT32 event = 0; + + /* Flow control to the user can be caused by flow controlling by the peer */ + /* (FlowInd, or flow control by the peer RFCOMM (Fcon) or internally if */ + /* tx_queue is full */ + BOOLEAN fc = p_port->tx.peer_fc + || !p_port->rfc.p_mcb + || !p_port->rfc.p_mcb->peer_ready + || (p_port->tx.queue_size > PORT_TX_HIGH_WM) + || (GKI_queue_length(&p_port->tx.queue) > PORT_TX_BUF_HIGH_WM); + + if (p_port->tx.user_fc == fc) + return (0); + + p_port->tx.user_fc = fc; + + if (fc) + event = PORT_EV_FC; + else + event = PORT_EV_FC | PORT_EV_FCS; + + return (event); +} + + +/******************************************************************************* +** +** Function port_get_signal_changes +** +** Description Check modem signals that has been changed +** +** Returns event mask to be returned to the application +** +*******************************************************************************/ +UINT32 port_get_signal_changes (tPORT *p_port, UINT8 old_signals, UINT8 signal) +{ + UINT8 changed_signals = (signal ^ old_signals); + UINT32 events = 0; + + if (changed_signals & PORT_DTRDSR_ON) + { + events |= PORT_EV_DSR; + + if (signal & PORT_DTRDSR_ON) + events |= PORT_EV_DSRS; + } + + if (changed_signals & PORT_CTSRTS_ON) + { + events |= PORT_EV_CTS; + + if (signal & PORT_CTSRTS_ON) + events |= PORT_EV_CTSS; + } + + if (changed_signals & PORT_RING_ON) + events |= PORT_EV_RING; + + if (changed_signals & PORT_DCD_ON) + { + events |= PORT_EV_RLSD; + + if (signal & PORT_DCD_ON) + events |= PORT_EV_RLSDS; + } + + return (p_port->ev_mask & events); +} + +/******************************************************************************* +** +** Function port_flow_control_peer +** +** Description Send flow control messages to the peer for both enabling +** and disabling flow control, for both credit-based and +** TS 07.10 flow control mechanisms. +** +** Returns nothing +** +*******************************************************************************/ +void port_flow_control_peer(tPORT *p_port, BOOLEAN enable, UINT16 count) +{ + if (!p_port->rfc.p_mcb) + return; + + /* If using credit based flow control */ + if (p_port->rfc.p_mcb->flow == PORT_FC_CREDIT) + { + /* if want to enable flow from peer */ + if (enable) + { + /* update rx credits */ + if (count > p_port->credit_rx) + { + p_port->credit_rx = 0; + } + else + { + p_port->credit_rx -= count; + } + + /* If credit count is less than low credit watermark, and user */ + /* did not force flow control, send a credit update */ + /* There might be a special case when we just adjusted rx_max */ + if ((p_port->credit_rx <= p_port->credit_rx_low) + && !p_port->rx.user_fc + && (p_port->credit_rx_max > p_port->credit_rx)) + { + rfc_send_credit(p_port->rfc.p_mcb, p_port->dlci, + (UINT8) (p_port->credit_rx_max - p_port->credit_rx)); + + p_port->credit_rx = p_port->credit_rx_max; + + p_port->rx.peer_fc = FALSE; + } + } + /* else want to disable flow from peer */ + else + { + /* if client registered data callback, just do what they want */ + if (p_port->p_data_callback || p_port->p_data_co_callback) + { + p_port->rx.peer_fc = TRUE; + } + /* if queue count reached credit rx max, set peer fc */ + else if (GKI_queue_length(&p_port->rx.queue) >= p_port->credit_rx_max) + { + p_port->rx.peer_fc = TRUE; + } + } + } + /* else using TS 07.10 flow control */ + else + { + /* if want to enable flow from peer */ + if (enable) + { + /* If rfcomm suspended traffic from the peer based on the rx_queue_size */ + /* check if it can be resumed now */ + if (p_port->rx.peer_fc + && (p_port->rx.queue_size < PORT_RX_LOW_WM) + && (GKI_queue_length(&p_port->rx.queue) < PORT_RX_BUF_LOW_WM)) + { + p_port->rx.peer_fc = FALSE; + + /* If user did not force flow control allow traffic now */ + if (!p_port->rx.user_fc) + RFCOMM_FlowReq (p_port->rfc.p_mcb, p_port->dlci, TRUE); + } + } + /* else want to disable flow from peer */ + else + { + /* if client registered data callback, just do what they want */ + if (p_port->p_data_callback || p_port->p_data_co_callback) + { + p_port->rx.peer_fc = TRUE; + RFCOMM_FlowReq (p_port->rfc.p_mcb, p_port->dlci, FALSE); + } + /* Check the size of the rx queue. If it exceeds certain */ + /* level and flow control has not been sent to the peer do it now */ + else if ( ((p_port->rx.queue_size > PORT_RX_HIGH_WM) + || (GKI_queue_length(&p_port->rx.queue) > PORT_RX_BUF_HIGH_WM)) + && !p_port->rx.peer_fc) + { + RFCOMM_TRACE_EVENT ("PORT_DataInd Data reached HW. Sending FC set."); + + p_port->rx.peer_fc = TRUE; + RFCOMM_FlowReq (p_port->rfc.p_mcb, p_port->dlci, FALSE); + } + } + } +} + diff --git a/components/bt/bluedroid/stack/rfcomm/rfc_l2cap_if.c b/components/bt/bluedroid/stack/rfcomm/rfc_l2cap_if.c new file mode 100755 index 0000000000..fba523a0f0 --- /dev/null +++ b/components/bt/bluedroid/stack/rfcomm/rfc_l2cap_if.c @@ -0,0 +1,447 @@ +/****************************************************************************** + * + * Copyright (C) 1999-2012 Broadcom Corporation + * + * 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 L2CAP interface functions + * + ******************************************************************************/ + +#include +#include "bt_target.h" +#include "gki.h" + +#include "rfcdefs.h" +#include "port_api.h" +#include "port_int.h" +#include "l2c_api.h" +#include "l2cdefs.h" +#include "rfc_int.h" +#include "bt_defs.h" + + +/* +** Define Callback functions to be called by L2CAP +*/ +static void RFCOMM_ConnectInd (BD_ADDR bd_addr, UINT16 lcid, UINT16 psm, UINT8 id); +static void RFCOMM_ConnectCnf (UINT16 lcid, UINT16 err); +static void RFCOMM_ConfigInd (UINT16 lcid, tL2CAP_CFG_INFO *p_cfg); +static void RFCOMM_ConfigCnf (UINT16 lcid, tL2CAP_CFG_INFO *p_cfg); +static void RFCOMM_DisconnectInd (UINT16 lcid, BOOLEAN is_clear); +static void RFCOMM_QoSViolationInd (BD_ADDR bd_addr); +static void RFCOMM_BufDataInd (UINT16 lcid, BT_HDR *p_buf); +static void RFCOMM_CongestionStatusInd (UINT16 lcid, BOOLEAN is_congested); + + +/******************************************************************************* +** +** Function rfcomm_l2cap_if_init +** +** Description This function is called during the RFCOMM task startup +** to register interface functions with L2CAP. +** +*******************************************************************************/ +void rfcomm_l2cap_if_init (void) +{ + tL2CAP_APPL_INFO *p_l2c = &rfc_cb.rfc.reg_info; + + p_l2c->pL2CA_ConnectInd_Cb = RFCOMM_ConnectInd; + p_l2c->pL2CA_ConnectCfm_Cb = RFCOMM_ConnectCnf; + p_l2c->pL2CA_ConnectPnd_Cb = NULL; + p_l2c->pL2CA_ConfigInd_Cb = RFCOMM_ConfigInd; + p_l2c->pL2CA_ConfigCfm_Cb = RFCOMM_ConfigCnf; + p_l2c->pL2CA_DisconnectInd_Cb = RFCOMM_DisconnectInd; + p_l2c->pL2CA_DisconnectCfm_Cb = NULL; + p_l2c->pL2CA_QoSViolationInd_Cb = RFCOMM_QoSViolationInd; + p_l2c->pL2CA_DataInd_Cb = RFCOMM_BufDataInd; + p_l2c->pL2CA_CongestionStatus_Cb = RFCOMM_CongestionStatusInd; + p_l2c->pL2CA_TxComplete_Cb = NULL; + + + L2CA_Register (BT_PSM_RFCOMM, p_l2c); +} + + +/******************************************************************************* +** +** Function RFCOMM_ConnectInd +** +** Description This is a callback function called by L2CAP when +** L2CA_ConnectInd received. Allocate multiplexer control block +** and dispatch the event to it. +** +*******************************************************************************/ +void RFCOMM_ConnectInd (BD_ADDR bd_addr, UINT16 lcid, UINT16 psm, UINT8 id) +{ + tRFC_MCB *p_mcb = rfc_alloc_multiplexer_channel(bd_addr, FALSE); + UNUSED(psm); + + if ((p_mcb)&&(p_mcb->state != RFC_MX_STATE_IDLE)) + { + /* if this is collision case */ + if ((p_mcb->is_initiator)&&(p_mcb->state == RFC_MX_STATE_WAIT_CONN_CNF)) + { + p_mcb->pending_lcid = lcid; + p_mcb->pending_id = id; + + /* wait random timeout (2 - 12) to resolve collision */ + /* if peer gives up then local device rejects incoming connection and continues as initiator */ + /* if timeout, local device disconnects outgoing connection and continues as acceptor */ + RFCOMM_TRACE_DEBUG ("RFCOMM_ConnectInd start timer for collision, initiator's LCID(0x%x), acceptor's LCID(0x%x)", + p_mcb->lcid, p_mcb->pending_lcid); + + rfc_timer_start(p_mcb, (UINT16)(GKI_get_os_tick_count()%10 + 2)); + return; + } + else + { + /* we cannot accept connection request from peer at this state */ + /* don't update lcid */ + p_mcb = NULL; + } + } + else + { + /* store mcb even if null */ + rfc_save_lcid_mcb (p_mcb, lcid); + } + + if (p_mcb == NULL) + { + L2CA_ConnectRsp (bd_addr, id, lcid, L2CAP_CONN_NO_RESOURCES, 0); + return; + } + p_mcb->lcid = lcid; + + rfc_mx_sm_execute (p_mcb, RFC_MX_EVENT_CONN_IND, &id); +} + + +/******************************************************************************* +** +** Function RFCOMM_ConnectCnf +** +** Description This is a callback function called by L2CAP when +** L2CA_ConnectCnf received. Save L2CAP handle and dispatch +** event to the FSM. +** +*******************************************************************************/ +void RFCOMM_ConnectCnf (UINT16 lcid, UINT16 result) +{ + tRFC_MCB *p_mcb = rfc_find_lcid_mcb (lcid); + + if (!p_mcb) + { + RFCOMM_TRACE_ERROR ("RFCOMM_ConnectCnf LCID:0x%x", lcid); + return; + } + + if (p_mcb->pending_lcid) + { + /* if peer rejects our connect request but peer's connect request is pending */ + if (result != L2CAP_CONN_OK ) + { + UINT16 i; + UINT8 idx; + + RFCOMM_TRACE_DEBUG ("RFCOMM_ConnectCnf retry as acceptor on pending LCID(0x%x)", p_mcb->pending_lcid); + + /* remove mcb from mapping table */ + rfc_save_lcid_mcb (NULL, p_mcb->lcid); + + p_mcb->lcid = p_mcb->pending_lcid; + p_mcb->is_initiator = FALSE; + p_mcb->state = RFC_MX_STATE_IDLE; + + /* store mcb into mapping table */ + rfc_save_lcid_mcb (p_mcb, p_mcb->lcid); + + /* update direction bit */ + for (i = 0; i < RFCOMM_MAX_DLCI; i += 2) + { + if ((idx = p_mcb->port_inx[i]) != 0) + { + p_mcb->port_inx[i] = 0; + p_mcb->port_inx[i+1] = idx; + rfc_cb.port.port[idx - 1].dlci += 1; + RFCOMM_TRACE_DEBUG ("RFCOMM MX - DLCI:%d -> %d", i, rfc_cb.port.port[idx - 1].dlci); + } + } + + rfc_mx_sm_execute (p_mcb, RFC_MX_EVENT_CONN_IND, &(p_mcb->pending_id)); + return; + } + else + { + RFCOMM_TRACE_DEBUG ("RFCOMM_ConnectCnf peer gave up pending LCID(0x%x)", p_mcb->pending_lcid); + + /* Peer gave up his connection request, make sure cleaning up L2CAP channel */ + L2CA_ConnectRsp (p_mcb->bd_addr, p_mcb->pending_id, p_mcb->pending_lcid, L2CAP_CONN_NO_RESOURCES, 0); + + p_mcb->pending_lcid = 0; + } + } + + /* Save LCID to be used in all consecutive calls to L2CAP */ + p_mcb->lcid = lcid; + + rfc_mx_sm_execute (p_mcb, RFC_MX_EVENT_CONN_CNF, &result); +} + + +/******************************************************************************* +** +** Function RFCOMM_ConfigInd +** +** Description This is a callback function called by L2CAP when +** L2CA_ConfigInd received. Save parameters in the control +** block and dispatch event to the FSM. +** +*******************************************************************************/ +void RFCOMM_ConfigInd (UINT16 lcid, tL2CAP_CFG_INFO *p_cfg) +{ + tRFC_MCB *p_mcb = rfc_find_lcid_mcb (lcid); + + if (!p_mcb) + { + RFCOMM_TRACE_ERROR ("RFCOMM_ConfigInd LCID:0x%x", lcid); + return; + } + + rfc_mx_sm_execute (p_mcb, RFC_MX_EVENT_CONF_IND, (void *)p_cfg); +} + + +/******************************************************************************* +** +** Function RFCOMM_ConfigCnf +** +** Description This is a callback function called by L2CAP when +** L2CA_ConfigCnf received. Save L2CAP handle and dispatch +** event to the FSM. +** +*******************************************************************************/ +void RFCOMM_ConfigCnf (UINT16 lcid, tL2CAP_CFG_INFO *p_cfg) +{ + tRFC_MCB *p_mcb = rfc_find_lcid_mcb (lcid); + + if (!p_mcb) + { + RFCOMM_TRACE_ERROR ("RFCOMM_ConfigCnf no MCB LCID:0x%x", lcid); + return; + } + + rfc_mx_sm_execute (p_mcb, RFC_MX_EVENT_CONF_CNF, (void *)p_cfg); +} + + +/******************************************************************************* +** +** Function RFCOMM_QoSViolationInd +** +** Description This is a callback function called by L2CAP when +** L2CA_QoSViolationIndInd received. Dispatch event to the FSM. +** +*******************************************************************************/ +void RFCOMM_QoSViolationInd (BD_ADDR bd_addr) +{ + UNUSED(bd_addr); +} + + +/******************************************************************************* +** +** Function RFCOMM_DisconnectInd +** +** Description This is a callback function called by L2CAP when +** L2CA_DisconnectInd received. Dispatch event to the FSM. +** +*******************************************************************************/ +void RFCOMM_DisconnectInd (UINT16 lcid, BOOLEAN is_conf_needed) +{ + tRFC_MCB *p_mcb = rfc_find_lcid_mcb (lcid); + + if (is_conf_needed) + { + L2CA_DisconnectRsp (lcid); + } + + if (!p_mcb) + { + RFCOMM_TRACE_WARNING ("RFCOMM_DisconnectInd LCID:0x%x", lcid); + return; + } + + rfc_mx_sm_execute (p_mcb, RFC_MX_EVENT_DISC_IND, NULL); +} + + +/******************************************************************************* +** +** Function RFCOMM_BufDataInd +** +** Description This is a callback function called by L2CAP when +** data RFCOMM frame is received. Parse the frames, check +** the checksum and dispatch event to multiplexer or port +** state machine depending on the frame destination. +** +*******************************************************************************/ +void RFCOMM_BufDataInd (UINT16 lcid, BT_HDR *p_buf) +{ + tRFC_MCB *p_mcb = rfc_find_lcid_mcb (lcid); + tPORT *p_port; + UINT8 event; + + + if (!p_mcb) + { + RFCOMM_TRACE_WARNING ("RFCOMM_BufDataInd LCID:0x%x", lcid); + GKI_freebuf (p_buf); + return; + } + + event = rfc_parse_data (p_mcb, &rfc_cb.rfc.rx_frame, p_buf); + + /* If the frame did not pass validation just ignore it */ + if (event == RFC_EVENT_BAD_FRAME) + { + GKI_freebuf (p_buf); + return; + } + + if (rfc_cb.rfc.rx_frame.dlci == RFCOMM_MX_DLCI) + { + /* Take special care of the Multiplexer Control Messages */ + if (event == RFC_EVENT_UIH) + { + rfc_process_mx_message (p_mcb, p_buf); + return; + } + + /* Other multiplexer events go to state machine */ + rfc_mx_sm_execute (p_mcb, event, NULL); + GKI_freebuf (p_buf); + return; + } + + /* The frame was received on the data channel DLCI, verify that DLC exists */ + if (((p_port = port_find_mcb_dlci_port (p_mcb, rfc_cb.rfc.rx_frame.dlci)) == NULL) + || (!p_port->rfc.p_mcb)) + { + /* If this is a SABME on the new port, check if any appl is waiting for it */ + if (event != RFC_EVENT_SABME) + { + if (( p_mcb->is_initiator && !rfc_cb.rfc.rx_frame.cr) + || (!p_mcb->is_initiator && rfc_cb.rfc.rx_frame.cr)) + rfc_send_dm (p_mcb, rfc_cb.rfc.rx_frame.dlci, rfc_cb.rfc.rx_frame.pf); + GKI_freebuf (p_buf); + return; + } + + if ((p_port = port_find_dlci_port (rfc_cb.rfc.rx_frame.dlci)) == NULL) + { + rfc_send_dm (p_mcb, rfc_cb.rfc.rx_frame.dlci, TRUE); + GKI_freebuf (p_buf); + return; + } + p_mcb->port_inx[rfc_cb.rfc.rx_frame.dlci] = p_port->inx; + p_port->rfc.p_mcb = p_mcb; + } + + if (event == RFC_EVENT_UIH) + { + if (p_buf->len > 0) + rfc_port_sm_execute (p_port, event, p_buf); + else + GKI_freebuf (p_buf); + + if (rfc_cb.rfc.rx_frame.credit != 0) + rfc_inc_credit (p_port, rfc_cb.rfc.rx_frame.credit); + + return; + } + rfc_port_sm_execute (p_port, event, NULL); + GKI_freebuf (p_buf); +} + +/******************************************************************************* +** +** Function RFCOMM_CongestionStatusInd +** +** Description This is a callback function called by L2CAP when +** data RFCOMM L2CAP congestion status changes +** +*******************************************************************************/ +void RFCOMM_CongestionStatusInd (UINT16 lcid, BOOLEAN is_congested) +{ + tRFC_MCB *p_mcb = rfc_find_lcid_mcb (lcid); + + if (!p_mcb) + { + RFCOMM_TRACE_ERROR ("RFCOMM_CongestionStatusInd dropped LCID:0x%x", lcid); + return; + } + else + { + RFCOMM_TRACE_EVENT ("RFCOMM_CongestionStatusInd LCID:0x%x", lcid); + } + rfc_process_l2cap_congestion (p_mcb, is_congested); +} + +/******************************************************************************* +** +** Function rfc_find_lcid_mcb +** +** Description This function returns MCB block supporting local cid +** +*******************************************************************************/ +tRFC_MCB *rfc_find_lcid_mcb (UINT16 lcid) +{ + tRFC_MCB *p_mcb; + + if (lcid - L2CAP_BASE_APPL_CID >= MAX_L2CAP_CHANNELS) + { + RFCOMM_TRACE_ERROR ("rfc_find_lcid_mcb LCID:0x%x", lcid); + return (NULL); + } + else + { + if ((p_mcb = rfc_cb.rfc.p_rfc_lcid_mcb[lcid - L2CAP_BASE_APPL_CID]) != NULL) + { + if (p_mcb->lcid != lcid) + { + RFCOMM_TRACE_WARNING ("rfc_find_lcid_mcb LCID reused LCID:0x%x current:0x%x", lcid, p_mcb->lcid); + return (NULL); + } + } + } + return (p_mcb); +} + + +/******************************************************************************* +** +** Function rfc_save_lcid_mcb +** +** Description This function returns MCB block supporting local cid +** +*******************************************************************************/ +void rfc_save_lcid_mcb (tRFC_MCB *p_mcb, UINT16 lcid) +{ + rfc_cb.rfc.p_rfc_lcid_mcb[lcid - L2CAP_BASE_APPL_CID] = p_mcb; +} diff --git a/components/bt/bluedroid/stack/rfcomm/rfc_mx_fsm.c b/components/bt/bluedroid/stack/rfcomm/rfc_mx_fsm.c new file mode 100755 index 0000000000..10d6d6a0ee --- /dev/null +++ b/components/bt/bluedroid/stack/rfcomm/rfc_mx_fsm.c @@ -0,0 +1,672 @@ +/****************************************************************************** + * + * Copyright (C) 1999-2012 Broadcom Corporation + * + * 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 state machine and action routines for multiplexer + * channel of the RFCOMM unit + * + ******************************************************************************/ +#include +#include "gki.h" +#include "bt_types.h" +#include "rfcdefs.h" +#include "l2cdefs.h" +#include "port_api.h" +#include "port_int.h" +#include "l2c_api.h" +#include "rfc_int.h" +#include "bt_defs.h" + +#define L2CAP_SUCCESS 0 +#define L2CAP_ERROR 1 + + +/********************************************************************************/ +/* L O C A L F U N C T I O N P R O T O T Y P E S */ +/********************************************************************************/ +static void rfc_mx_sm_state_idle (tRFC_MCB *p_mcb, UINT16 event, void *p_data); +static void rfc_mx_sm_state_wait_conn_cnf (tRFC_MCB *p_mcb, UINT16 event, void *p_data); +static void rfc_mx_sm_state_configure (tRFC_MCB *p_mcb, UINT16 event, void *p_data); +static void rfc_mx_sm_sabme_wait_ua (tRFC_MCB *p_mcb, UINT16 event, void *p_data); +static void rfc_mx_sm_state_wait_sabme (tRFC_MCB *p_mcb, UINT16 event, void *p_data); +static void rfc_mx_sm_state_connected (tRFC_MCB *p_mcb, UINT16 event, void *p_data); +static void rfc_mx_sm_state_disc_wait_ua (tRFC_MCB *p_mcb, UINT16 event, void *p_data); + +static void rfc_mx_send_config_req (tRFC_MCB *p_mcb); +static void rfc_mx_conf_ind (tRFC_MCB *p_mcb, tL2CAP_CFG_INFO *p_cfg); +static void rfc_mx_conf_cnf (tRFC_MCB *p_mcb, tL2CAP_CFG_INFO *p_cfg); + + + +/******************************************************************************* +** +** Function rfc_mx_sm_execute +** +** Description This function sends multiplexor events through the state +** machine. +** +** Returns void +** +*******************************************************************************/ +void rfc_mx_sm_execute (tRFC_MCB *p_mcb, UINT16 event, void *p_data) +{ + switch (p_mcb->state) + { + case RFC_MX_STATE_IDLE: + rfc_mx_sm_state_idle (p_mcb, event, p_data); + break; + + case RFC_MX_STATE_WAIT_CONN_CNF: + rfc_mx_sm_state_wait_conn_cnf (p_mcb, event, p_data); + break; + + case RFC_MX_STATE_CONFIGURE: + rfc_mx_sm_state_configure (p_mcb, event, p_data); + break; + + case RFC_MX_STATE_SABME_WAIT_UA: + rfc_mx_sm_sabme_wait_ua (p_mcb, event, p_data); + break; + + case RFC_MX_STATE_WAIT_SABME: + rfc_mx_sm_state_wait_sabme (p_mcb, event, p_data); + break; + + case RFC_MX_STATE_CONNECTED: + rfc_mx_sm_state_connected (p_mcb, event, p_data); + break; + + case RFC_MX_STATE_DISC_WAIT_UA: + rfc_mx_sm_state_disc_wait_ua (p_mcb, event, p_data); + break; + + } +} + + +/******************************************************************************* +** +** Function rfc_mx_sm_state_idle +** +** Description This function handles events when the multiplexer is in +** IDLE state. This state exists when connection is being +** initially established. +** +** Returns void +** +*******************************************************************************/ +void rfc_mx_sm_state_idle (tRFC_MCB *p_mcb, UINT16 event, void *p_data) +{ + RFCOMM_TRACE_EVENT ("rfc_mx_sm_state_idle - evt:%d", event); + switch (event) + { + case RFC_MX_EVENT_START_REQ: + + /* Initialize L2CAP MTU */ + p_mcb->peer_l2cap_mtu = L2CAP_DEFAULT_MTU - RFCOMM_MIN_OFFSET - 1; + + if ((p_mcb->lcid = L2CA_ConnectReq (BT_PSM_RFCOMM, p_mcb->bd_addr)) == 0) + { + PORT_StartCnf (p_mcb, RFCOMM_ERROR); + return; + } + /* Save entry for quicker access to mcb based on the LCID */ + rfc_save_lcid_mcb (p_mcb, p_mcb->lcid); + + p_mcb->state = RFC_MX_STATE_WAIT_CONN_CNF; + return; + + case RFC_MX_EVENT_START_RSP: + case RFC_MX_EVENT_CONN_CNF: + case RFC_MX_EVENT_CONF_IND: + case RFC_MX_EVENT_CONF_CNF: + RFCOMM_TRACE_ERROR ("Mx error state %d event %d", p_mcb->state, event); + return; + + case RFC_MX_EVENT_CONN_IND: + + rfc_timer_start (p_mcb, RFCOMM_CONN_TIMEOUT); + L2CA_ConnectRsp (p_mcb->bd_addr, *((UINT8 *)p_data), p_mcb->lcid, L2CAP_CONN_OK, 0); + + rfc_mx_send_config_req (p_mcb); + + p_mcb->state = RFC_MX_STATE_CONFIGURE; + return; + + case RFC_EVENT_SABME: + break; + + case RFC_EVENT_UA: + case RFC_EVENT_DM: + return; + + case RFC_EVENT_DISC: + rfc_send_dm (p_mcb, RFCOMM_MX_DLCI, TRUE); + return; + + case RFC_EVENT_UIH: + rfc_send_dm (p_mcb, RFCOMM_MX_DLCI, FALSE); + return; + } + RFCOMM_TRACE_EVENT ("RFCOMM MX ignored - evt:%d in state:%d", event, p_mcb->state); +} + + +/******************************************************************************* +** +** Function rfc_mx_sm_state_wait_conn_cnf +** +** Description This function handles events when the multiplexer is +** waiting for Connection Confirm from L2CAP. +** +** Returns void +** +*******************************************************************************/ +void rfc_mx_sm_state_wait_conn_cnf (tRFC_MCB *p_mcb, UINT16 event, void *p_data) +{ + RFCOMM_TRACE_EVENT ("rfc_mx_sm_state_wait_conn_cnf - evt:%d", event); + switch (event) + { + case RFC_MX_EVENT_START_REQ: + RFCOMM_TRACE_ERROR ("Mx error state %d event %d", p_mcb->state, event); + return; + + /* There is some new timing so that Config Ind comes before security is completed + so we are still waiting fo the confirmation. */ + case RFC_MX_EVENT_CONF_IND: + rfc_mx_conf_ind (p_mcb, (tL2CAP_CFG_INFO *)p_data); + return; + + case RFC_MX_EVENT_CONN_CNF: + if (*((UINT16 *)p_data) != L2CAP_SUCCESS) + { + p_mcb->state = RFC_MX_STATE_IDLE; + + PORT_StartCnf (p_mcb, *((UINT16 *)p_data)); + return; + } + p_mcb->state = RFC_MX_STATE_CONFIGURE; + rfc_mx_send_config_req (p_mcb); + return; + + case RFC_MX_EVENT_DISC_IND: + p_mcb->state = RFC_MX_STATE_IDLE; + PORT_CloseInd (p_mcb); + return; + + case RFC_EVENT_TIMEOUT: + p_mcb->state = RFC_MX_STATE_IDLE; + L2CA_DisconnectReq (p_mcb->lcid); + + /* we gave up outgoing connection request then try peer's request */ + if (p_mcb->pending_lcid) + { + UINT16 i; + UINT8 idx; + + RFCOMM_TRACE_DEBUG ("RFCOMM MX retry as acceptor in collision case - evt:%d in state:%d", event, p_mcb->state); + + rfc_save_lcid_mcb (NULL, p_mcb->lcid); + p_mcb->lcid = p_mcb->pending_lcid; + rfc_save_lcid_mcb (p_mcb, p_mcb->lcid); + + p_mcb->is_initiator = FALSE; + + /* update direction bit */ + for (i = 0; i < RFCOMM_MAX_DLCI; i += 2) + { + if ((idx = p_mcb->port_inx[i]) != 0) + { + p_mcb->port_inx[i] = 0; + p_mcb->port_inx[i+1] = idx; + rfc_cb.port.port[idx - 1].dlci += 1; + RFCOMM_TRACE_DEBUG ("RFCOMM MX - DLCI:%d -> %d", i, rfc_cb.port.port[idx - 1].dlci); + } + } + + rfc_mx_sm_execute (p_mcb, RFC_MX_EVENT_CONN_IND, &(p_mcb->pending_id)); + } + else + { + PORT_CloseInd (p_mcb); + } + return; + } + RFCOMM_TRACE_EVENT ("RFCOMM MX ignored - evt:%d in state:%d", event, p_mcb->state); +} + + +/******************************************************************************* +** +** Function rfc_mx_sm_state_configure +** +** Description This function handles events when the multiplexer in the +** configuration state. +** +** Returns void +** +*******************************************************************************/ +void rfc_mx_sm_state_configure (tRFC_MCB *p_mcb, UINT16 event, void *p_data) +{ + RFCOMM_TRACE_EVENT ("rfc_mx_sm_state_configure - evt:%d", event); + switch (event) + { + case RFC_MX_EVENT_START_REQ: + case RFC_MX_EVENT_CONN_CNF: + + RFCOMM_TRACE_ERROR ("Mx error state %d event %d", p_mcb->state, event); + return; + + case RFC_MX_EVENT_CONF_IND: + rfc_mx_conf_ind (p_mcb, (tL2CAP_CFG_INFO *)p_data); + return; + + case RFC_MX_EVENT_CONF_CNF: + rfc_mx_conf_cnf (p_mcb, (tL2CAP_CFG_INFO *)p_data); + return; + + case RFC_MX_EVENT_DISC_IND: + p_mcb->state = RFC_MX_STATE_IDLE; + PORT_CloseInd (p_mcb); + return; + + case RFC_EVENT_TIMEOUT: + p_mcb->state = RFC_MX_STATE_IDLE; + L2CA_DisconnectReq (p_mcb->lcid); + + PORT_StartCnf (p_mcb, RFCOMM_ERROR); + return; + } + RFCOMM_TRACE_EVENT ("RFCOMM MX ignored - evt:%d in state:%d", event, p_mcb->state); +} + + +/******************************************************************************* +** +** Function rfc_mx_sm_sabme_wait_ua +** +** Description This function handles events when the multiplexer sent +** SABME and is waiting for UA reply. +** +** Returns void +** +*******************************************************************************/ +void rfc_mx_sm_sabme_wait_ua (tRFC_MCB *p_mcb, UINT16 event, void *p_data) +{ + UNUSED(p_data); + + RFCOMM_TRACE_EVENT ("rfc_mx_sm_sabme_wait_ua - evt:%d", event); + switch (event) + { + case RFC_MX_EVENT_START_REQ: + case RFC_MX_EVENT_CONN_CNF: + RFCOMM_TRACE_ERROR ("Mx error state %d event %d", p_mcb->state, event); + return; + + /* workaround: we don't support reconfig */ + /* commented out until we support reconfig + case RFC_MX_EVENT_CONF_IND: + rfc_mx_conf_ind (p_mcb, (tL2CAP_CFG_INFO *)p_data); + return; + + case RFC_MX_EVENT_CONF_CNF: + rfc_mx_conf_cnf (p_mcb, (tL2CAP_CFG_INFO *)p_data); + return; + */ + + case RFC_MX_EVENT_DISC_IND: + p_mcb->state = RFC_MX_STATE_IDLE; + PORT_CloseInd (p_mcb); + return; + + case RFC_EVENT_UA: + rfc_timer_stop (p_mcb); + + p_mcb->state = RFC_MX_STATE_CONNECTED; + p_mcb->peer_ready = TRUE; + + PORT_StartCnf (p_mcb, RFCOMM_SUCCESS); + return; + + case RFC_EVENT_DM: + rfc_timer_stop (p_mcb); + /* Case falls through */ + + case RFC_MX_EVENT_CONF_IND: /* workaround: we don't support reconfig */ + case RFC_MX_EVENT_CONF_CNF: /* workaround: we don't support reconfig */ + case RFC_EVENT_TIMEOUT: + p_mcb->state = RFC_MX_STATE_IDLE; + L2CA_DisconnectReq (p_mcb->lcid); + + PORT_StartCnf (p_mcb, RFCOMM_ERROR); + return; + } + RFCOMM_TRACE_EVENT ("RFCOMM MX ignored - evt:%d in state:%d", event, p_mcb->state); +} + +/******************************************************************************* +** +** Function rfc_mx_sm_state_wait_sabme +** +** Description This function handles events when the multiplexer is +** waiting for SABME on the acceptor side after configuration +** +** Returns void +** +*******************************************************************************/ +void rfc_mx_sm_state_wait_sabme (tRFC_MCB *p_mcb, UINT16 event, void *p_data) +{ + RFCOMM_TRACE_EVENT ("rfc_mx_sm_state_wait_sabme - evt:%d", event); + switch (event) + { + case RFC_MX_EVENT_DISC_IND: + p_mcb->state = RFC_MX_STATE_IDLE; + PORT_CloseInd (p_mcb); + return; + + case RFC_EVENT_SABME: + /* if we gave up outgoing connection request */ + if (p_mcb->pending_lcid) + { + p_mcb->pending_lcid = 0; + + rfc_send_ua (p_mcb, RFCOMM_MX_DLCI); + + rfc_timer_stop (p_mcb); + p_mcb->state = RFC_MX_STATE_CONNECTED; + p_mcb->peer_ready = TRUE; + + /* MX channel collision has been resolved, continue to open ports */ + PORT_StartCnf (p_mcb, RFCOMM_SUCCESS); + } + else + { + rfc_timer_stop (p_mcb); + PORT_StartInd (p_mcb); + } + return; + + case RFC_MX_EVENT_START_RSP: + if (*((UINT16 *)p_data) != RFCOMM_SUCCESS) + rfc_send_dm (p_mcb, RFCOMM_MX_DLCI, TRUE); + else + { + rfc_send_ua (p_mcb, RFCOMM_MX_DLCI); + + p_mcb->state = RFC_MX_STATE_CONNECTED; + p_mcb->peer_ready = TRUE; + } + return; + + case RFC_MX_EVENT_CONF_IND: /* workaround: we don't support reconfig */ + case RFC_MX_EVENT_CONF_CNF: /* workaround: we don't support reconfig */ + case RFC_EVENT_TIMEOUT: + p_mcb->state = RFC_MX_STATE_IDLE; + L2CA_DisconnectReq (p_mcb->lcid); + + PORT_CloseInd (p_mcb); + return; + } + RFCOMM_TRACE_EVENT ("RFCOMM MX ignored - evt:%d in state:%d", event, p_mcb->state); +} + + +/******************************************************************************* +** +** Function rfc_mx_sm_state_connected +** +** Description This function handles events when the multiplexer is +** in the CONNECTED state +** +** Returns void +** +*******************************************************************************/ +void rfc_mx_sm_state_connected (tRFC_MCB *p_mcb, UINT16 event, void *p_data) +{ + UNUSED(p_data); + + RFCOMM_TRACE_EVENT ("rfc_mx_sm_state_connected - evt:%d", event); + + switch (event) + { + case RFC_EVENT_TIMEOUT: + case RFC_MX_EVENT_CLOSE_REQ: + rfc_timer_start (p_mcb, RFC_DISC_TIMEOUT); + p_mcb->state = RFC_MX_STATE_DISC_WAIT_UA; + rfc_send_disc (p_mcb, RFCOMM_MX_DLCI); + return; + + case RFC_MX_EVENT_DISC_IND: + p_mcb->state = RFC_MX_STATE_IDLE; + PORT_CloseInd (p_mcb); + return; + + case RFC_EVENT_DISC: + /* Reply with UA. If initiator bring down L2CAP connection */ + /* If server wait for some time if client decide to reinitiate channel */ + rfc_send_ua (p_mcb, RFCOMM_MX_DLCI); + if (p_mcb->is_initiator) + { + L2CA_DisconnectReq (p_mcb->lcid); + } + /* notify all ports that connection is gone */ + PORT_CloseInd (p_mcb); + return; + } + RFCOMM_TRACE_EVENT ("RFCOMM MX ignored - evt:%d in state:%d", event, p_mcb->state); +} + + +/******************************************************************************* +** +** Function rfc_mx_sm_state_disc_wait_ua +** +** Description This function handles events when the multiplexer sent +** DISC and is waiting for UA reply. +** +** Returns void +** +*******************************************************************************/ +void rfc_mx_sm_state_disc_wait_ua (tRFC_MCB *p_mcb, UINT16 event, void *p_data) +{ + BT_HDR *p_buf; + + RFCOMM_TRACE_EVENT ("rfc_mx_sm_state_disc_wait_ua - evt:%d", event); + switch (event) + { + case RFC_EVENT_UA: + case RFC_EVENT_DM: + case RFC_EVENT_TIMEOUT: + L2CA_DisconnectReq (p_mcb->lcid); + + if (p_mcb->restart_required) + { + /* Start Request was received while disconnecting. Execute it again */ + if ((p_mcb->lcid = L2CA_ConnectReq (BT_PSM_RFCOMM, p_mcb->bd_addr)) == 0) + { + PORT_StartCnf (p_mcb, RFCOMM_ERROR); + return; + } + /* Save entry for quicker access to mcb based on the LCID */ + rfc_save_lcid_mcb (p_mcb, p_mcb->lcid); + + /* clean up before reuse it */ + while ((p_buf = (BT_HDR *)GKI_dequeue(&p_mcb->cmd_q)) != NULL) + GKI_freebuf(p_buf); + + rfc_timer_start (p_mcb, RFC_MCB_INIT_INACT_TIMER); + + p_mcb->is_initiator = TRUE; + p_mcb->restart_required = FALSE; + p_mcb->local_cfg_sent = FALSE; + p_mcb->peer_cfg_rcvd = FALSE; + + p_mcb->state = RFC_MX_STATE_WAIT_CONN_CNF; + return; + } + rfc_release_multiplexer_channel (p_mcb); + return; + + case RFC_EVENT_DISC: + rfc_send_ua (p_mcb, RFCOMM_MX_DLCI); + return; + + case RFC_EVENT_UIH: + GKI_freebuf (p_data); + rfc_send_dm (p_mcb, RFCOMM_MX_DLCI, FALSE); + return; + + case RFC_MX_EVENT_START_REQ: + p_mcb->restart_required = TRUE; + return; + + case RFC_MX_EVENT_DISC_IND: + p_mcb->state = RFC_MX_STATE_IDLE; + PORT_CloseInd (p_mcb); + return; + + case RFC_MX_EVENT_CLOSE_REQ: + return; + + case RFC_MX_EVENT_QOS_VIOLATION_IND: + break; + } + RFCOMM_TRACE_EVENT ("RFCOMM MX ignored - evt:%d in state:%d", event, p_mcb->state); +} + + +/******************************************************************************* +** +** Function rfc_mx_send_config_req +** +** Description This function handles L2CA_ConnectInd message from the +** L2CAP. Accept connection. +** +*******************************************************************************/ +static void rfc_mx_send_config_req (tRFC_MCB *p_mcb) +{ + tL2CAP_CFG_INFO cfg; + + RFCOMM_TRACE_EVENT ("rfc_mx_send_config_req"); + + memset (&cfg, 0, sizeof (tL2CAP_CFG_INFO)); + + cfg.mtu_present = TRUE; + cfg.mtu = L2CAP_MTU_SIZE; + +/* Defaults set by memset + cfg.flush_to_present = FALSE; + cfg.qos_present = FALSE; + cfg.fcr_present = FALSE; + cfg.fcr.mode = L2CAP_FCR_BASIC_MODE; + cfg.fcs_present = FALSE; + cfg.fcs = N/A when fcs_present is FALSE; +*/ + L2CA_ConfigReq (p_mcb->lcid, &cfg); +} + + +/******************************************************************************* +** +** Function rfc_mx_conf_cnf +** +** Description This function handles L2CA_ConfigCnf message from the +** L2CAP. If result is not success tell upper layer that +** start has not been accepted. If initiator send SABME +** on DLCI 0. T1 is still running. +** +*******************************************************************************/ +static void rfc_mx_conf_cnf (tRFC_MCB *p_mcb, tL2CAP_CFG_INFO *p_cfg) +{ + RFCOMM_TRACE_EVENT ("rfc_mx_conf_cnf p_cfg:%08x res:%d ", p_cfg, (p_cfg) ? p_cfg->result : 0); + + if (p_cfg->result != L2CAP_CFG_OK) + { + if (p_mcb->is_initiator) + { + PORT_StartCnf (p_mcb, p_cfg->result); + L2CA_DisconnectReq (p_mcb->lcid); + } + rfc_release_multiplexer_channel (p_mcb); + return; + } + + p_mcb->local_cfg_sent = TRUE; + if ((p_mcb->state == RFC_MX_STATE_CONFIGURE) && p_mcb->peer_cfg_rcvd) + { + if (p_mcb->is_initiator) + { + p_mcb->state = RFC_MX_STATE_SABME_WAIT_UA; + rfc_send_sabme (p_mcb, RFCOMM_MX_DLCI); + rfc_timer_start (p_mcb, RFC_T1_TIMEOUT); + } + else + { + p_mcb->state = RFC_MX_STATE_WAIT_SABME; + rfc_timer_start (p_mcb, RFCOMM_CONN_TIMEOUT); /* - increased from T2=20 to CONN=120 + to allow the user more than 10 sec to type in the + pin which can be e.g. 16 digits */ + } + } +} + + +/******************************************************************************* +** +** Function rfc_mx_conf_ind +** +** Description This function handles L2CA_ConfigInd message from the +** L2CAP. Send the L2CA_ConfigRsp message. +** +*******************************************************************************/ +static void rfc_mx_conf_ind (tRFC_MCB *p_mcb, tL2CAP_CFG_INFO *p_cfg) +{ + /* Save peer L2CAP MTU if present */ + /* RFCOMM adds 3-4 bytes in the beginning and 1 bytes FCS */ + if (p_cfg->mtu_present) + p_mcb->peer_l2cap_mtu = p_cfg->mtu - RFCOMM_MIN_OFFSET - 1; + else + p_mcb->peer_l2cap_mtu = L2CAP_DEFAULT_MTU - RFCOMM_MIN_OFFSET - 1; + + p_cfg->mtu_present = FALSE; + p_cfg->flush_to_present = FALSE; + p_cfg->qos_present = FALSE; + + p_cfg->result = L2CAP_CFG_OK; + + L2CA_ConfigRsp (p_mcb->lcid, p_cfg); + + p_mcb->peer_cfg_rcvd = TRUE; + if ((p_mcb->state == RFC_MX_STATE_CONFIGURE) && p_mcb->local_cfg_sent) + { + if (p_mcb->is_initiator) + { + p_mcb->state = RFC_MX_STATE_SABME_WAIT_UA; + rfc_send_sabme (p_mcb, RFCOMM_MX_DLCI); + rfc_timer_start (p_mcb, RFC_T1_TIMEOUT); + } + else + { + p_mcb->state = RFC_MX_STATE_WAIT_SABME; + rfc_timer_start (p_mcb, RFCOMM_CONN_TIMEOUT); /* - increased from T2=20 to CONN=120 + to allow the user more than 10 sec to type in the + pin which can be e.g. 16 digits */ + } + } +} diff --git a/components/bt/bluedroid/stack/rfcomm/rfc_port_fsm.c b/components/bt/bluedroid/stack/rfcomm/rfc_port_fsm.c new file mode 100755 index 0000000000..0d082aac9e --- /dev/null +++ b/components/bt/bluedroid/stack/rfcomm/rfc_port_fsm.c @@ -0,0 +1,920 @@ +/****************************************************************************** + * + * Copyright (C) 1999-2012 Broadcom Corporation + * + * 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 state machine and action routines for a port of the + * RFCOMM unit + * + ******************************************************************************/ +#include +#include "bt_target.h" +#include "gki.h" +#include "rfcdefs.h" +#include "btm_api.h" +#include "btm_int.h" +#include "port_api.h" +#include "port_int.h" +#include "rfc_int.h" +#include "bt_defs.h" + +/********************************************************************************/ +/* L O C A L F U N C T I O N P R O T O T Y P E S */ +/********************************************************************************/ +static void rfc_port_sm_state_closed (tPORT *p_port, UINT16 event, void *p_data); +static void rfc_port_sm_sabme_wait_ua (tPORT *p_port, UINT16 event, void *p_data); +static void rfc_port_sm_opened (tPORT *p_port, UINT16 event, void *p_data); +static void rfc_port_sm_orig_wait_sec_check (tPORT *p_port, UINT16 event, void *p_data); +static void rfc_port_sm_term_wait_sec_check (tPORT *p_port, UINT16 event, void *p_data); +static void rfc_port_sm_disc_wait_ua (tPORT *p_port, UINT16 event, void *p_data); + +static void rfc_port_uplink_data (tPORT *p_port, BT_HDR *p_buf); + +static void rfc_set_port_state(tPORT_STATE *port_pars, MX_FRAME *p_frame); + + +/******************************************************************************* +** +** Function rfc_port_sm_execute +** +** Description This function sends port events through the state +** machine. +** +** Returns void +** +*******************************************************************************/ +void rfc_port_sm_execute (tPORT *p_port, UINT16 event, void *p_data) +{ + if (!p_port) + { + RFCOMM_TRACE_WARNING ("NULL port event %d", event); + return; + } + + switch (p_port->rfc.state) + { + case RFC_STATE_CLOSED: + rfc_port_sm_state_closed (p_port, event, p_data); + break; + + case RFC_STATE_SABME_WAIT_UA: + rfc_port_sm_sabme_wait_ua (p_port, event, p_data); + break; + + case RFC_STATE_ORIG_WAIT_SEC_CHECK: + rfc_port_sm_orig_wait_sec_check (p_port, event, p_data); + break; + + case RFC_STATE_TERM_WAIT_SEC_CHECK: + rfc_port_sm_term_wait_sec_check (p_port, event, p_data); + break; + + case RFC_STATE_OPENED: + rfc_port_sm_opened (p_port, event, p_data); + break; + + case RFC_STATE_DISC_WAIT_UA: + rfc_port_sm_disc_wait_ua (p_port, event, p_data); + break; + } +} + + +/******************************************************************************* +** +** Function rfc_port_sm_state_closed +** +** Description This function handles events when the port is in +** CLOSED state. This state exists when port is +** being initially established. +** +** Returns void +** +*******************************************************************************/ +void rfc_port_sm_state_closed (tPORT *p_port, UINT16 event, void *p_data) +{ + switch (event) + { + case RFC_EVENT_OPEN: + p_port->rfc.state = RFC_STATE_ORIG_WAIT_SEC_CHECK; + btm_sec_mx_access_request (p_port->rfc.p_mcb->bd_addr, BT_PSM_RFCOMM, TRUE, + BTM_SEC_PROTO_RFCOMM, (UINT32)(p_port->dlci / 2), + &rfc_sec_check_complete, p_port); + return; + + case RFC_EVENT_CLOSE: + break; + + case RFC_EVENT_CLEAR: + return; + + case RFC_EVENT_DATA: + GKI_freebuf (p_data); + break; + + case RFC_EVENT_SABME: + /* make sure the multiplexer disconnect timer is not running (reconnect case) */ + rfc_timer_stop(p_port->rfc.p_mcb ); + + /* Open will be continued after security checks are passed */ + p_port->rfc.state = RFC_STATE_TERM_WAIT_SEC_CHECK; + btm_sec_mx_access_request (p_port->rfc.p_mcb->bd_addr, BT_PSM_RFCOMM, FALSE, + BTM_SEC_PROTO_RFCOMM, (UINT32)(p_port->dlci / 2), + &rfc_sec_check_complete, p_port); + return; + + case RFC_EVENT_UA: + return; + + case RFC_EVENT_DM: + rfc_port_closed (p_port); + return; + + case RFC_EVENT_UIH: + GKI_freebuf (p_data); + rfc_send_dm (p_port->rfc.p_mcb, p_port->dlci, FALSE); + return; + + case RFC_EVENT_DISC: + rfc_send_dm (p_port->rfc.p_mcb, p_port->dlci, FALSE); + return; + + case RFC_EVENT_TIMEOUT: + Port_TimeOutCloseMux( p_port->rfc.p_mcb ) ; + RFCOMM_TRACE_ERROR ("Port error state %d event %d", p_port->rfc.state, event); + return; + } + + RFCOMM_TRACE_WARNING ("Port state closed Event ignored %d", event); + return; +} + +/******************************************************************************* +** +** Function rfc_port_sm_sabme_wait_ua +** +** Description This function handles events when SABME on the DLC was +** sent and SM is waiting for UA or DM. +** +** Returns void +** +*******************************************************************************/ +void rfc_port_sm_sabme_wait_ua (tPORT *p_port, UINT16 event, void *p_data) +{ + switch (event) + { + case RFC_EVENT_OPEN: + case RFC_EVENT_ESTABLISH_RSP: + RFCOMM_TRACE_ERROR ("Port error state %d event %d", p_port->rfc.state, event); + return; + + case RFC_EVENT_CLOSE: + rfc_port_timer_start (p_port, RFC_DISC_TIMEOUT); + rfc_send_disc (p_port->rfc.p_mcb, p_port->dlci); + p_port->rfc.expected_rsp = 0; + p_port->rfc.state = RFC_STATE_DISC_WAIT_UA; + return; + + case RFC_EVENT_CLEAR: + rfc_port_closed (p_port); + return; + + case RFC_EVENT_DATA: + GKI_freebuf (p_data); + break; + + case RFC_EVENT_UA: + rfc_port_timer_stop (p_port); + p_port->rfc.state = RFC_STATE_OPENED; + PORT_DlcEstablishCnf (p_port->rfc.p_mcb, p_port->dlci, p_port->rfc.p_mcb->peer_l2cap_mtu, RFCOMM_SUCCESS); + return; + + case RFC_EVENT_DM: + p_port->rfc.p_mcb->is_disc_initiator = TRUE; + PORT_DlcEstablishCnf (p_port->rfc.p_mcb, p_port->dlci, p_port->rfc.p_mcb->peer_l2cap_mtu, RFCOMM_ERROR); + rfc_port_closed (p_port); + return; + + case RFC_EVENT_DISC: + rfc_send_ua (p_port->rfc.p_mcb, p_port->dlci); + PORT_DlcEstablishCnf (p_port->rfc.p_mcb, p_port->dlci, p_port->rfc.p_mcb->peer_l2cap_mtu, RFCOMM_ERROR); + rfc_port_closed (p_port); + return; + + case RFC_EVENT_SABME: + /* Continue to wait for the UA the SABME this side sent */ + rfc_send_ua (p_port->rfc.p_mcb, p_port->dlci); + return; + + case RFC_EVENT_UIH: + GKI_freebuf (p_data); + return; + + case RFC_EVENT_TIMEOUT: + p_port->rfc.state = RFC_STATE_CLOSED; + PORT_DlcEstablishCnf (p_port->rfc.p_mcb, p_port->dlci, p_port->rfc.p_mcb->peer_l2cap_mtu, RFCOMM_ERROR); + return; + } + RFCOMM_TRACE_WARNING ("Port state sabme_wait_ua Event ignored %d", event); +} + + +/******************************************************************************* +** +** Function rfc_port_sm_term_wait_sec_check +** +** Description This function handles events for the port in the +** WAIT_SEC_CHECK state. SABME has been received from the +** peer and Security Manager verifes BD_ADDR, before we can +** send ESTABLISH_IND to the Port entity +** +** Returns void +** +*******************************************************************************/ +void rfc_port_sm_term_wait_sec_check (tPORT *p_port, UINT16 event, void *p_data) +{ + switch (event) + { + case RFC_EVENT_SEC_COMPLETE: + if (*((UINT8 *)p_data) != BTM_SUCCESS) + { + /* Authentication/authorization failed. If link is still */ + /* up send DM and check if we need to start inactive timer */ + if (p_port->rfc.p_mcb) + { + rfc_send_dm (p_port->rfc.p_mcb, p_port->dlci, TRUE); + p_port->rfc.p_mcb->is_disc_initiator = TRUE; + port_rfc_closed (p_port, PORT_SEC_FAILED); + } + } + else + { + PORT_DlcEstablishInd (p_port->rfc.p_mcb, p_port->dlci, p_port->rfc.p_mcb->peer_l2cap_mtu); + } + return; + + case RFC_EVENT_OPEN: + case RFC_EVENT_CLOSE: + RFCOMM_TRACE_ERROR ("Port error state %d event %d", p_port->rfc.state, event); + return; + + case RFC_EVENT_CLEAR: + btm_sec_abort_access_req (p_port->rfc.p_mcb->bd_addr); + rfc_port_closed (p_port); + return; + + case RFC_EVENT_DATA: + RFCOMM_TRACE_ERROR ("Port error state Term Wait Sec event Data"); + GKI_freebuf (p_data); + return; + + case RFC_EVENT_SABME: + /* Ignore SABME retransmission if client dares to do so */ + return; + + case RFC_EVENT_DISC: + btm_sec_abort_access_req (p_port->rfc.p_mcb->bd_addr); + p_port->rfc.state = RFC_STATE_CLOSED; + rfc_send_ua (p_port->rfc.p_mcb, p_port->dlci); + + PORT_DlcReleaseInd (p_port->rfc.p_mcb, p_port->dlci); + return; + + case RFC_EVENT_UIH: + GKI_freebuf (p_data); + return; + + case RFC_EVENT_ESTABLISH_RSP: + if (*((UINT8 *)p_data) != RFCOMM_SUCCESS) + { + if (p_port->rfc.p_mcb) + rfc_send_dm (p_port->rfc.p_mcb, p_port->dlci, TRUE); + } + else + { + rfc_send_ua (p_port->rfc.p_mcb, p_port->dlci); + p_port->rfc.state = RFC_STATE_OPENED; + } + return; + } + RFCOMM_TRACE_WARNING ("Port state term_wait_sec_check Event ignored %d", event); +} + + +/******************************************************************************* +** +** Function rfc_port_sm_orig_wait_sec_check +** +** Description This function handles events for the port in the +** ORIG_WAIT_SEC_CHECK state. RFCOMM is waiting for Security +** manager to finish before sending SABME to the peer +** +** Returns void +** +*******************************************************************************/ +void rfc_port_sm_orig_wait_sec_check (tPORT *p_port, UINT16 event, void *p_data) +{ + switch (event) + { + case RFC_EVENT_SEC_COMPLETE: + if (*((UINT8 *)p_data) != BTM_SUCCESS) + { + p_port->rfc.p_mcb->is_disc_initiator = TRUE; + PORT_DlcEstablishCnf (p_port->rfc.p_mcb, p_port->dlci, 0, RFCOMM_SECURITY_ERR); + rfc_port_closed (p_port); + return; + } + rfc_send_sabme (p_port->rfc.p_mcb, p_port->dlci); + rfc_port_timer_start (p_port, RFC_PORT_T1_TIMEOUT); + p_port->rfc.state = RFC_STATE_SABME_WAIT_UA; + return; + + case RFC_EVENT_OPEN: + case RFC_EVENT_SABME: /* Peer should not use the same dlci */ + RFCOMM_TRACE_ERROR ("Port error state %d event %d", p_port->rfc.state, event); + return; + + case RFC_EVENT_CLOSE: + btm_sec_abort_access_req (p_port->rfc.p_mcb->bd_addr); + rfc_port_closed (p_port); + return; + + case RFC_EVENT_DATA: + RFCOMM_TRACE_ERROR ("Port error state Orig Wait Sec event Data"); + GKI_freebuf (p_data); + return; + + case RFC_EVENT_UIH: + GKI_freebuf (p_data); + return; + } + RFCOMM_TRACE_WARNING ("Port state orig_wait_sec_check Event ignored %d", event); +} + + +/******************************************************************************* +** +** Function rfc_port_sm_opened +** +** Description This function handles events for the port in the OPENED +** state +** +** Returns void +** +*******************************************************************************/ +void rfc_port_sm_opened (tPORT *p_port, UINT16 event, void *p_data) +{ + switch (event) + { + case RFC_EVENT_OPEN: + RFCOMM_TRACE_ERROR ("Port error state %d event %d", p_port->rfc.state, event); + return; + + case RFC_EVENT_CLOSE: + rfc_port_timer_start (p_port, RFC_DISC_TIMEOUT); + rfc_send_disc (p_port->rfc.p_mcb, p_port->dlci); + p_port->rfc.expected_rsp = 0; + p_port->rfc.state = RFC_STATE_DISC_WAIT_UA; + return; + + case RFC_EVENT_CLEAR: + rfc_port_closed (p_port); + return; + + case RFC_EVENT_DATA: + /* Send credits in the frame. Pass them in the layer specific member of the hdr. */ + /* There might be an initial case when we reduced rx_max and credit_rx is still */ + /* bigger. Make sure that we do not send 255 */ + if ((p_port->rfc.p_mcb->flow == PORT_FC_CREDIT) + && (((BT_HDR *)p_data)->len < p_port->peer_mtu) + && (!p_port->rx.user_fc) + && (p_port->credit_rx_max > p_port->credit_rx)) + { + ((BT_HDR *)p_data)->layer_specific = (UINT8) (p_port->credit_rx_max - p_port->credit_rx); + p_port->credit_rx = p_port->credit_rx_max; + } + else + { + ((BT_HDR *)p_data)->layer_specific = 0; + } + rfc_send_buf_uih (p_port->rfc.p_mcb, p_port->dlci, (BT_HDR *)p_data); + rfc_dec_credit (p_port); + return; + + case RFC_EVENT_UA: + return; + + case RFC_EVENT_SABME: + rfc_send_ua (p_port->rfc.p_mcb, p_port->dlci); + return; + + case RFC_EVENT_DM: + PORT_DlcReleaseInd (p_port->rfc.p_mcb, p_port->dlci); + rfc_port_closed (p_port); + return; + + case RFC_EVENT_DISC: + p_port->rfc.state = RFC_STATE_CLOSED; + rfc_send_ua (p_port->rfc.p_mcb, p_port->dlci); + if(!GKI_queue_is_empty(&p_port->rx.queue)) + { + /* give a chance to upper stack to close port properly */ + RFCOMM_TRACE_DEBUG("port queue is not empty"); + rfc_port_timer_start (p_port, RFC_DISC_TIMEOUT); + } + else + PORT_DlcReleaseInd (p_port->rfc.p_mcb, p_port->dlci); + return; + + case RFC_EVENT_UIH: + rfc_port_uplink_data (p_port, (BT_HDR *)p_data); + return; + + case RFC_EVENT_TIMEOUT: + Port_TimeOutCloseMux( p_port->rfc.p_mcb ) ; + RFCOMM_TRACE_ERROR ("Port error state %d event %d", p_port->rfc.state, event); + return; + } + RFCOMM_TRACE_WARNING ("Port state opened Event ignored %d", event); +} + + +/******************************************************************************* +** +** Function rfc_port_sm_disc_wait_ua +** +** Description This function handles events when DISC on the DLC was +** sent and SM is waiting for UA or DM. +** +** Returns void +** +*******************************************************************************/ +void rfc_port_sm_disc_wait_ua (tPORT *p_port, UINT16 event, void *p_data) +{ + switch (event) + { + case RFC_EVENT_OPEN: + case RFC_EVENT_ESTABLISH_RSP: + RFCOMM_TRACE_ERROR ("Port error state %d event %d", p_port->rfc.state, event); + return; + + case RFC_EVENT_CLEAR: + rfc_port_closed (p_port); + return; + + case RFC_EVENT_DATA: + GKI_freebuf (p_data); + return; + + case RFC_EVENT_UA: + p_port->rfc.p_mcb->is_disc_initiator = TRUE; + /* Case falls through */ + + case RFC_EVENT_DM: + rfc_port_closed (p_port); + return; + + case RFC_EVENT_SABME: + rfc_send_dm (p_port->rfc.p_mcb, p_port->dlci, TRUE); + return; + + case RFC_EVENT_DISC: + rfc_send_dm (p_port->rfc.p_mcb, p_port->dlci, TRUE); + return; + + case RFC_EVENT_UIH: + GKI_freebuf (p_data); + rfc_send_dm (p_port->rfc.p_mcb, p_port->dlci, FALSE); + return; + + case RFC_EVENT_TIMEOUT: + rfc_port_closed (p_port); + return; + } + + RFCOMM_TRACE_WARNING ("Port state disc_wait_ua Event ignored %d", event); +} + + +/******************************************************************************* +** +** Function rfc_port_uplink_data +** +** Description This function handles uplink information data frame. +** +*******************************************************************************/ +void rfc_port_uplink_data (tPORT *p_port, BT_HDR *p_buf) +{ + PORT_DataInd (p_port->rfc.p_mcb, p_port->dlci, p_buf); +} + + +/******************************************************************************* +** +** Function rfc_process_pn +** +** Description This function handles DLC parameter negotiation frame. +** Record MTU and pass indication to the upper layer. +** +*******************************************************************************/ +void rfc_process_pn (tRFC_MCB *p_mcb, BOOLEAN is_command, MX_FRAME *p_frame) +{ + tPORT *p_port; + UINT8 dlci = p_frame->dlci; + + if (is_command) + { + /* Ignore if Multiplexer is being shut down */ + if (p_mcb->state != RFC_MX_STATE_DISC_WAIT_UA) + { + PORT_ParNegInd (p_mcb, dlci, p_frame->u.pn.mtu, + p_frame->u.pn.conv_layer, p_frame->u.pn.k); + } + else + { + rfc_send_dm(p_mcb, dlci, FALSE); + RFCOMM_TRACE_WARNING("***** MX PN while disconnecting *****"); + } + + return; + } + /* If we are not awaiting response just ignore it */ + p_port = port_find_mcb_dlci_port (p_mcb, dlci); + if ((p_port == NULL) || !(p_port->rfc.expected_rsp & RFC_RSP_PN)) + return; + + p_port->rfc.expected_rsp &= ~RFC_RSP_PN; + + rfc_port_timer_stop (p_port); + + PORT_ParNegCnf (p_mcb, dlci, p_frame->u.pn.mtu, + p_frame->u.pn.conv_layer, p_frame->u.pn.k); +} + + +/******************************************************************************* +** +** Function rfc_process_rpn +** +** Description This function handles Remote DLC parameter negotiation +** command/response. Pass command to the user. +** +*******************************************************************************/ +void rfc_process_rpn (tRFC_MCB *p_mcb, BOOLEAN is_command, + BOOLEAN is_request, MX_FRAME *p_frame) +{ + tPORT_STATE port_pars; + tPORT *p_port; + + if ((p_port = port_find_mcb_dlci_port (p_mcb, p_frame->dlci)) == NULL) + { + /* This is the first command on the port */ + if (is_command) + { + + memset(&port_pars, 0, sizeof(tPORT_STATE)); + rfc_set_port_state(&port_pars, p_frame); + + PORT_PortNegInd(p_mcb, p_frame->dlci, &port_pars, p_frame->u.rpn.param_mask); + } + return; + } + + if (is_command && is_request) + { + /* This is the special situation when peer just request local pars */ + port_pars = p_port->peer_port_pars; + rfc_send_rpn (p_mcb, p_frame->dlci, FALSE, &p_port->peer_port_pars, 0); + return; + } + + port_pars = p_port->peer_port_pars; + + rfc_set_port_state(&port_pars, p_frame); + + if (is_command) + { + PORT_PortNegInd (p_mcb, p_frame->dlci, &port_pars, p_frame->u.rpn.param_mask); + return; + } + + /* If we are not awaiting response just ignore it */ + p_port = port_find_mcb_dlci_port (p_mcb, p_frame->dlci); + if ((p_port == NULL) || !(p_port->rfc.expected_rsp & (RFC_RSP_RPN | RFC_RSP_RPN_REPLY))) + return; + + /* If we sent a request for port parameters to the peer he is replying with */ + /* mask 0. */ + rfc_port_timer_stop (p_port); + + if (p_port->rfc.expected_rsp & RFC_RSP_RPN_REPLY) + { + p_port->rfc.expected_rsp &= ~RFC_RSP_RPN_REPLY; + + p_port->peer_port_pars = port_pars; + + if ((port_pars.fc_type == (RFCOMM_FC_RTR_ON_INPUT | RFCOMM_FC_RTR_ON_OUTPUT)) + || (port_pars.fc_type == (RFCOMM_FC_RTC_ON_INPUT | RFCOMM_FC_RTC_ON_OUTPUT))) + { + /* This is satisfactory port parameters. Set mask as it was Ok */ + p_frame->u.rpn.param_mask = RFCOMM_RPN_PM_MASK; + } + else + { + /* Current peer parameters are not good, try to fix them */ + p_port->peer_port_pars.fc_type = (RFCOMM_FC_RTR_ON_INPUT | RFCOMM_FC_RTR_ON_OUTPUT); + + p_port->rfc.expected_rsp |= RFC_RSP_RPN; + rfc_send_rpn (p_mcb, p_frame->dlci, TRUE, &p_port->peer_port_pars, + RFCOMM_RPN_PM_RTR_ON_INPUT | RFCOMM_RPN_PM_RTR_ON_OUTPUT); + rfc_port_timer_start (p_port, RFC_T2_TIMEOUT) ; + return; + } + } + else + p_port->rfc.expected_rsp &= ~RFC_RSP_RPN; + + /* Check if all suggested parameters were accepted */ + if (((p_frame->u.rpn.param_mask & (RFCOMM_RPN_PM_RTR_ON_INPUT | RFCOMM_RPN_PM_RTR_ON_OUTPUT)) == + (RFCOMM_RPN_PM_RTR_ON_INPUT | RFCOMM_RPN_PM_RTR_ON_OUTPUT)) + || ((p_frame->u.rpn.param_mask & (RFCOMM_RPN_PM_RTC_ON_INPUT | RFCOMM_RPN_PM_RTC_ON_OUTPUT)) == + (RFCOMM_RPN_PM_RTC_ON_INPUT | RFCOMM_RPN_PM_RTC_ON_OUTPUT))) + { + PORT_PortNegCnf (p_mcb, p_port->dlci, &port_pars, RFCOMM_SUCCESS); + return; + } + + /* If we were proposing RTR flow control try RTC flow control */ + /* If we were proposing RTC flow control try no flow control */ + /* otherwise drop the connection */ + if (p_port->peer_port_pars.fc_type == (RFCOMM_FC_RTR_ON_INPUT | RFCOMM_FC_RTR_ON_OUTPUT)) + { + /* Current peer parameters are not good, try to fix them */ + p_port->peer_port_pars.fc_type = (RFCOMM_FC_RTC_ON_INPUT | RFCOMM_FC_RTC_ON_OUTPUT); + + p_port->rfc.expected_rsp |= RFC_RSP_RPN; + + rfc_send_rpn (p_mcb, p_frame->dlci, TRUE, &p_port->peer_port_pars, + RFCOMM_RPN_PM_RTC_ON_INPUT | RFCOMM_RPN_PM_RTC_ON_OUTPUT); + rfc_port_timer_start (p_port, RFC_T2_TIMEOUT) ; + return; + } + + /* Other side does not support flow control */ + if (p_port->peer_port_pars.fc_type == (RFCOMM_FC_RTC_ON_INPUT | RFCOMM_FC_RTC_ON_OUTPUT)) + { + p_port->peer_port_pars.fc_type = RFCOMM_FC_OFF; + PORT_PortNegCnf (p_mcb, p_port->dlci, &port_pars, RFCOMM_SUCCESS); + } +} + + +/******************************************************************************* +** +** Function rfc_process_msc +** +** Description This function handles Modem Status Command. +** Pass command to the user. +** +*******************************************************************************/ +void rfc_process_msc (tRFC_MCB *p_mcb, BOOLEAN is_command, MX_FRAME *p_frame) +{ + tPORT_CTRL pars; + tPORT *p_port; + UINT8 modem_signals = p_frame->u.msc.signals; + BOOLEAN new_peer_fc = FALSE; + + p_port = port_find_mcb_dlci_port (p_mcb, p_frame->dlci); + if (p_port == NULL) + return; + + pars.modem_signal = 0; + + if (modem_signals & RFCOMM_MSC_RTC) + pars.modem_signal |= MODEM_SIGNAL_DTRDSR; + + if (modem_signals & RFCOMM_MSC_RTR) + pars.modem_signal |= MODEM_SIGNAL_RTSCTS; + + if (modem_signals & RFCOMM_MSC_IC) + pars.modem_signal |= MODEM_SIGNAL_RI; + + if (modem_signals & RFCOMM_MSC_DV) + pars.modem_signal |= MODEM_SIGNAL_DCD; + + pars.fc = ((modem_signals & RFCOMM_MSC_FC) == RFCOMM_MSC_FC); + + pars.break_signal = (p_frame->u.msc.break_present) ? + p_frame->u.msc.break_duration : 0; + pars.discard_buffers = 0; + pars.break_signal_seq = RFCOMM_CTRL_BREAK_IN_SEQ; /* this is default */ + + /* Check if this command is passed only to indicate flow control */ + if (is_command) + { + rfc_send_msc (p_mcb, p_frame->dlci, FALSE, &pars); + + if (p_port->rfc.p_mcb->flow != PORT_FC_CREDIT) + { + /* Spec 1.1 indicates that only FC bit is used for flow control */ + p_port->peer_ctrl.fc = new_peer_fc = pars.fc; + + if (new_peer_fc != p_port->tx.peer_fc) + PORT_FlowInd (p_mcb, p_frame->dlci, (BOOLEAN)!new_peer_fc); + } + + PORT_ControlInd (p_mcb, p_frame->dlci, &pars); + + return; + } + + /* If we are not awaiting response just ignore it */ + if (!(p_port->rfc.expected_rsp & RFC_RSP_MSC)) + return; + + p_port->rfc.expected_rsp &= ~RFC_RSP_MSC; + + rfc_port_timer_stop (p_port); + + PORT_ControlCnf (p_port->rfc.p_mcb, p_port->dlci, &pars); +} + + +/******************************************************************************* +** +** Function rfc_process_rls +** +** Description This function handles Remote Line Status command. +** Pass command to the user. +** +*******************************************************************************/ +void rfc_process_rls (tRFC_MCB *p_mcb, BOOLEAN is_command, MX_FRAME *p_frame) +{ + tPORT *p_port; + + if (is_command) + { + PORT_LineStatusInd (p_mcb, p_frame->dlci, p_frame->u.rls.line_status); + rfc_send_rls (p_mcb, p_frame->dlci, FALSE, p_frame->u.rls.line_status); + } + else + { + p_port = port_find_mcb_dlci_port (p_mcb, p_frame->dlci); + + /* If we are not awaiting response just ignore it */ + if (!p_port || !(p_port->rfc.expected_rsp & RFC_RSP_RLS)) + return; + + p_port->rfc.expected_rsp &= ~RFC_RSP_RLS; + + rfc_port_timer_stop (p_port); + } +} + + +/******************************************************************************* +** +** Function rfc_process_nsc +** +** Description This function handles None Supported Command frame. +** +*******************************************************************************/ +void rfc_process_nsc (tRFC_MCB *p_mcb, MX_FRAME *p_frame) +{ + UNUSED(p_mcb); + UNUSED(p_frame); +} + + +/******************************************************************************* +** +** Function rfc_process_test +** +** Description This function handles Test frame. If this is a command +** reply to it. Otherwise pass response to the user. +** +*******************************************************************************/ +void rfc_process_test_rsp (tRFC_MCB *p_mcb, BT_HDR *p_buf) +{ + UNUSED(p_mcb); + + GKI_freebuf (p_buf); +} + + +/******************************************************************************* +** +** Function rfc_process_fcon +** +** Description This function handles FCON frame. The peer entity is able +** to receive new information +** +*******************************************************************************/ +void rfc_process_fcon (tRFC_MCB *p_mcb, BOOLEAN is_command) +{ + if (is_command) + { + rfc_cb.rfc.peer_rx_disabled = FALSE; + + rfc_send_fcon (p_mcb, FALSE); + + if (!p_mcb->l2cap_congested) + PORT_FlowInd (p_mcb, 0, TRUE); + } +} + +/******************************************************************************* +** +** Function rfc_process_fcoff +** +** Description This function handles FCOFF frame. The peer entity is unable +** to receive new information +** +*******************************************************************************/ +void rfc_process_fcoff (tRFC_MCB *p_mcb, BOOLEAN is_command) +{ + if (is_command) + { + rfc_cb.rfc.peer_rx_disabled = TRUE; + + if (!p_mcb->l2cap_congested) + PORT_FlowInd (p_mcb, 0, FALSE); + + rfc_send_fcoff (p_mcb, FALSE); + } +} + + +/******************************************************************************* +** +** Function rfc_process_l2cap_congestion +** +** Description This function handles L2CAP congestion messages +** +*******************************************************************************/ +void rfc_process_l2cap_congestion (tRFC_MCB *p_mcb, BOOLEAN is_congested) +{ + p_mcb->l2cap_congested = is_congested; + + if (!is_congested) + { + rfc_check_send_cmd(p_mcb, NULL); + } + + if (!rfc_cb.rfc.peer_rx_disabled) + { + if (!is_congested) + PORT_FlowInd (p_mcb, 0, TRUE); + else + PORT_FlowInd (p_mcb, 0, FALSE); + } +} + +/******************************************************************************* +** +** Function rfc_set_port_pars +** +** Description This function sets the tPORT_STATE structure given a p_frame. +** +*******************************************************************************/ + +void rfc_set_port_state(tPORT_STATE *port_pars, MX_FRAME *p_frame) +{ + if (p_frame->u.rpn.param_mask & RFCOMM_RPN_PM_BIT_RATE) + port_pars->baud_rate = p_frame->u.rpn.baud_rate; + if (p_frame->u.rpn.param_mask & RFCOMM_RPN_PM_DATA_BITS) + port_pars->byte_size = p_frame->u.rpn.byte_size; + if (p_frame->u.rpn.param_mask & RFCOMM_RPN_PM_STOP_BITS) + port_pars->stop_bits = p_frame->u.rpn.stop_bits; + if (p_frame->u.rpn.param_mask & RFCOMM_RPN_PM_PARITY) + port_pars->parity = p_frame->u.rpn.parity; + if (p_frame->u.rpn.param_mask & RFCOMM_RPN_PM_PARITY_TYPE) + port_pars->parity_type = p_frame->u.rpn.parity_type; + if (p_frame->u.rpn.param_mask & (RFCOMM_RPN_PM_XONXOFF_ON_INPUT | + RFCOMM_RPN_PM_XONXOFF_ON_OUTPUT | + RFCOMM_RPN_PM_RTR_ON_INPUT | + RFCOMM_RPN_PM_RTR_ON_OUTPUT | + RFCOMM_RPN_PM_RTC_ON_INPUT | + RFCOMM_RPN_PM_RTC_ON_OUTPUT)) + port_pars->fc_type = p_frame->u.rpn.fc_type; + if (p_frame->u.rpn.param_mask & RFCOMM_RPN_PM_XON_CHAR) + port_pars->xon_char = p_frame->u.rpn.xon_char; + if (p_frame->u.rpn.param_mask & RFCOMM_RPN_PM_XOFF_CHAR) + port_pars->xoff_char = p_frame->u.rpn.xoff_char; +} + diff --git a/components/bt/bluedroid/stack/rfcomm/rfc_port_if.c b/components/bt/bluedroid/stack/rfcomm/rfc_port_if.c new file mode 100755 index 0000000000..cdf9b12e91 --- /dev/null +++ b/components/bt/bluedroid/stack/rfcomm/rfc_port_if.c @@ -0,0 +1,376 @@ +/****************************************************************************** + * + * Copyright (C) 1999-2012 Broadcom Corporation + * + * 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 functions callable by an application + * running on top of RFCOMM + * + *****************************************************************************/ + +#include +#include "bt_target.h" +#include "gki.h" +#include "rfcdefs.h" +#include "port_api.h" +#include "l2c_api.h" +#include "port_int.h" +#include "rfc_int.h" +#include "bt_defs.h" + +#if RFC_DYNAMIC_MEMORY == FALSE +tRFC_CB rfc_cb; +#endif + +/******************************************************************************* +** +** Function RFCOMM_StartReq +** +** Description This function handles Start Request from the upper layer. +** If RFCOMM multiplexer channel can not be allocated +** send start not accepted confirmation. Otherwise dispatch +** start event to the state machine. +** +*******************************************************************************/ +void RFCOMM_StartReq (tRFC_MCB *p_mcb) +{ + rfc_mx_sm_execute (p_mcb, RFC_MX_EVENT_START_REQ, NULL); +} + + +/******************************************************************************* +** +** Function RFCOMM_StartRsp +** +** Description This function handles Start Response from the upper layer. +** Save upper layer handle and result of the Start Indication +** in the control block and dispatch event to the FSM. +** +*******************************************************************************/ +void RFCOMM_StartRsp (tRFC_MCB *p_mcb, UINT16 result) +{ + rfc_mx_sm_execute (p_mcb, RFC_MX_EVENT_START_RSP, &result); +} + + +/******************************************************************************* +** +** Function RFCOMM_DlcEstablishReq +** +** Description This function is called by the user app to establish +** connection with the specific dlci on a specific bd device. +** It will allocate RFCOMM connection control block if not +** allocated before and dispatch open event to the state +** machine. +** +*******************************************************************************/ +void RFCOMM_DlcEstablishReq (tRFC_MCB *p_mcb, UINT8 dlci, UINT16 mtu) +{ + UNUSED(mtu); + if (p_mcb->state != RFC_MX_STATE_CONNECTED) + { + PORT_DlcEstablishCnf (p_mcb, dlci, 0, RFCOMM_ERROR); + return; + } + + tPORT *p_port = port_find_mcb_dlci_port(p_mcb, dlci); + if (p_port == NULL) { + RFCOMM_TRACE_WARNING("%s Unable to find DLCI port dlci:%d", __func__, + dlci); + return; + } + + rfc_port_sm_execute(p_port, RFC_EVENT_OPEN, NULL); +} + + +/******************************************************************************* +** +** Function RFCOMM_DlcEstablishRsp +** +** Description This function is called by the port emulation entity +** acks Establish Indication. +** +*******************************************************************************/ +void RFCOMM_DlcEstablishRsp (tRFC_MCB *p_mcb, UINT8 dlci, UINT16 mtu, UINT16 result) +{ + UNUSED(mtu); + if ((p_mcb->state != RFC_MX_STATE_CONNECTED) && (result == RFCOMM_SUCCESS)) + { + PORT_DlcReleaseInd (p_mcb, dlci); + return; + } + + tPORT *p_port = port_find_mcb_dlci_port (p_mcb, dlci); + if (p_port == NULL) { + RFCOMM_TRACE_WARNING("%s Unable to find DLCI port dlci:%d", __func__, + dlci); + return; + } + rfc_port_sm_execute(p_port, RFC_EVENT_ESTABLISH_RSP, &result); +} + + +/******************************************************************************* +** +** Function RFCOMM_ParNegReq +** +** Description This function is called by the user app to start +** DLC parameter negotiation. Port emulation can send this +** request before actually establishing the DLC. In this +** case the function will allocate RFCOMM connection control +** block. +** +*******************************************************************************/ +void RFCOMM_ParNegReq (tRFC_MCB *p_mcb, UINT8 dlci, UINT16 mtu) +{ + UINT8 flow; + UINT8 cl; + UINT8 k; + + tPORT *p_port = port_find_mcb_dlci_port(p_mcb, dlci); + if (p_port == NULL) { + RFCOMM_TRACE_WARNING("%s Unable to find DLCI port dlci:%d", __func__, + dlci); + return; + } + + if (p_mcb->state != RFC_MX_STATE_CONNECTED) + { + p_port->error = PORT_PAR_NEG_FAILED; + return; + } + + /* Negotiate the flow control mechanism. If flow control mechanism for */ + /* mux has not been set yet, use our default value. If it has been set, */ + /* use that value. */ + flow = (p_mcb->flow == PORT_FC_UNDEFINED) ? PORT_FC_DEFAULT : p_mcb->flow; + + /* Set convergence layer and number of credits (k) */ + if (flow == PORT_FC_CREDIT) + { + cl = RFCOMM_PN_CONV_LAYER_CBFC_I; + k = (p_port->credit_rx_max < RFCOMM_K_MAX) ? p_port->credit_rx_max : RFCOMM_K_MAX; + p_port->credit_rx = k; + } + else + { + cl = RFCOMM_PN_CONV_LAYER_TYPE_1; + k = 0; + } + + /* Send Parameter Negotiation Command UIH frame */ + p_port->rfc.expected_rsp |= RFC_RSP_PN; + + rfc_send_pn (p_mcb, dlci, TRUE, mtu, cl, k); + + rfc_port_timer_start (p_port, RFC_T2_TIMEOUT) ; +} + + +/******************************************************************************* +** +** Function RFCOMM_ParNegRsp +** +** Description This function is called by the user app to acknowledge +** DLC parameter negotiation. +** +*******************************************************************************/ +void RFCOMM_ParNegRsp (tRFC_MCB *p_mcb, UINT8 dlci, UINT16 mtu, UINT8 cl, UINT8 k) +{ + if (p_mcb->state != RFC_MX_STATE_CONNECTED) + return; + + /* Send Parameter Negotiation Response UIH frame */ + rfc_send_pn (p_mcb, dlci, FALSE, mtu, cl, k); +} + + +/******************************************************************************* +** +** Function RFCOMM_PortNegReq +** +** Description This function is called by the user app to start +** Remote Port parameter negotiation. Port emulation can +** send this request before actually establishing the DLC. +** In this case the function will allocate RFCOMM connection +** control block. +** +*******************************************************************************/ +void RFCOMM_PortNegReq (tRFC_MCB *p_mcb, UINT8 dlci, tPORT_STATE *p_pars) +{ + if (p_mcb->state != RFC_MX_STATE_CONNECTED) + { + PORT_PortNegCnf (p_mcb, dlci, NULL, RFCOMM_ERROR); + return; + } + + tPORT *p_port = port_find_mcb_dlci_port(p_mcb, dlci); + if (p_port == NULL) { + RFCOMM_TRACE_WARNING("%s Unable to find DLCI port dlci:%d", __func__, + dlci); + return; + } + + /* Send Parameter Negotiation Command UIH frame */ + if (!p_pars) + p_port->rfc.expected_rsp |= RFC_RSP_RPN_REPLY; + else + p_port->rfc.expected_rsp |= RFC_RSP_RPN; + + rfc_send_rpn (p_mcb, dlci, TRUE, p_pars, RFCOMM_RPN_PM_MASK); + rfc_port_timer_start (p_port, RFC_T2_TIMEOUT) ; + +} + + +/******************************************************************************* +** +** Function RFCOMM_PortNegRsp +** +** Description This function is called by the user app to acknowledge +** Port parameters negotiation. +** +*******************************************************************************/ +void RFCOMM_PortNegRsp (tRFC_MCB *p_mcb, UINT8 dlci, tPORT_STATE *p_pars, + UINT16 param_mask) +{ + if (p_mcb->state != RFC_MX_STATE_CONNECTED) + return; + + rfc_send_rpn (p_mcb, dlci, FALSE, p_pars, param_mask); +} + + +/******************************************************************************* +** +** Function RFCOMM_ControlReq +** +** Description This function is called by the port entity to send control +** parameters to remote port emulation entity. +** +*******************************************************************************/ +void RFCOMM_ControlReq (tRFC_MCB *p_mcb, UINT8 dlci, tPORT_CTRL *p_pars) +{ + tPORT *p_port = port_find_mcb_dlci_port(p_mcb, dlci); + if (p_port == NULL) { + RFCOMM_TRACE_WARNING("%s Unable to find DLCI port dlci:%d", __func__, + dlci); + return; + } + + if ((p_port->state != PORT_STATE_OPENED) + || (p_port->rfc.state != RFC_STATE_OPENED)) + return; + + p_port->port_ctrl |= PORT_CTRL_REQ_SENT; + + p_port->rfc.expected_rsp |= RFC_RSP_MSC; + + rfc_send_msc (p_mcb, dlci, TRUE, p_pars); + rfc_port_timer_start (p_port, RFC_T2_TIMEOUT) ; + +} + + +/******************************************************************************* +** +** Function RFCOMM_FlowReq +** +** Description This function is called by the port entity when flow +** control state has changed. Enable flag passed shows if +** port can accept more data. +** +*******************************************************************************/ +void RFCOMM_FlowReq (tRFC_MCB *p_mcb, UINT8 dlci, UINT8 enable) +{ + tPORT *p_port = port_find_mcb_dlci_port(p_mcb, dlci); + if (p_port == NULL) { + RFCOMM_TRACE_WARNING("%s Unable to find DLCI port dlci:%d", __func__, + dlci); + return; + } + + if ((p_port->state != PORT_STATE_OPENED) + || (p_port->rfc.state != RFC_STATE_OPENED)) + return; + + p_port->local_ctrl.fc = !enable; + + p_port->rfc.expected_rsp |= RFC_RSP_MSC; + + rfc_send_msc (p_mcb, dlci, TRUE, &p_port->local_ctrl); + rfc_port_timer_start (p_port, RFC_T2_TIMEOUT) ; + +} + + +/******************************************************************************* +** +** Function RFCOMM_LineStatusReq +** +** Description This function is called by the port entity when line +** status should be delivered to the peer. +** +*******************************************************************************/ +void RFCOMM_LineStatusReq (tRFC_MCB *p_mcb, UINT8 dlci, UINT8 status) +{ + tPORT *p_port = port_find_mcb_dlci_port(p_mcb, dlci); + if (p_port == NULL) { + RFCOMM_TRACE_WARNING("%s Unable to find DLCI port dlci:%d", __func__, + dlci); + return; + } + + if ((p_port->state != PORT_STATE_OPENED) + || (p_port->rfc.state != RFC_STATE_OPENED)) + return; + + p_port->rfc.expected_rsp |= RFC_RSP_RLS; + + rfc_send_rls (p_mcb, dlci, TRUE, status); + rfc_port_timer_start (p_port, RFC_T2_TIMEOUT); +} + + +/******************************************************************************* +** +** Function RFCOMM_DlcReleaseReq +** +** Description This function is called by the PORT unit to close DLC +** +*******************************************************************************/ +void RFCOMM_DlcReleaseReq (tRFC_MCB *p_mcb, UINT8 dlci) +{ + rfc_port_sm_execute(port_find_mcb_dlci_port (p_mcb, dlci), RFC_EVENT_CLOSE, 0); +} + + +/******************************************************************************* +** +** Function RFCOMM_DataReq +** +** Description This function is called by the user app to send data buffer +** +*******************************************************************************/ +void RFCOMM_DataReq (tRFC_MCB *p_mcb, UINT8 dlci, BT_HDR *p_buf) +{ + rfc_port_sm_execute(port_find_mcb_dlci_port (p_mcb, dlci), RFC_EVENT_DATA, p_buf); +} + + diff --git a/components/bt/bluedroid/stack/rfcomm/rfc_ts_frames.c b/components/bt/bluedroid/stack/rfcomm/rfc_ts_frames.c new file mode 100755 index 0000000000..357df4f9f0 --- /dev/null +++ b/components/bt/bluedroid/stack/rfcomm/rfc_ts_frames.c @@ -0,0 +1,909 @@ +/****************************************************************************** + * + * Copyright (C) 1999-2012 Broadcom Corporation + * + * 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 functions to send TS 07.10 frames + * + ******************************************************************************/ + +#include +#include "bt_target.h" +#include "gki.h" +#include "rfcdefs.h" +#include "port_api.h" +#include "l2c_api.h" +#include "port_int.h" +#include "rfc_int.h" + +/******************************************************************************* +** +** Function rfc_send_sabme +** +** Description This function sends SABME frame. +** +*******************************************************************************/ +void rfc_send_sabme (tRFC_MCB *p_mcb, UINT8 dlci) +{ + BT_HDR *p_buf; + UINT8 *p_data; + UINT8 cr = RFCOMM_CR(p_mcb->is_initiator, TRUE); + + if ((p_buf = (BT_HDR *)GKI_getpoolbuf (RFCOMM_CMD_POOL_ID)) == NULL) + return; + + p_buf->offset = L2CAP_MIN_OFFSET; + p_data = (UINT8 *)(p_buf + 1) + L2CAP_MIN_OFFSET; + + /* SABME frame, command, PF = 1, dlci */ + *p_data++ = RFCOMM_EA | cr | (dlci << RFCOMM_SHIFT_DLCI); + *p_data++ = RFCOMM_SABME | RFCOMM_PF; + *p_data++ = RFCOMM_EA | 0; + + *p_data = RFCOMM_SABME_FCS ((UINT8 *)(p_buf + 1) + L2CAP_MIN_OFFSET, cr, dlci); + + p_buf->len = 4; + + rfc_check_send_cmd(p_mcb, p_buf); +} + + +/******************************************************************************* +** +** Function rfc_send_ua +** +** Description This function sends UA frame. +** +*******************************************************************************/ +void rfc_send_ua (tRFC_MCB *p_mcb, UINT8 dlci) +{ + BT_HDR *p_buf; + UINT8 *p_data; + UINT8 cr = RFCOMM_CR(p_mcb->is_initiator, FALSE); + + if ((p_buf = (BT_HDR *)GKI_getpoolbuf (RFCOMM_CMD_POOL_ID)) == NULL) + return; + + p_buf->offset = L2CAP_MIN_OFFSET; + p_data = (UINT8 *)(p_buf + 1) + L2CAP_MIN_OFFSET; + + /* ua frame, response, PF = 1, dlci */ + *p_data++ = RFCOMM_EA | cr | (dlci << RFCOMM_SHIFT_DLCI); + *p_data++ = RFCOMM_UA | RFCOMM_PF; + *p_data++ = RFCOMM_EA | 0; + + *p_data = RFCOMM_UA_FCS ((UINT8 *)(p_buf + 1) + L2CAP_MIN_OFFSET, cr, dlci); + + p_buf->len = 4; + + rfc_check_send_cmd(p_mcb, p_buf); +} + + +/******************************************************************************* +** +** Function rfc_send_dm +** +** Description This function sends DM frame. +** +*******************************************************************************/ +void rfc_send_dm (tRFC_MCB *p_mcb, UINT8 dlci, BOOLEAN pf) +{ + BT_HDR *p_buf; + UINT8 *p_data; + UINT8 cr = RFCOMM_CR(p_mcb->is_initiator, FALSE); + + if ((p_buf = (BT_HDR *)GKI_getpoolbuf (RFCOMM_CMD_POOL_ID)) == NULL) + return; + + p_buf->offset = L2CAP_MIN_OFFSET; + p_data = (UINT8 *)(p_buf + 1) + L2CAP_MIN_OFFSET; + + /* DM frame, response, PF = 1, dlci */ + *p_data++ = RFCOMM_EA | cr | (dlci << RFCOMM_SHIFT_DLCI); + *p_data++ = RFCOMM_DM | ((pf) ? RFCOMM_PF : 0); + *p_data++ = RFCOMM_EA | 0; + + *p_data = RFCOMM_DM_FCS ((UINT8 *)(p_buf + 1) + L2CAP_MIN_OFFSET, cr, dlci); + + p_buf->len = 4; + + rfc_check_send_cmd(p_mcb, p_buf); +} + + +/******************************************************************************* +** +** Function rfc_send_disc +** +** Description This function sends DISC frame. +** +*******************************************************************************/ +void rfc_send_disc (tRFC_MCB *p_mcb, UINT8 dlci) +{ + BT_HDR *p_buf; + UINT8 *p_data; + UINT8 cr = RFCOMM_CR(p_mcb->is_initiator, TRUE); + + if ((p_buf = (BT_HDR *)GKI_getpoolbuf (RFCOMM_CMD_POOL_ID)) == NULL) + return; + + p_buf->offset = L2CAP_MIN_OFFSET; + p_data = (UINT8 *)(p_buf + 1) + L2CAP_MIN_OFFSET; + + /* DISC frame, command, PF = 1, dlci */ + *p_data++ = RFCOMM_EA | cr | (dlci << RFCOMM_SHIFT_DLCI); + *p_data++ = RFCOMM_DISC | RFCOMM_PF; + *p_data++ = RFCOMM_EA | 0; + + *p_data = RFCOMM_DISC_FCS ((UINT8 *)(p_buf + 1) + L2CAP_MIN_OFFSET, cr, dlci); + + p_buf->len = 4; + + rfc_check_send_cmd(p_mcb, p_buf); +} + + +/******************************************************************************* +** +** Function rfc_send_buf_uih +** +** Description This function sends UIH frame. +** +*******************************************************************************/ +void rfc_send_buf_uih (tRFC_MCB *p_mcb, UINT8 dlci, BT_HDR *p_buf) +{ + UINT8 *p_data; + UINT8 cr = RFCOMM_CR(p_mcb->is_initiator, TRUE); + UINT8 credits; + + p_buf->offset -= RFCOMM_CTRL_FRAME_LEN; + if (p_buf->len > 127) + p_buf->offset--; + + if (dlci) + credits = (UINT8)p_buf->layer_specific; + else + credits = 0; + + if (credits) + p_buf->offset--; + + p_data = (UINT8 *)(p_buf + 1) + p_buf->offset; + + /* UIH frame, command, PF = 0, dlci */ + *p_data++ = RFCOMM_EA | cr | (dlci << RFCOMM_SHIFT_DLCI); + *p_data++ = RFCOMM_UIH | ((credits) ? RFCOMM_PF : 0); + if (p_buf->len <= 127) + { + *p_data++ = RFCOMM_EA | (p_buf->len << 1); + p_buf->len += 3; + } + else + { + *p_data++ = (p_buf->len & 0x7f) << 1; + *p_data++ = p_buf->len >> RFCOMM_SHIFT_LENGTH2; + p_buf->len += 4; + } + + if (credits) + { + *p_data++ = credits; + p_buf->len++; + } + + p_data = (UINT8 *)(p_buf + 1) + p_buf->offset + p_buf->len++; + + *p_data = RFCOMM_UIH_FCS ((UINT8 *)(p_buf + 1) + p_buf->offset, dlci); + + if (dlci == RFCOMM_MX_DLCI) + { + rfc_check_send_cmd(p_mcb, p_buf); + } + else + { + L2CA_DataWrite (p_mcb->lcid, p_buf); + } +} + + +/******************************************************************************* +** +** Function rfc_send_pn +** +** Description This function sends DLC Parameters Negotiation Frame. +** +*******************************************************************************/ +void rfc_send_pn (tRFC_MCB *p_mcb, UINT8 dlci, BOOLEAN is_command, UINT16 mtu, UINT8 cl, UINT8 k) +{ + BT_HDR *p_buf; + UINT8 *p_data; + + if ((p_buf = (BT_HDR *)GKI_getpoolbuf (RFCOMM_CMD_POOL_ID)) == NULL) + return; + + p_buf->offset = L2CAP_MIN_OFFSET + RFCOMM_CTRL_FRAME_LEN; + p_data = (UINT8 *)(p_buf + 1) + p_buf->offset; + + *p_data++ = RFCOMM_EA | RFCOMM_I_CR(is_command) | RFCOMM_MX_PN; + *p_data++ = RFCOMM_EA | (RFCOMM_MX_PN_LEN << 1); + + *p_data++ = dlci; + *p_data++ = RFCOMM_PN_FRAM_TYPE_UIH | cl; + + /* It appeared that we need to reply with the same priority bits as we received. + ** We will use the fact that we reply in the same context so rx_frame can still be used. + */ + if (is_command) + *p_data++ = RFCOMM_PN_PRIORITY_0; + else + *p_data++ = rfc_cb.rfc.rx_frame.u.pn.priority; + + *p_data++ = RFCOMM_T1_DSEC; + *p_data++ = mtu & 0xFF; + *p_data++ = mtu >> 8; + *p_data++ = RFCOMM_N2; + *p_data = k; + + /* Total length is sizeof PN data + mx header 2 */ + p_buf->len = RFCOMM_MX_PN_LEN + 2; + + rfc_send_buf_uih (p_mcb, RFCOMM_MX_DLCI, p_buf); +} + + +/******************************************************************************* +** +** Function rfc_send_fcon +** +** Description This function sends Flow Control On Command. +** +*******************************************************************************/ +void rfc_send_fcon (tRFC_MCB *p_mcb, BOOLEAN is_command) +{ + BT_HDR *p_buf; + UINT8 *p_data; + + if ((p_buf = (BT_HDR *)GKI_getpoolbuf (RFCOMM_CMD_POOL_ID)) == NULL) + return; + + p_buf->offset = L2CAP_MIN_OFFSET + RFCOMM_CTRL_FRAME_LEN; + p_data = (UINT8 *)(p_buf + 1) + p_buf->offset; + + *p_data++ = RFCOMM_EA | RFCOMM_I_CR(is_command) | RFCOMM_MX_FCON; + *p_data++ = RFCOMM_EA | (RFCOMM_MX_FCON_LEN << 1); + + /* Total length is sizeof FCON data + mx header 2 */ + p_buf->len = RFCOMM_MX_FCON_LEN + 2; + + rfc_send_buf_uih (p_mcb, RFCOMM_MX_DLCI, p_buf); +} + + +/******************************************************************************* +** +** Function rfc_send_fcoff +** +** Description This function sends Flow Control Off Command. +** +*******************************************************************************/ +void rfc_send_fcoff (tRFC_MCB *p_mcb, BOOLEAN is_command) +{ + BT_HDR *p_buf; + UINT8 *p_data; + + if ((p_buf = (BT_HDR *)GKI_getpoolbuf (RFCOMM_CMD_POOL_ID)) == NULL) + return; + + p_buf->offset = L2CAP_MIN_OFFSET + RFCOMM_CTRL_FRAME_LEN; + p_data = (UINT8 *)(p_buf + 1) + p_buf->offset; + + *p_data++ = RFCOMM_EA | RFCOMM_I_CR(is_command) | RFCOMM_MX_FCOFF; + *p_data++ = RFCOMM_EA | (RFCOMM_MX_FCOFF_LEN << 1); + + /* Total length is sizeof FCOFF data + mx header 2 */ + p_buf->len = RFCOMM_MX_FCOFF_LEN + 2; + + rfc_send_buf_uih (p_mcb, RFCOMM_MX_DLCI, p_buf); +} + + +/******************************************************************************* +** +** Function rfc_send_msc +** +** Description This function sends Modem Status Command Frame. +** +*******************************************************************************/ +void rfc_send_msc (tRFC_MCB *p_mcb, UINT8 dlci, BOOLEAN is_command, + tPORT_CTRL *p_pars) +{ + BT_HDR *p_buf; + UINT8 *p_data; + UINT8 signals; + UINT8 break_duration; + UINT8 len; + + signals = p_pars->modem_signal; + break_duration = p_pars->break_signal; + + if ((p_buf = (BT_HDR *)GKI_getpoolbuf (RFCOMM_CMD_POOL_ID)) == NULL) + return; + + p_buf->offset = L2CAP_MIN_OFFSET + RFCOMM_CTRL_FRAME_LEN; + p_data = (UINT8 *)(p_buf + 1) + p_buf->offset; + + if (break_duration) + len = RFCOMM_MX_MSC_LEN_WITH_BREAK; + else + len = RFCOMM_MX_MSC_LEN_NO_BREAK; + + *p_data++ = RFCOMM_EA | RFCOMM_I_CR(is_command) | RFCOMM_MX_MSC; + *p_data++ = RFCOMM_EA | (len << 1); + + *p_data++ = RFCOMM_EA | RFCOMM_CR_MASK | (dlci << RFCOMM_SHIFT_DLCI); + *p_data++ = RFCOMM_EA | + ((p_pars->fc) ? RFCOMM_MSC_FC : 0) | + ((signals & MODEM_SIGNAL_DTRDSR) ? RFCOMM_MSC_RTC : 0) | + ((signals & MODEM_SIGNAL_RTSCTS) ? RFCOMM_MSC_RTR : 0) | + ((signals & MODEM_SIGNAL_RI) ? RFCOMM_MSC_IC : 0) | + ((signals & MODEM_SIGNAL_DCD) ? RFCOMM_MSC_DV : 0); + + if (break_duration) + { + *p_data++ = RFCOMM_EA | RFCOMM_MSC_BREAK_PRESENT_MASK | + (break_duration << RFCOMM_MSC_SHIFT_BREAK); + } + + /* Total length is sizeof MSC data + mx header 2 */ + p_buf->len = len + 2; + + rfc_send_buf_uih (p_mcb, RFCOMM_MX_DLCI, p_buf); +} + + +/******************************************************************************* +** +** Function rfc_send_rls +** +** Description This function sends Remote Line Status Command Frame. +** +*******************************************************************************/ +void rfc_send_rls (tRFC_MCB *p_mcb, UINT8 dlci, BOOLEAN is_command, UINT8 status) +{ + BT_HDR *p_buf; + UINT8 *p_data; + + if ((p_buf = (BT_HDR *)GKI_getpoolbuf (RFCOMM_CMD_POOL_ID)) == NULL) + return; + + p_buf->offset = L2CAP_MIN_OFFSET + RFCOMM_CTRL_FRAME_LEN; + p_data = (UINT8 *)(p_buf + 1) + p_buf->offset; + + *p_data++ = RFCOMM_EA | RFCOMM_I_CR(is_command) | RFCOMM_MX_RLS; + *p_data++ = RFCOMM_EA | (RFCOMM_MX_RLS_LEN << 1); + + *p_data++ = RFCOMM_EA | RFCOMM_CR_MASK | (dlci << RFCOMM_SHIFT_DLCI); + *p_data++ = RFCOMM_RLS_ERROR | status; + + /* Total length is sizeof RLS data + mx header 2 */ + p_buf->len = RFCOMM_MX_RLS_LEN + 2; + + rfc_send_buf_uih (p_mcb, RFCOMM_MX_DLCI, p_buf); +} + + +/******************************************************************************* +** +** Function rfc_send_nsc +** +** Description This function sends Non Supported Command Response. +** +*******************************************************************************/ +void rfc_send_nsc (tRFC_MCB *p_mcb) +{ + BT_HDR *p_buf; + UINT8 *p_data; + + if ((p_buf = (BT_HDR *)GKI_getpoolbuf (RFCOMM_CMD_POOL_ID)) == NULL) + return; + + p_buf->offset = L2CAP_MIN_OFFSET + RFCOMM_CTRL_FRAME_LEN; + p_data = (UINT8 *)(p_buf + 1) + p_buf->offset; + + *p_data++ = RFCOMM_EA | RFCOMM_I_CR(FALSE) | RFCOMM_MX_NSC; + *p_data++ = RFCOMM_EA | (RFCOMM_MX_NSC_LEN << 1); + + *p_data++ = rfc_cb.rfc.rx_frame.ea | + (rfc_cb.rfc.rx_frame.cr << RFCOMM_SHIFT_CR) | + rfc_cb.rfc.rx_frame.type; + + /* Total length is sizeof NSC data + mx header 2 */ + p_buf->len = RFCOMM_MX_NSC_LEN + 2; + + rfc_send_buf_uih (p_mcb, RFCOMM_MX_DLCI, p_buf); +} + + +/******************************************************************************* +** +** Function rfc_send_rpn +** +** Description This function sends Remote Port Negotiation Command +** +*******************************************************************************/ +void rfc_send_rpn (tRFC_MCB *p_mcb, UINT8 dlci, BOOLEAN is_command, + tPORT_STATE *p_pars, UINT16 mask) +{ + BT_HDR *p_buf; + UINT8 *p_data; + + if ((p_buf = (BT_HDR *)GKI_getpoolbuf (RFCOMM_CMD_POOL_ID)) == NULL) + return; + + p_buf->offset = L2CAP_MIN_OFFSET + RFCOMM_CTRL_FRAME_LEN; + p_data = (UINT8 *)(p_buf + 1) + p_buf->offset; + + *p_data++ = RFCOMM_EA | RFCOMM_I_CR(is_command) | RFCOMM_MX_RPN; + + if (!p_pars) + { + *p_data++ = RFCOMM_EA | (RFCOMM_MX_RPN_REQ_LEN << 1); + + *p_data++ = RFCOMM_EA | RFCOMM_CR_MASK | (dlci << RFCOMM_SHIFT_DLCI); + + p_buf->len = RFCOMM_MX_RPN_REQ_LEN + 2; + } + else + { + *p_data++ = RFCOMM_EA | (RFCOMM_MX_RPN_LEN << 1); + + *p_data++ = RFCOMM_EA | RFCOMM_CR_MASK | (dlci << RFCOMM_SHIFT_DLCI); + *p_data++ = p_pars->baud_rate; + *p_data++ = (p_pars->byte_size << RFCOMM_RPN_BITS_SHIFT) + | (p_pars->stop_bits << RFCOMM_RPN_STOP_BITS_SHIFT) + | (p_pars->parity << RFCOMM_RPN_PARITY_SHIFT) + | (p_pars->parity_type << RFCOMM_RPN_PARITY_TYPE_SHIFT); + *p_data++ = p_pars->fc_type; + *p_data++ = p_pars->xon_char; + *p_data++ = p_pars->xoff_char; + *p_data++ = (mask & 0xFF); + *p_data++ = (mask >> 8); + + /* Total length is sizeof RPN data + mx header 2 */ + p_buf->len = RFCOMM_MX_RPN_LEN + 2; + } + + rfc_send_buf_uih (p_mcb, RFCOMM_MX_DLCI, p_buf); +} + + +/******************************************************************************* +** +** Function rfc_send_test +** +** Description This function sends Test frame. +** +*******************************************************************************/ +void rfc_send_test (tRFC_MCB *p_mcb, BOOLEAN is_command, BT_HDR *p_buf) +{ + UINT8 *p_data; + UINT16 xx; + UINT8 *p_src, *p_dest; + + /* Shift buffer to give space for header */ + if (p_buf->offset < (L2CAP_MIN_OFFSET + RFCOMM_MIN_OFFSET + 2)) + { + p_src = (UINT8 *) (p_buf + 1) + p_buf->offset + p_buf->len - 1; + p_dest = (UINT8 *) (p_buf + 1) + L2CAP_MIN_OFFSET + RFCOMM_MIN_OFFSET + 2 + p_buf->len - 1; + + for (xx = 0; xx < p_buf->len; xx++) + *p_dest-- = *p_src--; + + p_buf->offset = L2CAP_MIN_OFFSET + RFCOMM_MIN_OFFSET + 2; + } + + /* Adjust offset by number of bytes we are going to fill */ + p_buf->offset -= 2; + p_data = (UINT8 *)(p_buf + 1) + p_buf->offset; + + *p_data++ = RFCOMM_EA | RFCOMM_I_CR(is_command) | RFCOMM_MX_TEST; + *p_data++ = RFCOMM_EA | (p_buf->len << 1); + + p_buf->len += 2; + + rfc_send_buf_uih (p_mcb, RFCOMM_MX_DLCI, p_buf); +} + +/******************************************************************************* +** +** Function rfc_send_credit +** +** Description This function sends a flow control credit in UIH frame. +** +*******************************************************************************/ +void rfc_send_credit(tRFC_MCB *p_mcb, UINT8 dlci, UINT8 credit) +{ + BT_HDR *p_buf; + UINT8 *p_data; + UINT8 cr = RFCOMM_CR(p_mcb->is_initiator, TRUE); + + if ((p_buf = (BT_HDR *)GKI_getpoolbuf (RFCOMM_CMD_POOL_ID)) == NULL) + return; + + p_buf->offset = L2CAP_MIN_OFFSET; + p_data = (UINT8 *)(p_buf + 1) + p_buf->offset; + + *p_data++ = RFCOMM_EA | cr | (dlci << RFCOMM_SHIFT_DLCI); + *p_data++ = RFCOMM_UIH | RFCOMM_PF; + *p_data++ = RFCOMM_EA | 0; + *p_data++ = credit; + *p_data = RFCOMM_UIH_FCS ((UINT8 *)(p_buf + 1) + p_buf->offset, dlci); + + p_buf->len = 5; + + rfc_check_send_cmd(p_mcb, p_buf); +} + + +/******************************************************************************* +** +** Function rfc_parse_data +** +** Description This function processes data packet received from L2CAP +** +*******************************************************************************/ +UINT8 rfc_parse_data (tRFC_MCB *p_mcb, MX_FRAME *p_frame, BT_HDR *p_buf) +{ + UINT8 ead, eal, fcs; + UINT8 *p_data = (UINT8 *)(p_buf + 1) + p_buf->offset; + UINT8 *p_start = p_data; + UINT16 len; + + if (p_buf->len < RFCOMM_CTRL_FRAME_LEN) + { + RFCOMM_TRACE_ERROR ("Bad Length1: %d", p_buf->len); + return (RFC_EVENT_BAD_FRAME); + } + + RFCOMM_PARSE_CTRL_FIELD (ead, p_frame->cr, p_frame->dlci, p_data); + if( !ead ) + { + RFCOMM_TRACE_ERROR ("Bad Address(EA must be 1)"); + return (RFC_EVENT_BAD_FRAME); + } + RFCOMM_PARSE_TYPE_FIELD (p_frame->type, p_frame->pf, p_data); + RFCOMM_PARSE_LEN_FIELD (eal, len, p_data); + + p_buf->len -= (3 + !ead + !eal + 1); /* Additional 1 for FCS */ + p_buf->offset += (3 + !ead + !eal); + + /* handle credit if credit based flow control */ + if ((p_mcb->flow == PORT_FC_CREDIT) && (p_frame->type == RFCOMM_UIH) && + (p_frame->dlci != RFCOMM_MX_DLCI) && (p_frame->pf == 1)) + { + p_frame->credit = *p_data++; + p_buf->len--; + p_buf->offset++; + } + else + p_frame->credit = 0; + + if (p_buf->len != len) + { + RFCOMM_TRACE_ERROR ("Bad Length2 %d %d", p_buf->len, len); + return (RFC_EVENT_BAD_FRAME); + } + + fcs = *(p_data + len); + + /* All control frames that we are sending are sent with P=1, expect */ + /* reply with F=1 */ + /* According to TS 07.10 spec ivalid frames are discarded without */ + /* notification to the sender */ + switch (p_frame->type) + { + case RFCOMM_SABME: + if (RFCOMM_FRAME_IS_RSP(p_mcb->is_initiator, p_frame->cr) + || !p_frame->pf || len || !RFCOMM_VALID_DLCI (p_frame->dlci) + || !rfc_check_fcs (RFCOMM_CTRL_FRAME_LEN, p_start, fcs)) + { + RFCOMM_TRACE_ERROR ("Bad SABME"); + return (RFC_EVENT_BAD_FRAME); + } + else + return (RFC_EVENT_SABME); + + case RFCOMM_UA: + if (RFCOMM_FRAME_IS_CMD(p_mcb->is_initiator, p_frame->cr) + || !p_frame->pf || len || !RFCOMM_VALID_DLCI (p_frame->dlci) + || !rfc_check_fcs (RFCOMM_CTRL_FRAME_LEN, p_start, fcs)) + { + RFCOMM_TRACE_ERROR ("Bad UA"); + return (RFC_EVENT_BAD_FRAME); + } + else + return (RFC_EVENT_UA); + + case RFCOMM_DM: + if (RFCOMM_FRAME_IS_CMD(p_mcb->is_initiator, p_frame->cr) + || len || !RFCOMM_VALID_DLCI(p_frame->dlci) + || !rfc_check_fcs (RFCOMM_CTRL_FRAME_LEN, p_start, fcs)) + { + RFCOMM_TRACE_ERROR ("Bad DM"); + return (RFC_EVENT_BAD_FRAME); + } + else + return (RFC_EVENT_DM); + + case RFCOMM_DISC: + if (RFCOMM_FRAME_IS_RSP(p_mcb->is_initiator, p_frame->cr) + || !p_frame->pf || len || !RFCOMM_VALID_DLCI(p_frame->dlci) + || !rfc_check_fcs (RFCOMM_CTRL_FRAME_LEN, p_start, fcs)) + { + RFCOMM_TRACE_ERROR ("Bad DISC"); + return (RFC_EVENT_BAD_FRAME); + } + else + return (RFC_EVENT_DISC); + + case RFCOMM_UIH: + if (!RFCOMM_VALID_DLCI(p_frame->dlci)) + { + RFCOMM_TRACE_ERROR ("Bad UIH - invalid DLCI"); + return (RFC_EVENT_BAD_FRAME); + } + else if (!rfc_check_fcs (2, p_start, fcs)) + { + RFCOMM_TRACE_ERROR ("Bad UIH - FCS"); + return (RFC_EVENT_BAD_FRAME); + } + else if (RFCOMM_FRAME_IS_RSP(p_mcb->is_initiator, p_frame->cr)) + { + /* we assume that this is ok to allow bad implementations to work */ + RFCOMM_TRACE_ERROR ("Bad UIH - response"); + return (RFC_EVENT_UIH); + } + else + return (RFC_EVENT_UIH); + } + + return (RFC_EVENT_BAD_FRAME); +} + + +/******************************************************************************* +** +** Function rfc_process_mx_message +** +** Description This function processes UIH frames received on the +** multiplexer control channel. +** +*******************************************************************************/ +void rfc_process_mx_message (tRFC_MCB *p_mcb, BT_HDR *p_buf) +{ + UINT8 *p_data = (UINT8 *)(p_buf + 1) + p_buf->offset; + MX_FRAME *p_rx_frame = &rfc_cb.rfc.rx_frame; + UINT16 length = p_buf->len; + UINT8 ea, cr, mx_len; + BOOLEAN is_command; + + p_rx_frame->ea = *p_data & RFCOMM_EA; + p_rx_frame->cr = (*p_data & RFCOMM_CR_MASK) >> RFCOMM_SHIFT_CR; + p_rx_frame->type = *p_data++ & ~(RFCOMM_CR_MASK | RFCOMM_EA_MASK); + + if (!p_rx_frame->ea || !length) + { + RFCOMM_TRACE_ERROR ("Illegal MX Frame ea:%d len:%d", p_rx_frame->ea, length); + GKI_freebuf (p_buf); + return; + } + + length--; + + is_command = p_rx_frame->cr; + + ea = *p_data & RFCOMM_EA; + + mx_len = *p_data++ >> RFCOMM_SHIFT_LENGTH1; + length--; + + if (!ea) + { + mx_len += *p_data++ << RFCOMM_SHIFT_LENGTH2; + length --; + } + + if (mx_len != length) + { + RFCOMM_TRACE_ERROR ("Bad MX frame"); + GKI_freebuf (p_buf); + return; + } + + switch (p_rx_frame->type) + { + case RFCOMM_MX_PN: + if (length != RFCOMM_MX_PN_LEN) + break; + + p_rx_frame->dlci = *p_data++ & RFCOMM_PN_DLCI_MASK; + p_rx_frame->u.pn.frame_type = *p_data & RFCOMM_PN_FRAME_TYPE_MASK; + p_rx_frame->u.pn.conv_layer = *p_data++ & RFCOMM_PN_CONV_LAYER_MASK; + p_rx_frame->u.pn.priority = *p_data++ & RFCOMM_PN_PRIORITY_MASK; + p_rx_frame->u.pn.t1 = *p_data++; + p_rx_frame->u.pn.mtu = *p_data + (*(p_data + 1) << 8); + p_data += 2; + p_rx_frame->u.pn.n2 = *p_data++; + p_rx_frame->u.pn.k = *p_data++ & RFCOMM_PN_K_MASK; + + if (!p_rx_frame->dlci + || !RFCOMM_VALID_DLCI (p_rx_frame->dlci) + || (p_rx_frame->u.pn.mtu < RFCOMM_MIN_MTU) + || (p_rx_frame->u.pn.mtu > RFCOMM_MAX_MTU)) + { + RFCOMM_TRACE_ERROR ("Bad PN frame"); + break; + } + + GKI_freebuf (p_buf); + + rfc_process_pn (p_mcb, is_command, p_rx_frame); + return; + + case RFCOMM_MX_TEST: + if (!length) + break; + + p_rx_frame->u.test.p_data = p_data; + p_rx_frame->u.test.data_len = length; + + p_buf->offset += 2; + p_buf->len -= 2; + + if (is_command) + rfc_send_test (p_mcb, FALSE, p_buf); + else + rfc_process_test_rsp (p_mcb, p_buf); + return; + + case RFCOMM_MX_FCON: + if (length != RFCOMM_MX_FCON_LEN) + break; + + GKI_freebuf (p_buf); + + rfc_process_fcon (p_mcb, is_command); + return; + + case RFCOMM_MX_FCOFF: + if (length != RFCOMM_MX_FCOFF_LEN) + break; + + GKI_freebuf (p_buf); + + rfc_process_fcoff (p_mcb, is_command); + return; + + case RFCOMM_MX_MSC: + + ea = *p_data & RFCOMM_EA; + cr = (*p_data & RFCOMM_CR_MASK) >> RFCOMM_SHIFT_CR; + p_rx_frame->dlci = *p_data++ >> RFCOMM_SHIFT_DLCI; + + if (!ea || !cr || !p_rx_frame->dlci + || !RFCOMM_VALID_DLCI (p_rx_frame->dlci)) + { + RFCOMM_TRACE_ERROR ("Bad MSC frame"); + break; + } + + p_rx_frame->u.msc.signals = *p_data++; + + if (mx_len == RFCOMM_MX_MSC_LEN_WITH_BREAK) + { + p_rx_frame->u.msc.break_present = *p_data & RFCOMM_MSC_BREAK_PRESENT_MASK; + p_rx_frame->u.msc.break_duration = (*p_data & RFCOMM_MSC_BREAK_MASK) >> RFCOMM_MSC_SHIFT_BREAK; + } + else + { + p_rx_frame->u.msc.break_present = FALSE; + p_rx_frame->u.msc.break_duration = 0; + } + GKI_freebuf (p_buf); + + rfc_process_msc (p_mcb, is_command, p_rx_frame); + return; + + case RFCOMM_MX_NSC: + if ((length != RFCOMM_MX_NSC_LEN) || !is_command) + break; + + p_rx_frame->u.nsc.ea = *p_data & RFCOMM_EA; + p_rx_frame->u.nsc.cr = (*p_data & RFCOMM_CR_MASK) >> RFCOMM_SHIFT_CR; + p_rx_frame->u.nsc.type = *p_data++ >> RFCOMM_SHIFT_DLCI; + + GKI_freebuf (p_buf); + + rfc_process_nsc (p_mcb, p_rx_frame); + return; + + case RFCOMM_MX_RPN: + if ((length != RFCOMM_MX_RPN_REQ_LEN) && (length != RFCOMM_MX_RPN_LEN)) + break; + + ea = *p_data & RFCOMM_EA; + cr = (*p_data & RFCOMM_CR_MASK) >> RFCOMM_SHIFT_CR; + p_rx_frame->dlci = *p_data++ >> RFCOMM_SHIFT_DLCI; + + if (!ea || !cr || !p_rx_frame->dlci + || !RFCOMM_VALID_DLCI (p_rx_frame->dlci)) + { + RFCOMM_TRACE_ERROR ("Bad RPN frame"); + break; + } + + p_rx_frame->u.rpn.is_request = (length == RFCOMM_MX_RPN_REQ_LEN); + + if (!p_rx_frame->u.rpn.is_request) + { + p_rx_frame->u.rpn.baud_rate = *p_data++; + p_rx_frame->u.rpn.byte_size = (*p_data >> RFCOMM_RPN_BITS_SHIFT) & RFCOMM_RPN_BITS_MASK; + p_rx_frame->u.rpn.stop_bits = (*p_data >> RFCOMM_RPN_STOP_BITS_SHIFT) & RFCOMM_RPN_STOP_BITS_MASK; + p_rx_frame->u.rpn.parity = (*p_data >> RFCOMM_RPN_PARITY_SHIFT) & RFCOMM_RPN_PARITY_MASK; + p_rx_frame->u.rpn.parity_type = (*p_data++ >> RFCOMM_RPN_PARITY_TYPE_SHIFT) & RFCOMM_RPN_PARITY_TYPE_MASK; + + p_rx_frame->u.rpn.fc_type = *p_data++ & RFCOMM_FC_MASK; + p_rx_frame->u.rpn.xon_char = *p_data++; + p_rx_frame->u.rpn.xoff_char = *p_data++; + p_rx_frame->u.rpn.param_mask = (*p_data + (*(p_data + 1) << 8)) & RFCOMM_RPN_PM_MASK; + } + GKI_freebuf (p_buf); + + rfc_process_rpn (p_mcb, is_command, p_rx_frame->u.rpn.is_request, p_rx_frame); + return; + + case RFCOMM_MX_RLS: + if (length != RFCOMM_MX_RLS_LEN) + break; + + ea = *p_data & RFCOMM_EA; + cr = (*p_data & RFCOMM_CR_MASK) >> RFCOMM_SHIFT_CR; + + p_rx_frame->dlci = *p_data++ >> RFCOMM_SHIFT_DLCI; + p_rx_frame->u.rls.line_status = (*p_data & ~0x01); + + if (!ea || !cr || !p_rx_frame->dlci + || !RFCOMM_VALID_DLCI (p_rx_frame->dlci)) + { + RFCOMM_TRACE_ERROR ("Bad RPN frame"); + break; + } + + GKI_freebuf (p_buf); + + rfc_process_rls (p_mcb, is_command, p_rx_frame); + return; + } + + GKI_freebuf (p_buf); + + if (is_command) + rfc_send_nsc (p_mcb); +} + diff --git a/components/bt/bluedroid/stack/rfcomm/rfc_utils.c b/components/bt/bluedroid/stack/rfcomm/rfc_utils.c new file mode 100755 index 0000000000..4850fc9d95 --- /dev/null +++ b/components/bt/bluedroid/stack/rfcomm/rfc_utils.c @@ -0,0 +1,484 @@ +/****************************************************************************** + * + * Copyright (C) 1999-2012 Broadcom Corporation + * + * 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 collection of utility functions used the RFCOMM unit + * + *****************************************************************************/ + +#include "bt_target.h" +#include "gki.h" + +#include "btm_api.h" +#include "btm_int.h" +#include "rfcdefs.h" +#include "port_api.h" +#include "port_ext.h" +#include "port_int.h" +#include "rfc_int.h" +#include "btu.h" +#include "bt_defs.h" + +#include + +/******************************************************************************* +** +** Function rfc_calc_fcs +** +** Description Reversed CRC Table , 8-bit, poly=0x07 +** (GSM 07.10 TS 101 369 V6.3.0) +*******************************************************************************/ +static const UINT8 rfc_crctable[] = +{ + 0x00, 0x91, 0xE3, 0x72, 0x07, 0x96, 0xE4, 0x75, 0x0E, 0x9F, 0xED, 0x7C, 0x09, 0x98, 0xEA, 0x7B, + 0x1C, 0x8D, 0xFF, 0x6E, 0x1B, 0x8A, 0xF8, 0x69, 0x12, 0x83, 0xF1, 0x60, 0x15, 0x84, 0xF6, 0x67, + 0x38, 0xA9, 0xDB, 0x4A, 0x3F, 0xAE, 0xDC, 0x4D, 0x36, 0xA7, 0xD5, 0x44, 0x31, 0xA0, 0xD2, 0x43, + 0x24, 0xB5, 0xC7, 0x56, 0x23, 0xB2, 0xC0, 0x51, 0x2A, 0xBB, 0xC9, 0x58, 0x2D, 0xBC, 0xCE, 0x5F, + + 0x70, 0xE1, 0x93, 0x02, 0x77, 0xE6, 0x94, 0x05, 0x7E, 0xEF, 0x9D, 0x0C, 0x79, 0xE8, 0x9A, 0x0B, + 0x6C, 0xFD, 0x8F, 0x1E, 0x6B, 0xFA, 0x88, 0x19, 0x62, 0xF3, 0x81, 0x10, 0x65, 0xF4, 0x86, 0x17, + 0x48, 0xD9, 0xAB, 0x3A, 0x4F, 0xDE, 0xAC, 0x3D, 0x46, 0xD7, 0xA5, 0x34, 0x41, 0xD0, 0xA2, 0x33, + 0x54, 0xC5, 0xB7, 0x26, 0x53, 0xC2, 0xB0, 0x21, 0x5A, 0xCB, 0xB9, 0x28, 0x5D, 0xCC, 0xBE, 0x2F, + + 0xE0, 0x71, 0x03, 0x92, 0xE7, 0x76, 0x04, 0x95, 0xEE, 0x7F, 0x0D, 0x9C, 0xE9, 0x78, 0x0A, 0x9B, + 0xFC, 0x6D, 0x1F, 0x8E, 0xFB, 0x6A, 0x18, 0x89, 0xF2, 0x63, 0x11, 0x80, 0xF5, 0x64, 0x16, 0x87, + 0xD8, 0x49, 0x3B, 0xAA, 0xDF, 0x4E, 0x3C, 0xAD, 0xD6, 0x47, 0x35, 0xA4, 0xD1, 0x40, 0x32, 0xA3, + 0xC4, 0x55, 0x27, 0xB6, 0xC3, 0x52, 0x20, 0xB1, 0xCA, 0x5B, 0x29, 0xB8, 0xCD, 0x5C, 0x2E, 0xBF, + + 0x90, 0x01, 0x73, 0xE2, 0x97, 0x06, 0x74, 0xE5, 0x9E, 0x0F, 0x7D, 0xEC, 0x99, 0x08, 0x7A, 0xEB, + 0x8C, 0x1D, 0x6F, 0xFE, 0x8B, 0x1A, 0x68, 0xF9, 0x82, 0x13, 0x61, 0xF0, 0x85, 0x14, 0x66, 0xF7, + 0xA8, 0x39, 0x4B, 0xDA, 0xAF, 0x3E, 0x4C, 0xDD, 0xA6, 0x37, 0x45, 0xD4, 0xA1, 0x30, 0x42, 0xD3, + 0xB4, 0x25, 0x57, 0xC6, 0xB3, 0x22, 0x50, 0xC1, 0xBA, 0x2B, 0x59, 0xC8, 0xBD, 0x2C, 0x5E, 0xCF +}; + + +/******************************************************************************* +** +** Function rfc_calc_fcs +** +** Description This function calculate FCS for the RFCOMM frame +** (GSM 07.10 TS 101 369 V6.3.0) +** +** Input len - number of bytes in the message +** p - points to message +** +*******************************************************************************/ +UINT8 rfc_calc_fcs (UINT16 len, UINT8 *p) +{ + UINT8 fcs = 0xFF; + + while (len--) + { + fcs = rfc_crctable[fcs ^ *p++]; + } + + /* Ones compliment */ + return (0xFF - fcs); +} + + +/******************************************************************************* +** +** Function rfc_check_fcs +** +** Description This function checks FCS for the RFCOMM frame +** (GSM 07.10 TS 101 369 V6.3.0) +** +** Input len - number of bytes in the message +** p - points to message +** received_fcs - received FCS +** +*******************************************************************************/ +BOOLEAN rfc_check_fcs (UINT16 len, UINT8 *p, UINT8 received_fcs) +{ + UINT8 fcs = 0xFF; + + while (len--) + { + fcs = rfc_crctable[fcs ^ *p++]; + } + + /* Ones compliment */ + fcs = rfc_crctable[fcs ^ received_fcs]; + + /*0xCF is the reversed order of 11110011.*/ + return (fcs == 0xCF); +} + + +/******************************************************************************* +** +** Function rfc_alloc_multiplexer_channel +** +** Description This function returns existing or new control block for +** the BD_ADDR. +** +*******************************************************************************/ +tRFC_MCB *rfc_alloc_multiplexer_channel (BD_ADDR bd_addr, BOOLEAN is_initiator) +{ + int i, j; + tRFC_MCB *p_mcb = NULL; + RFCOMM_TRACE_DEBUG("rfc_alloc_multiplexer_channel: bd_addr:%02x:%02x:%02x:%02x:%02x:%02x", + bd_addr[0], bd_addr[1], bd_addr[2], bd_addr[3], bd_addr[4], bd_addr[5]); + RFCOMM_TRACE_DEBUG("rfc_alloc_multiplexer_channel:is_initiator:%d", is_initiator); + + for (i = 0; i < MAX_BD_CONNECTIONS; i++) + { + RFCOMM_TRACE_DEBUG("rfc_alloc_multiplexer_channel rfc_cb.port.rfc_mcb[%d].state:%d", + i, rfc_cb.port.rfc_mcb[i].state); + RFCOMM_TRACE_DEBUG("(rfc_cb.port.rfc_mcb[i].bd_addr:%02x:%02x:%02x:%02x:%02x:%02x", + rfc_cb.port.rfc_mcb[i].bd_addr[0], rfc_cb.port.rfc_mcb[i].bd_addr[1], + rfc_cb.port.rfc_mcb[i].bd_addr[2], rfc_cb.port.rfc_mcb[i].bd_addr[3], + rfc_cb.port.rfc_mcb[i].bd_addr[4], rfc_cb.port.rfc_mcb[i].bd_addr[5]); + + if ((rfc_cb.port.rfc_mcb[i].state != RFC_MX_STATE_IDLE) + && (!memcmp (rfc_cb.port.rfc_mcb[i].bd_addr, bd_addr, BD_ADDR_LEN))) + { + /* Multiplexer channel found do not change anything */ + /* If there was an inactivity timer running stop it now */ + if (rfc_cb.port.rfc_mcb[i].state == RFC_MX_STATE_CONNECTED) + rfc_timer_stop (&rfc_cb.port.rfc_mcb[i]); + RFCOMM_TRACE_DEBUG("rfc_alloc_multiplexer_channel:is_initiator:%d, found, state:%d, p_mcb:%p", + is_initiator, rfc_cb.port.rfc_mcb[i].state, &rfc_cb.port.rfc_mcb[i]); + return (&rfc_cb.port.rfc_mcb[i]); + } + } + + /* connection with bd_addr does not exist */ + for (i = 0, j = rfc_cb.rfc.last_mux + 1; i < MAX_BD_CONNECTIONS; i++, j++) + { + if (j >= MAX_BD_CONNECTIONS) + j = 0; + + p_mcb = &rfc_cb.port.rfc_mcb[j]; + if (rfc_cb.port.rfc_mcb[j].state == RFC_MX_STATE_IDLE) + { + /* New multiplexer control block */ + memset (p_mcb, 0, sizeof (tRFC_MCB)); + memcpy (p_mcb->bd_addr, bd_addr, BD_ADDR_LEN); + RFCOMM_TRACE_DEBUG("rfc_alloc_multiplexer_channel:is_initiator:%d, create new p_mcb:%p, index:%d", + is_initiator, &rfc_cb.port.rfc_mcb[j], j); + + GKI_init_q(&p_mcb->cmd_q); + + p_mcb->is_initiator = is_initiator; + + rfc_timer_start (p_mcb, RFC_MCB_INIT_INACT_TIMER); + + rfc_cb.rfc.last_mux = (UINT8) j; + return (p_mcb); + } + } + return (NULL); +} + + +/******************************************************************************* +** +** Function rfc_release_multiplexer_channel +** +** Description This function returns existing or new control block for +** the BD_ADDR. +** +*******************************************************************************/ +void rfc_release_multiplexer_channel (tRFC_MCB *p_mcb) +{ + void *p_buf; + + rfc_timer_stop (p_mcb); + + while ((p_buf = GKI_dequeue(&p_mcb->cmd_q)) != NULL) + GKI_freebuf(p_buf); + + memset (p_mcb, 0, sizeof (tRFC_MCB)); + p_mcb->state = RFC_MX_STATE_IDLE; +} + + +/******************************************************************************* +** +** Function rfc_timer_start +** +** Description Start RFC Timer +** +*******************************************************************************/ +void rfc_timer_start (tRFC_MCB *p_mcb, UINT16 timeout) +{ + TIMER_LIST_ENT *p_tle = &p_mcb->tle; + + RFCOMM_TRACE_EVENT ("rfc_timer_start - timeout:%d", timeout); + + p_tle->param = (UINT32)p_mcb; + + btu_start_timer (p_tle, BTU_TTYPE_RFCOMM_MFC, timeout); +} + + +/******************************************************************************* +** +** Function rfc_timer_stop +** +** Description Stop RFC Timer +** +*******************************************************************************/ +void rfc_timer_stop (tRFC_MCB *p_mcb) +{ + RFCOMM_TRACE_EVENT ("rfc_timer_stop"); + + btu_stop_timer (&p_mcb->tle); +} + + +/******************************************************************************* +** +** Function rfc_port_timer_start +** +** Description Start RFC Timer +** +*******************************************************************************/ +void rfc_port_timer_start (tPORT *p_port, UINT16 timeout) +{ + TIMER_LIST_ENT *p_tle = &p_port->rfc.tle; + + RFCOMM_TRACE_EVENT ("rfc_port_timer_start - timeout:%d", timeout); + + p_tle->param = (UINT32)p_port; + + btu_start_timer (p_tle, BTU_TTYPE_RFCOMM_PORT, timeout); +} + + +/******************************************************************************* +** +** Function rfc_port_timer_stop +** +** Description Stop RFC Timer +** +*******************************************************************************/ +void rfc_port_timer_stop (tPORT *p_port) +{ + RFCOMM_TRACE_EVENT ("rfc_port_timer_stop"); + + btu_stop_timer (&p_port->rfc.tle); +} + + +/******************************************************************************* +** +** Function rfc_check_mcb_active +** +** Description Check if there are any opened ports on the MCB if not +** start MCB Inact timer. +** +** Returns void +** +*******************************************************************************/ +void rfc_check_mcb_active (tRFC_MCB *p_mcb) +{ + UINT16 i; + + for (i = 0; i < RFCOMM_MAX_DLCI; i++) + { + if (p_mcb->port_inx[i] != 0) + { + p_mcb->is_disc_initiator = FALSE; + return; + } + } + /* The last port was DISCed. On the client side start disconnecting Mx */ + /* On the server side start inactivity timer */ + if (p_mcb->is_disc_initiator) + { + p_mcb->is_disc_initiator = FALSE; + rfc_mx_sm_execute (p_mcb, RFC_MX_EVENT_CLOSE_REQ, NULL); + } + else + rfc_timer_start (p_mcb, RFC_MCB_RELEASE_INACT_TIMER); +} + + +/******************************************************************************* +** +** Function rfcomm_process_timeout +** +** Description The function called every second to check RFCOMM timers +** +** Returns void +** +*******************************************************************************/ +void rfcomm_process_timeout (TIMER_LIST_ENT *p_tle) +{ + switch (p_tle->event) + { + case BTU_TTYPE_RFCOMM_MFC: + rfc_mx_sm_execute ((tRFC_MCB *)p_tle->param, RFC_EVENT_TIMEOUT, NULL); + break; + + case BTU_TTYPE_RFCOMM_PORT: + rfc_port_sm_execute ((tPORT *)p_tle->param, RFC_EVENT_TIMEOUT, NULL); + break; + + default: + break; + } +} + + +/******************************************************************************* +** +** Function rfc_sec_check_complete +** +** Description The function called when Security Manager finishes +** verification of the service side connection +** +** Returns void +** +*******************************************************************************/ +void rfc_sec_check_complete (BD_ADDR bd_addr, tBT_TRANSPORT transport, void *p_ref_data, UINT8 res) +{ + tPORT *p_port = (tPORT *)p_ref_data; + UNUSED(bd_addr); + UNUSED(transport); + + /* Verify that PORT is still waiting for Security to complete */ + if (!p_port->in_use + || ((p_port->rfc.state != RFC_STATE_ORIG_WAIT_SEC_CHECK) + && (p_port->rfc.state != RFC_STATE_TERM_WAIT_SEC_CHECK))) + return; + + rfc_port_sm_execute ((tPORT *)p_ref_data, RFC_EVENT_SEC_COMPLETE, &res); +} + + +/******************************************************************************* +** +** Function rfc_port_closed +** +** Description The function is called when port is released based on the +** event received from the lower layer, typically L2CAP +** connection down, DISC, or DM frame. +** +** Returns void +** +*******************************************************************************/ +void rfc_port_closed (tPORT *p_port) +{ + tRFC_MCB *p_mcb = p_port->rfc.p_mcb; + + RFCOMM_TRACE_DEBUG ("rfc_port_closed"); + + rfc_port_timer_stop (p_port); + + p_port->rfc.state = RFC_STATE_CLOSED; + + /* If multiplexer channel was up mark it as down */ + if (p_mcb) + { + p_mcb->port_inx[p_port->dlci] = 0; + + /* If there are no more ports opened on this MCB release it */ + rfc_check_mcb_active (p_mcb); + } + + /* Notify port that RFC connection is gone */ + port_rfc_closed (p_port, PORT_CLOSED); +} + +/******************************************************************************* +** +** Function rfc_inc_credit +** +** Description The function is called when a credit is received in a UIH +** frame. It increments the TX credit count, and if data +** flow had halted, it restarts it. +** +** Returns void +** +*******************************************************************************/ +void rfc_inc_credit (tPORT *p_port, UINT8 credit) +{ + if (p_port->rfc.p_mcb->flow == PORT_FC_CREDIT) + { + p_port->credit_tx += credit; + + RFCOMM_TRACE_EVENT ("rfc_inc_credit:%d", p_port->credit_tx); + + if (p_port->tx.peer_fc == TRUE) + PORT_FlowInd(p_port->rfc.p_mcb, p_port->dlci, TRUE); + } +} + +/******************************************************************************* +** +** Function rfc_dec_credit +** +** Description The function is called when a UIH frame of user data is +** sent. It decrements the credit count. If credit count +** Reaches zero, peer_fc is set. +** +** Returns void +** +*******************************************************************************/ +void rfc_dec_credit (tPORT *p_port) +{ + if (p_port->rfc.p_mcb->flow == PORT_FC_CREDIT) + { + if (p_port->credit_tx > 0) + p_port->credit_tx--; + + if (p_port->credit_tx == 0) + p_port->tx.peer_fc = TRUE; + } +} + + +/******************************************************************************* +** +** Function rfc_check_send_cmd +** +** Description This function is called to send an RFCOMM command message +** or to handle the RFCOMM command message queue. +** +** Returns void +** +*******************************************************************************/ +void rfc_check_send_cmd(tRFC_MCB *p_mcb, BT_HDR *p_buf) +{ + BT_HDR *p; + + /* if passed a buffer queue it */ + if (p_buf != NULL) + { + GKI_enqueue(&p_mcb->cmd_q, p_buf); + } + + /* handle queue if L2CAP not congested */ + while (p_mcb->l2cap_congested == FALSE) + { + if ((p = (BT_HDR *) GKI_dequeue(&p_mcb->cmd_q)) == NULL) + { + break; + } + + + L2CA_DataWrite (p_mcb->lcid, p); + } +} + + diff --git a/components/bt/bluedroid/stack/sdp/sdp_api.c b/components/bt/bluedroid/stack/sdp/sdp_api.c new file mode 100755 index 0000000000..1eab7d541c --- /dev/null +++ b/components/bt/bluedroid/stack/sdp/sdp_api.c @@ -0,0 +1,1275 @@ +/****************************************************************************** + * + * Copyright (C) 1999-2012 Broadcom Corporation + * + * 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 SDP interface functions + * + ******************************************************************************/ + +//#include +#include +//#include + +#include "bt_target.h" +//#include "bt_utils.h" +#include "gki.h" +#include "l2cdefs.h" +#include "hcidefs.h" +#include "hcimsgs.h" +#include "bt_defs.h" +#include "sdp_api.h" +#include "sdpint.h" +#include "btu.h" + +/********************************************************************** +** C L I E N T F U N C T I O N P R O T O T Y P E S * +***********************************************************************/ + +/******************************************************************************* +** +** Function SDP_InitDiscoveryDb +** +** Description This function is called to initialize a discovery database. +** +** Parameters: p_db - (input) address of an area of memory where the +** discovery database is managed. +** len - (input) size (in bytes) of the memory +** NOTE: This must be larger than sizeof(tSDP_DISCOVERY_DB) +** num_uuid - (input) number of UUID filters applied +** p_uuid_list - (input) list of UUID filters +** num_attr - (input) number of attribute filters applied +** p_attr_list - (input) list of attribute filters +** +** +** Returns BOOLEAN +** TRUE if successful +** FALSE if one or more parameters are bad +** +*******************************************************************************/ +BOOLEAN SDP_InitDiscoveryDb (tSDP_DISCOVERY_DB *p_db, UINT32 len, UINT16 num_uuid, + tSDP_UUID *p_uuid_list, UINT16 num_attr, UINT16 *p_attr_list) +{ +#if SDP_CLIENT_ENABLED == TRUE + UINT16 xx; + + /* verify the parameters */ + if (p_db == NULL || (sizeof (tSDP_DISCOVERY_DB) > len) || + num_attr > SDP_MAX_ATTR_FILTERS || num_uuid > SDP_MAX_UUID_FILTERS) + { + SDP_TRACE_ERROR("SDP_InitDiscoveryDb Illegal param: p_db 0x%x, len %d, num_uuid %d, num_attr %d", + (UINT32)p_db, len, num_uuid, num_attr); + + return(FALSE); + } + + memset (p_db, 0, (size_t)len); + + p_db->mem_size = len - sizeof (tSDP_DISCOVERY_DB); + p_db->mem_free = p_db->mem_size; + p_db->p_first_rec = NULL; + p_db->p_free_mem = (UINT8 *)(p_db + 1); + + for (xx = 0; xx < num_uuid; xx++) + p_db->uuid_filters[xx] = *p_uuid_list++; + + p_db->num_uuid_filters = num_uuid; + + for (xx = 0; xx < num_attr; xx++) + p_db->attr_filters[xx] = *p_attr_list++; + + /* sort attributes */ + sdpu_sort_attr_list( num_attr, p_db ); + + p_db->num_attr_filters = num_attr; +#endif + return(TRUE); +} + + + +/******************************************************************************* +** +** Function SDP_CancelServiceSearch +** +** Description This function cancels an active query to an SDP server. +** +** Returns TRUE if discovery cancelled, FALSE if a matching activity is not found. +** +*******************************************************************************/ +BOOLEAN SDP_CancelServiceSearch (tSDP_DISCOVERY_DB *p_db) +{ +#if SDP_CLIENT_ENABLED == TRUE + tCONN_CB *p_ccb = sdpu_find_ccb_by_db (p_db); + if (!p_ccb) + return(FALSE); + + sdp_disconnect (p_ccb, SDP_CANCEL); + p_ccb->disc_state = SDP_DISC_WAIT_CANCEL; +#endif + return(TRUE); +} + + + +/******************************************************************************* +** +** Function SDP_ServiceSearchRequest +** +** Description This function queries an SDP server for information. +** +** Returns TRUE if discovery started, FALSE if failed. +** +*******************************************************************************/ +BOOLEAN SDP_ServiceSearchRequest (UINT8 *p_bd_addr, tSDP_DISCOVERY_DB *p_db, + tSDP_DISC_CMPL_CB *p_cb) +{ +#if SDP_CLIENT_ENABLED == TRUE + tCONN_CB *p_ccb; + + /* Specific BD address */ + p_ccb = sdp_conn_originate (p_bd_addr); + + if (!p_ccb) + return(FALSE); + + p_ccb->disc_state = SDP_DISC_WAIT_CONN; + p_ccb->p_db = p_db; + p_ccb->p_cb = p_cb; + + return(TRUE); +#else + return(FALSE); +#endif +} + + +/******************************************************************************* +** +** Function SDP_ServiceSearchAttributeRequest +** +** Description This function queries an SDP server for information. +** +** The difference between this API function and the function +** SDP_ServiceSearchRequest is that this one does a +** combined ServiceSearchAttributeRequest SDP function. +** (This is for Unplug Testing) +** +** Returns TRUE if discovery started, FALSE if failed. +** +*******************************************************************************/ +BOOLEAN SDP_ServiceSearchAttributeRequest (UINT8 *p_bd_addr, tSDP_DISCOVERY_DB *p_db, + tSDP_DISC_CMPL_CB *p_cb) +{ +#if SDP_CLIENT_ENABLED == TRUE + tCONN_CB *p_ccb; + + /* Specific BD address */ + p_ccb = sdp_conn_originate (p_bd_addr); + + if (!p_ccb) + return(FALSE); + + p_ccb->disc_state = SDP_DISC_WAIT_CONN; + p_ccb->p_db = p_db; + p_ccb->p_cb = p_cb; + + p_ccb->is_attr_search = TRUE; + + return(TRUE); +#else + return(FALSE); +#endif +} +/******************************************************************************* +** +** Function SDP_ServiceSearchAttributeRequest2 +** +** Description This function queries an SDP server for information. +** +** The difference between this API function and the function +** SDP_ServiceSearchRequest is that this one does a +** combined ServiceSearchAttributeRequest SDP function. +** (This is for Unplug Testing) +** +** Returns TRUE if discovery started, FALSE if failed. +** +*******************************************************************************/ +BOOLEAN SDP_ServiceSearchAttributeRequest2 (UINT8 *p_bd_addr, tSDP_DISCOVERY_DB *p_db, + tSDP_DISC_CMPL_CB2 *p_cb2, void * user_data) +{ +#if SDP_CLIENT_ENABLED == TRUE + tCONN_CB *p_ccb; + + /* Specific BD address */ + p_ccb = sdp_conn_originate (p_bd_addr); + + if (!p_ccb) + return(FALSE); + + p_ccb->disc_state = SDP_DISC_WAIT_CONN; + p_ccb->p_db = p_db; + p_ccb->p_cb2 = p_cb2; + + p_ccb->is_attr_search = TRUE; + p_ccb->user_data = user_data; + + return(TRUE); +#else + return(FALSE); +#endif +} + +#if SDP_CLIENT_ENABLED == TRUE +void SDP_SetIdleTimeout (BD_ADDR addr, UINT16 timeout) +{ + UNUSED(addr); + UNUSED(timeout); +} +#endif + +/******************************************************************************* +** +** Function SDP_FindAttributeInDb +** +** Description This function queries an SDP database for a specific attribute. +** If the p_start_rec pointer is NULL, it looks from the beginning +** of the database, else it continues from the next record after +** p_start_rec. +** +** Returns Pointer to matching record, or NULL +** +*******************************************************************************/ +tSDP_DISC_REC *SDP_FindAttributeInDb (tSDP_DISCOVERY_DB *p_db, UINT16 attr_id, + tSDP_DISC_REC *p_start_rec) +{ +#if SDP_CLIENT_ENABLED == TRUE + tSDP_DISC_REC *p_rec; + tSDP_DISC_ATTR *p_attr; + + /* Must have a valid database */ + if (p_db == NULL) + return(NULL); + + if (!p_start_rec) + p_rec = p_db->p_first_rec; + else + p_rec = p_start_rec->p_next_rec; + + while (p_rec) + { + p_attr = p_rec->p_first_attr; + while (p_attr) + { + if (p_attr->attr_id == attr_id) + return(p_rec); + + p_attr = p_attr->p_next_attr; + } + + p_rec = p_rec->p_next_rec; + } +#endif + /* If here, no matching attribute found */ + return(NULL); +} + + +/******************************************************************************* +** +** Function SDP_FindAttributeInRec +** +** Description This function searches an SDP discovery record for a specific +** attribute. +** +** Returns Pointer to matching attribute entry, or NULL +** +*******************************************************************************/ +tSDP_DISC_ATTR *SDP_FindAttributeInRec (tSDP_DISC_REC *p_rec, UINT16 attr_id) +{ +#if SDP_CLIENT_ENABLED == TRUE + tSDP_DISC_ATTR *p_attr; + + p_attr = p_rec->p_first_attr; + while (p_attr) + { + if (p_attr->attr_id == attr_id) + return(p_attr); + + p_attr = p_attr->p_next_attr; + } +#endif + /* If here, no matching attribute found */ + return(NULL); +} + +/******************************************************************************* +** +** Function SDP_FindServiceUUIDInRec +** +** Description This function is called to read the service UUID within a record +** if there is any. +** +** Parameters: p_rec - pointer to a SDP record. +** p_uuid - output parameter to save the UUID found. +** +** Returns TRUE if found, otherwise FALSE. +** +*******************************************************************************/ +BOOLEAN SDP_FindServiceUUIDInRec(tSDP_DISC_REC *p_rec, tBT_UUID * p_uuid) +{ +#if SDP_CLIENT_ENABLED == TRUE + tSDP_DISC_ATTR *p_attr, *p_sattr, *p_extra_sattr; + + p_attr = p_rec->p_first_attr; + + while (p_attr) + { + if ((p_attr->attr_id == ATTR_ID_SERVICE_CLASS_ID_LIST) + && (SDP_DISC_ATTR_TYPE(p_attr->attr_len_type) == DATA_ELE_SEQ_DESC_TYPE)) + { + for (p_sattr = p_attr->attr_value.v.p_sub_attr; p_sattr; p_sattr = p_sattr->p_next_attr) + { + if (SDP_DISC_ATTR_TYPE(p_sattr->attr_len_type) == UUID_DESC_TYPE) + { + if (SDP_DISC_ATTR_LEN(p_sattr->attr_len_type) == LEN_UUID_16) + { + p_uuid->len = LEN_UUID_16; + p_uuid->uu.uuid16 = p_sattr->attr_value.v.u16; + } + else if (SDP_DISC_ATTR_LEN(p_sattr->attr_len_type) == LEN_UUID_128) + { + p_uuid->len = LEN_UUID_128; + for (uint8_t i = 0; i != LEN_UUID_128; ++i) + p_uuid->uu.uuid128[i] = p_sattr->attr_value.v.array[LEN_UUID_128-i-1]; + } + else if (SDP_DISC_ATTR_LEN(p_sattr->attr_len_type) == LEN_UUID_32) + { + p_uuid->len = LEN_UUID_32; + p_uuid->uu.uuid32 = p_sattr->attr_value.v.u32; + } + + return(TRUE); + } + + /* Checking for Toyota G Block Car Kit: + ** This car kit puts an extra data element sequence + ** where the UUID is suppose to be!!! + */ + else + { + if (SDP_DISC_ATTR_TYPE(p_sattr->attr_len_type) == DATA_ELE_SEQ_DESC_TYPE) + { + /* Look through data element sequence until no more UUIDs */ + for (p_extra_sattr = p_sattr->attr_value.v.p_sub_attr; p_extra_sattr; p_extra_sattr = p_extra_sattr->p_next_attr) + { + /* Increment past this to see if the next attribut is UUID */ + if ((SDP_DISC_ATTR_TYPE(p_extra_sattr->attr_len_type) == UUID_DESC_TYPE) + /* only support 16 bits UUID for now */ + && (SDP_DISC_ATTR_LEN(p_extra_sattr->attr_len_type) == 2)) + { + p_uuid->len = 2; + p_uuid->uu.uuid16 = p_extra_sattr->attr_value.v.u16; + return(TRUE); + } + } + } + } + } + break; + } + else if (p_attr->attr_id == ATTR_ID_SERVICE_ID) + { + if ((SDP_DISC_ATTR_TYPE(p_attr->attr_len_type) == UUID_DESC_TYPE) + /* only support 16 bits UUID for now */ + && (SDP_DISC_ATTR_LEN(p_attr->attr_len_type) == 2)) + { + p_uuid->len = 2; + p_uuid->uu.uuid16 = p_attr->attr_value.v.u16; + return(TRUE); + } + } + p_attr = p_attr->p_next_attr; + } + return FALSE; +#endif +} + +/******************************************************************************* +** +** Function SDP_FindServiceUUIDInRec_128bit +** +** Description This function is called to read the 128-bit service UUID within a record +** if there is any. +** +** Parameters: p_rec - pointer to a SDP record. +** p_uuid - output parameter to save the UUID found. +** +** Returns TRUE if found, otherwise FALSE. +** +*******************************************************************************/ +BOOLEAN SDP_FindServiceUUIDInRec_128bit(tSDP_DISC_REC *p_rec, tBT_UUID * p_uuid) +{ +#if SDP_CLIENT_ENABLED == TRUE + tSDP_DISC_ATTR *p_attr, *p_sattr; + + p_attr = p_rec->p_first_attr; + + while (p_attr) + { + if ((p_attr->attr_id == ATTR_ID_SERVICE_CLASS_ID_LIST) + && (SDP_DISC_ATTR_TYPE(p_attr->attr_len_type) == DATA_ELE_SEQ_DESC_TYPE)) + { + for (p_sattr = p_attr->attr_value.v.p_sub_attr; p_sattr; p_sattr = p_sattr->p_next_attr) + { + if (SDP_DISC_ATTR_TYPE(p_sattr->attr_len_type) == UUID_DESC_TYPE) + { + /* only support 128 bits UUID for now */ + if (SDP_DISC_ATTR_LEN(p_sattr->attr_len_type) == 16) + { + p_uuid->len = LEN_UUID_128; + for (uint8_t i = 0; i != LEN_UUID_128; ++i) + p_uuid->uu.uuid128[i] = p_sattr->attr_value.v.array[LEN_UUID_128-i-1]; + } + return(TRUE); + } + } + break; + } + else if (p_attr->attr_id == ATTR_ID_SERVICE_ID) + { + if ((SDP_DISC_ATTR_TYPE(p_attr->attr_len_type) == UUID_DESC_TYPE) + /* only support 128 bits UUID for now */ + && (SDP_DISC_ATTR_LEN(p_attr->attr_len_type) == 16)) + { + p_uuid->len = LEN_UUID_128; + for (uint8_t i = 0; i != LEN_UUID_128; ++i) + p_uuid->uu.uuid128[i] = p_attr->attr_value.v.array[LEN_UUID_128-i-1]; + return(TRUE); + } + } + p_attr = p_attr->p_next_attr; + } + return FALSE; +#endif +} + +/******************************************************************************* +** +** Function SDP_FindServiceInDb +** +** Description This function queries an SDP database for a specific service. +** If the p_start_rec pointer is NULL, it looks from the beginning +** of the database, else it continues from the next record after +** p_start_rec. +** +** Returns Pointer to record containing service class, or NULL +** +*******************************************************************************/ +tSDP_DISC_REC *SDP_FindServiceInDb (tSDP_DISCOVERY_DB *p_db, UINT16 service_uuid, tSDP_DISC_REC *p_start_rec) +{ +#if SDP_CLIENT_ENABLED == TRUE + tSDP_DISC_REC *p_rec; + tSDP_DISC_ATTR *p_attr, *p_sattr, *p_extra_sattr; + + /* Must have a valid database */ + if (p_db == NULL) + return(NULL); + + if (!p_start_rec) + p_rec = p_db->p_first_rec; + else + p_rec = p_start_rec->p_next_rec; + + while (p_rec) + { + p_attr = p_rec->p_first_attr; + while (p_attr) + { + if ((p_attr->attr_id == ATTR_ID_SERVICE_CLASS_ID_LIST) + && (SDP_DISC_ATTR_TYPE(p_attr->attr_len_type) == DATA_ELE_SEQ_DESC_TYPE)) + { + for (p_sattr = p_attr->attr_value.v.p_sub_attr; p_sattr; p_sattr = p_sattr->p_next_attr) + { + + if ((SDP_DISC_ATTR_TYPE(p_sattr->attr_len_type) == UUID_DESC_TYPE) + && (SDP_DISC_ATTR_LEN(p_sattr->attr_len_type) == 2) ) { + SDP_TRACE_DEBUG("SDP_FindServiceInDb - p_sattr value = 0x%x serviceuuid = 0x%x\r\n", + p_sattr->attr_value.v.u16, service_uuid); + if(service_uuid == UUID_SERVCLASS_HDP_PROFILE) + { + if( (p_sattr->attr_value.v.u16==UUID_SERVCLASS_HDP_SOURCE) || ( p_sattr->attr_value.v.u16==UUID_SERVCLASS_HDP_SINK)) + { + SDP_TRACE_DEBUG("SDP_FindServiceInDb found HDP source or sink\n" ); + return (p_rec); + } + } + + } + + if (SDP_DISC_ATTR_TYPE(p_sattr->attr_len_type) == UUID_DESC_TYPE && (service_uuid == 0 + || (SDP_DISC_ATTR_LEN(p_sattr->attr_len_type) == 2 + && p_sattr->attr_value.v.u16 == service_uuid))) + /* for a specific uuid, or any one */ + { + return(p_rec); + } + + /* Checking for Toyota G Block Car Kit: + ** This car kit puts an extra data element sequence + ** where the UUID is suppose to be!!! + */ + else + { + if (SDP_DISC_ATTR_TYPE(p_sattr->attr_len_type) == DATA_ELE_SEQ_DESC_TYPE) + { + /* Look through data element sequence until no more UUIDs */ + for (p_extra_sattr = p_sattr->attr_value.v.p_sub_attr; p_extra_sattr; p_extra_sattr = p_extra_sattr->p_next_attr) + { + /* Increment past this to see if the next attribut is UUID */ + if ((SDP_DISC_ATTR_TYPE(p_extra_sattr->attr_len_type) == UUID_DESC_TYPE) + && (SDP_DISC_ATTR_LEN(p_extra_sattr->attr_len_type) == 2) + /* for a specific uuid, or any one */ + && ((p_extra_sattr->attr_value.v.u16 == service_uuid) || (service_uuid == 0))) + { + return(p_rec); + } + } + } + } + } + break; + } + else if (p_attr->attr_id == ATTR_ID_SERVICE_ID) + { + if ((SDP_DISC_ATTR_TYPE(p_attr->attr_len_type) == UUID_DESC_TYPE) + && (SDP_DISC_ATTR_LEN(p_attr->attr_len_type) == 2) + /* find a specific UUID or anyone */ + && ((p_attr->attr_value.v.u16 == service_uuid) || service_uuid == 0)) + return(p_rec); + } + + p_attr = p_attr->p_next_attr; + } + + p_rec = p_rec->p_next_rec; + } +#endif + /* If here, no matching UUID found */ + return(NULL); +} + +/******************************************************************************* +** +** Function SDP_FindServiceInDb_128bit +** +** Description This function queries an SDP database for a specific service. +** If the p_start_rec pointer is NULL, it looks from the beginning +** of the database, else it continues from the next record after +** p_start_rec. +** +** This function is kept separate from SDP_FindServiceInDb since +** that API is expected to return only 16-bit UUIDs +** +** Returns Pointer to record containing service class, or NULL +** +*******************************************************************************/ +tSDP_DISC_REC *SDP_FindServiceInDb_128bit(tSDP_DISCOVERY_DB *p_db, tSDP_DISC_REC *p_start_rec) +{ +#if SDP_CLIENT_ENABLED == TRUE + tSDP_DISC_REC *p_rec; + tSDP_DISC_ATTR *p_attr, *p_sattr; + + /* Must have a valid database */ + if (p_db == NULL) + return(NULL); + + if (!p_start_rec) + p_rec = p_db->p_first_rec; + else + p_rec = p_start_rec->p_next_rec; + + while (p_rec) + { + p_attr = p_rec->p_first_attr; + while (p_attr) + { + if ((p_attr->attr_id == ATTR_ID_SERVICE_CLASS_ID_LIST) + && (SDP_DISC_ATTR_TYPE(p_attr->attr_len_type) == DATA_ELE_SEQ_DESC_TYPE)) + { + for (p_sattr = p_attr->attr_value.v.p_sub_attr; p_sattr; p_sattr = p_sattr->p_next_attr) + { + if ((SDP_DISC_ATTR_TYPE(p_sattr->attr_len_type) == UUID_DESC_TYPE) + && (SDP_DISC_ATTR_LEN(p_sattr->attr_len_type) == 16)) + { + return(p_rec); + } + } + break; + } + else if (p_attr->attr_id == ATTR_ID_SERVICE_ID) + { + if ((SDP_DISC_ATTR_TYPE(p_attr->attr_len_type) == UUID_DESC_TYPE) + && (SDP_DISC_ATTR_LEN(p_attr->attr_len_type) == 16)) + return(p_rec); + } + + p_attr = p_attr->p_next_attr; + } + + p_rec = p_rec->p_next_rec; + } +#endif + /* If here, no matching UUID found */ + return(NULL); +} + + +/******************************************************************************* +** +** Function SDP_FindServiceUUIDInDb +** +** Description This function queries an SDP database for a specific service. +** If the p_start_rec pointer is NULL, it looks from the beginning +** of the database, else it continues from the next record after +** p_start_rec. +** +** NOTE the only difference between this function and the previous function +** "SDP_FindServiceInDb()" is that this function takes a tBT_UUID input +** +** Returns Pointer to record containing service class, or NULL +** +*******************************************************************************/ +tSDP_DISC_REC *SDP_FindServiceUUIDInDb (tSDP_DISCOVERY_DB *p_db, tBT_UUID *p_uuid, tSDP_DISC_REC *p_start_rec) +{ +#if SDP_CLIENT_ENABLED == TRUE + tSDP_DISC_REC *p_rec; + tSDP_DISC_ATTR *p_attr, *p_sattr; + + /* Must have a valid database */ + if (p_db == NULL) + return(NULL); + + if (!p_start_rec) + p_rec = p_db->p_first_rec; + else + p_rec = p_start_rec->p_next_rec; + + while (p_rec) + { + p_attr = p_rec->p_first_attr; + while (p_attr) + { + if ((p_attr->attr_id == ATTR_ID_SERVICE_CLASS_ID_LIST) + && (SDP_DISC_ATTR_TYPE(p_attr->attr_len_type) == DATA_ELE_SEQ_DESC_TYPE)) + { + for (p_sattr = p_attr->attr_value.v.p_sub_attr; p_sattr; p_sattr = p_sattr->p_next_attr) + { + if (SDP_DISC_ATTR_TYPE(p_sattr->attr_len_type) == UUID_DESC_TYPE) + { + if (sdpu_compare_uuid_with_attr (p_uuid, p_sattr)) + return(p_rec); + } + } + break; + } + else if (p_attr->attr_id == ATTR_ID_SERVICE_ID) + { + if (SDP_DISC_ATTR_TYPE(p_attr->attr_len_type) == UUID_DESC_TYPE ) + { + if (sdpu_compare_uuid_with_attr (p_uuid, p_attr)) + return(p_rec); + } + } + + p_attr = p_attr->p_next_attr; + } + + p_rec = p_rec->p_next_rec; + } +#endif /* CLIENT_ENABLED == TRUE */ + /* If here, no matching UUID found */ + return(NULL); +} + +#if SDP_CLIENT_ENABLED == TRUE +/******************************************************************************* +** +** Function sdp_fill_proto_elem +** +** Description This function retrieves the protocol element. +** +** Returns TRUE if found, FALSE if not +** If found, the passed protocol list element is filled in. +** +*******************************************************************************/ +static BOOLEAN sdp_fill_proto_elem( tSDP_DISC_ATTR *p_attr, UINT16 layer_uuid, + tSDP_PROTOCOL_ELEM *p_elem) +{ + tSDP_DISC_ATTR *p_sattr; + + /* Walk through the protocol descriptor list */ + for (p_attr = p_attr->attr_value.v.p_sub_attr; p_attr; p_attr = p_attr->p_next_attr) + { + /* Safety check - each entry should itself be a sequence */ + if (SDP_DISC_ATTR_TYPE(p_attr->attr_len_type) != DATA_ELE_SEQ_DESC_TYPE) + return(FALSE); + + /* Now, see if the entry contains the layer we are interested in */ + for (p_sattr = p_attr->attr_value.v.p_sub_attr; p_sattr; p_sattr = p_sattr->p_next_attr) + { + /* SDP_TRACE_DEBUG ("SDP - p_sattr 0x%x, layer_uuid:0x%x, u16:0x%x####", + p_sattr, layer_uuid, p_sattr->attr_value.v.u16); */ + + if ((SDP_DISC_ATTR_TYPE(p_sattr->attr_len_type) == UUID_DESC_TYPE) + && (SDP_DISC_ATTR_LEN(p_sattr->attr_len_type) == 2) + && (p_sattr->attr_value.v.u16 == layer_uuid)) + { + /* Bingo. Now fill in the passed element */ + p_elem->protocol_uuid = layer_uuid; + p_elem->num_params = 0; + + /* Store the parameters, if any */ + for (p_sattr = p_sattr->p_next_attr; p_sattr; p_sattr = p_sattr->p_next_attr) + { + if (SDP_DISC_ATTR_TYPE(p_sattr->attr_len_type) != UINT_DESC_TYPE) + break; + + if (SDP_DISC_ATTR_LEN(p_sattr->attr_len_type) == 2) + p_elem->params[p_elem->num_params++] = p_sattr->attr_value.v.u16; + else + p_elem->params[p_elem->num_params++] = p_sattr->attr_value.v.u8; + + if (p_elem->num_params >= SDP_MAX_PROTOCOL_PARAMS) + break; + } + return(TRUE); + } + } + } + + return(FALSE); +} +#endif /* CLIENT_ENABLED == TRUE */ + +/******************************************************************************* +** +** Function SDP_FindProtocolListElemInRec +** +** Description This function looks at a specific discovery record for a protocol +** list element. +** +** Returns TRUE if found, FALSE if not +** If found, the passed protocol list element is filled in. +** +*******************************************************************************/ +BOOLEAN SDP_FindProtocolListElemInRec (tSDP_DISC_REC *p_rec, UINT16 layer_uuid, tSDP_PROTOCOL_ELEM *p_elem) +{ +#if SDP_CLIENT_ENABLED == TRUE + tSDP_DISC_ATTR *p_attr; + + p_attr = p_rec->p_first_attr; + while (p_attr) + { + /* Find the protocol descriptor list */ + if ((p_attr->attr_id == ATTR_ID_PROTOCOL_DESC_LIST) + && (SDP_DISC_ATTR_TYPE(p_attr->attr_len_type) == DATA_ELE_SEQ_DESC_TYPE)) + { + return sdp_fill_proto_elem(p_attr, layer_uuid, p_elem); + } + p_attr = p_attr->p_next_attr; + } +#endif + /* If here, no match found */ + return(FALSE); +} + + +/******************************************************************************* +** +** Function SDP_FindAddProtoListsElemInRec +** +** Description This function looks at a specific discovery record for a protocol +** list element. +** +** Returns TRUE if found, FALSE if not +** If found, the passed protocol list element is filled in. +** +*******************************************************************************/ +BOOLEAN SDP_FindAddProtoListsElemInRec (tSDP_DISC_REC *p_rec, UINT16 layer_uuid, tSDP_PROTOCOL_ELEM *p_elem) +{ +#if SDP_CLIENT_ENABLED == TRUE + tSDP_DISC_ATTR *p_attr, *p_sattr; + BOOLEAN ret = FALSE; + + p_attr = p_rec->p_first_attr; + while (p_attr) + { + /* Find the additional protocol descriptor list attribute */ + if ((p_attr->attr_id == ATTR_ID_ADDITION_PROTO_DESC_LISTS) + && (SDP_DISC_ATTR_TYPE(p_attr->attr_len_type) == DATA_ELE_SEQ_DESC_TYPE)) + { + for (p_sattr = p_attr->attr_value.v.p_sub_attr; p_sattr; p_sattr = p_sattr->p_next_attr) + { + /* Safety check - each entry should itself be a sequence */ + if (SDP_DISC_ATTR_TYPE(p_sattr->attr_len_type) == DATA_ELE_SEQ_DESC_TYPE) + { + if ( (ret = sdp_fill_proto_elem(p_sattr, layer_uuid, p_elem)) == TRUE) + break; + } + } + return ret; + } + p_attr = p_attr->p_next_attr; + } +#endif + /* If here, no match found */ + return(FALSE); +} + + +/******************************************************************************* +** +** Function SDP_FindProfileVersionInRec +** +** Description This function looks at a specific discovery record for the +** Profile list descriptor, and pulls out the version number. +** The version number consists of an 8-bit major version and +** an 8-bit minor version. +** +** Returns TRUE if found, FALSE if not +** If found, the major and minor version numbers that were passed +** in are filled in. +** +*******************************************************************************/ +BOOLEAN SDP_FindProfileVersionInRec (tSDP_DISC_REC *p_rec, UINT16 profile_uuid, UINT16 *p_version) +{ +#if SDP_CLIENT_ENABLED == TRUE + tSDP_DISC_ATTR *p_attr, *p_sattr; + + p_attr = p_rec->p_first_attr; + while (p_attr) + { + /* Find the profile descriptor list */ + if ((p_attr->attr_id == ATTR_ID_BT_PROFILE_DESC_LIST) + && (SDP_DISC_ATTR_TYPE(p_attr->attr_len_type) == DATA_ELE_SEQ_DESC_TYPE)) + { + /* Walk through the protocol descriptor list */ + for (p_attr = p_attr->attr_value.v.p_sub_attr; p_attr; p_attr = p_attr->p_next_attr) + { + /* Safety check - each entry should itself be a sequence */ + if (SDP_DISC_ATTR_TYPE(p_attr->attr_len_type) != DATA_ELE_SEQ_DESC_TYPE) + return(FALSE); + + /* Now, see if the entry contains the profile UUID we are interested in */ + for (p_sattr = p_attr->attr_value.v.p_sub_attr; p_sattr; p_sattr = p_sattr->p_next_attr) + { + if ((SDP_DISC_ATTR_TYPE(p_sattr->attr_len_type) == UUID_DESC_TYPE) + && (SDP_DISC_ATTR_LEN(p_sattr->attr_len_type) == 2) /* <- This is bytes, not size code! */ + && (p_sattr->attr_value.v.u16 == profile_uuid)) + { + /* Now fill in the major and minor numbers */ + /* if the attribute matches the description for version (type UINT, size 2 bytes) */ + p_sattr = p_sattr->p_next_attr; + + if ((SDP_DISC_ATTR_TYPE(p_sattr->attr_len_type) == UINT_DESC_TYPE) && + (SDP_DISC_ATTR_LEN(p_sattr->attr_len_type) == 2)) + { + /* The high order 8 bits is the major number, low order is the minor number (big endian) */ + *p_version = p_sattr->attr_value.v.u16; + + return(TRUE); + } + else + return(FALSE); /* The type and/or size was not valid for the profile list version */ + } + } + } + + return(FALSE); + } + p_attr = p_attr->p_next_attr; + } +#endif /* CLIENT_ENABLED == TRUE */ + + /* If here, no match found */ + return(FALSE); +} + +/******************************************************************************* +** Device Identification (DI) Client Functions +*******************************************************************************/ + +/******************************************************************************* +** +** Function SDP_DiDiscover +** +** Description This function queries a remote device for DI information. +** +** Returns SDP_SUCCESS if query started successfully, else error +** +*******************************************************************************/ +UINT16 SDP_DiDiscover( BD_ADDR remote_device, tSDP_DISCOVERY_DB *p_db, + UINT32 len, tSDP_DISC_CMPL_CB *p_cb ) +{ +#if SDP_CLIENT_ENABLED == TRUE + UINT16 result = SDP_DI_DISC_FAILED; + UINT16 num_uuids = 1; + UINT16 di_uuid = UUID_SERVCLASS_PNP_INFORMATION; + + /* build uuid for db init */ + tSDP_UUID init_uuid; + init_uuid.len = 2; + init_uuid.uu.uuid16 = di_uuid; + + if ( SDP_InitDiscoveryDb(p_db, len, num_uuids, &init_uuid, 0, NULL) ) + if ( SDP_ServiceSearchRequest(remote_device, p_db, p_cb) ) + result = SDP_SUCCESS; + + return result; +#else + return SDP_DI_DISC_FAILED; +#endif +} + +/******************************************************************************* +** +** Function SDP_GetNumDiRecords +** +** Description Searches specified database for DI records +** +** Returns number of DI records found +** +*******************************************************************************/ +UINT8 SDP_GetNumDiRecords( tSDP_DISCOVERY_DB *p_db ) +{ +#if SDP_CLIENT_ENABLED == TRUE + UINT8 num_records = 0; + tSDP_DISC_REC *p_curr_record = NULL; + + do + { + p_curr_record = SDP_FindServiceInDb( p_db, UUID_SERVCLASS_PNP_INFORMATION, + p_curr_record ); + if ( p_curr_record ) + num_records++; + }while ( p_curr_record ); + + return num_records; +#else + return 0; +#endif +} + +/******************************************************************************* +** +** Function SDP_AttrStringCopy +** +** Description This function copy given attribute to specified buffer as a string +** +** Returns none +** +*******************************************************************************/ +static void SDP_AttrStringCopy(char *dst, tSDP_DISC_ATTR *p_attr, UINT16 dst_size) +{ + if ( dst == NULL ) return; + if ( p_attr ) + { + UINT16 len = SDP_DISC_ATTR_LEN(p_attr->attr_len_type); + if ( len > dst_size - 1 ) + { + len = dst_size - 1; + } + memcpy(dst, (char *)p_attr->attr_value.v.array, len); + dst[len] = '\0'; + } + else + { + dst[0] = '\0'; + } +} + +/******************************************************************************* +** +** Function SDP_GetDiRecord +** +** Description This function retrieves a remote device's DI record from +** the specified database. +** +** Returns SDP_SUCCESS if record retrieved, else error +** +*******************************************************************************/ +UINT16 SDP_GetDiRecord( UINT8 get_record_index, tSDP_DI_GET_RECORD *p_device_info, + tSDP_DISCOVERY_DB *p_db ) +{ +#if SDP_CLIENT_ENABLED == TRUE + UINT16 result = SDP_NO_DI_RECORD_FOUND; + UINT8 curr_record_index = 1; + + tSDP_DISC_REC *p_curr_record = NULL; + + /* find the requested SDP record in the discovery database */ + do + { + p_curr_record = SDP_FindServiceInDb( p_db, UUID_SERVCLASS_PNP_INFORMATION, + p_curr_record ); + if ( p_curr_record ) + { + if ( curr_record_index++ == get_record_index ) + { + result = SDP_SUCCESS; + break; + } + } + }while ( p_curr_record ); + + if ( result == SDP_SUCCESS ) + { + /* copy the information from the SDP record to the DI record */ + tSDP_DISC_ATTR *p_curr_attr = NULL; + + /* ClientExecutableURL is optional */ + p_curr_attr = SDP_FindAttributeInRec( p_curr_record, ATTR_ID_CLIENT_EXE_URL ); + SDP_AttrStringCopy( p_device_info->rec.client_executable_url, p_curr_attr, + SDP_MAX_ATTR_LEN ); + + /* Service Description is optional */ + p_curr_attr = SDP_FindAttributeInRec( p_curr_record, ATTR_ID_SERVICE_DESCRIPTION ); + SDP_AttrStringCopy( p_device_info->rec.service_description, p_curr_attr, SDP_MAX_ATTR_LEN ); + + /* DocumentationURL is optional */ + p_curr_attr = SDP_FindAttributeInRec( p_curr_record, ATTR_ID_DOCUMENTATION_URL ); + SDP_AttrStringCopy( p_device_info->rec.documentation_url, p_curr_attr, SDP_MAX_ATTR_LEN ); + + p_curr_attr = SDP_FindAttributeInRec( p_curr_record, ATTR_ID_SPECIFICATION_ID ); + if ( p_curr_attr ) + p_device_info->spec_id = p_curr_attr->attr_value.v.u16; + else + result = SDP_ERR_ATTR_NOT_PRESENT; + + p_curr_attr = SDP_FindAttributeInRec( p_curr_record, ATTR_ID_VENDOR_ID ); + if ( p_curr_attr ) + p_device_info->rec.vendor = p_curr_attr->attr_value.v.u16; + else + result = SDP_ERR_ATTR_NOT_PRESENT; + + p_curr_attr = SDP_FindAttributeInRec( p_curr_record, ATTR_ID_VENDOR_ID_SOURCE ); + if ( p_curr_attr ) + p_device_info->rec.vendor_id_source = p_curr_attr->attr_value.v.u16; + else + result = SDP_ERR_ATTR_NOT_PRESENT; + + p_curr_attr = SDP_FindAttributeInRec( p_curr_record, ATTR_ID_PRODUCT_ID ); + if ( p_curr_attr ) + p_device_info->rec.product = p_curr_attr->attr_value.v.u16; + else + result = SDP_ERR_ATTR_NOT_PRESENT; + + p_curr_attr = SDP_FindAttributeInRec( p_curr_record, ATTR_ID_PRODUCT_VERSION ); + if ( p_curr_attr ) + p_device_info->rec.version = p_curr_attr->attr_value.v.u16; + else + result = SDP_ERR_ATTR_NOT_PRESENT; + + p_curr_attr = SDP_FindAttributeInRec( p_curr_record, ATTR_ID_PRIMARY_RECORD ); + if ( p_curr_attr ) + p_device_info->rec.primary_record = (BOOLEAN)p_curr_attr->attr_value.v.u8; + else + result = SDP_ERR_ATTR_NOT_PRESENT; + } + + return result; +#else /* SDP_CLIENT_ENABLED is FALSE */ + return SDP_NO_DI_RECORD_FOUND; +#endif +} + +/******************************************************************************* +** Device Identification (DI) Server Functions +*******************************************************************************/ + +/******************************************************************************* +** +** Function SDP_SetLocalDiRecord +** +** Description This function adds a DI record to the local SDP database. +** +** +** +** Returns Returns SDP_SUCCESS if record added successfully, else error +** +*******************************************************************************/ +UINT16 SDP_SetLocalDiRecord( tSDP_DI_RECORD *p_device_info, UINT32 *p_handle ) +{ +#if SDP_SERVER_ENABLED == TRUE + UINT16 result = SDP_SUCCESS; + UINT32 handle; + UINT16 di_uuid = UUID_SERVCLASS_PNP_INFORMATION; + UINT16 di_specid = BLUETOOTH_DI_SPECIFICATION; + UINT8 temp_u16[2]; + UINT8 *p_temp; + UINT8 u8; + + *p_handle = 0; + if ( p_device_info == NULL ) + return SDP_ILLEGAL_PARAMETER; + + /* if record is to be primary record, get handle to replace old primary */ + if ( p_device_info->primary_record == TRUE && sdp_cb.server_db.di_primary_handle ) + handle = sdp_cb.server_db.di_primary_handle; + else + { + if ( (handle = SDP_CreateRecord()) == 0 ) + return SDP_NO_RESOURCES; + } + + *p_handle = handle; + + /* build the SDP entry */ + /* Add the UUID to the Service Class ID List */ + if ((SDP_AddServiceClassIdList(handle, 1, &di_uuid)) == FALSE) + result = SDP_DI_REG_FAILED; + + /* mandatory */ + if ( result == SDP_SUCCESS) + { + p_temp = temp_u16; + UINT16_TO_BE_STREAM(p_temp, di_specid); + if ( !(SDP_AddAttribute(handle, ATTR_ID_SPECIFICATION_ID, + UINT_DESC_TYPE, sizeof(di_specid), + temp_u16)) ) + result = SDP_DI_REG_FAILED; + } + + /* optional - if string is null, do not add attribute */ + if ( result == SDP_SUCCESS ) + { + if ( p_device_info->client_executable_url[0] != '\0' ) + { + if ( !((strlen(p_device_info->client_executable_url)+1 <= SDP_MAX_ATTR_LEN) && + SDP_AddAttribute(handle, ATTR_ID_CLIENT_EXE_URL, URL_DESC_TYPE, + (UINT32)(strlen(p_device_info->client_executable_url)+1), + (UINT8 *)p_device_info->client_executable_url)) ) + result = SDP_DI_REG_FAILED; + } + } + + /* optional - if string is null, do not add attribute */ + if ( result == SDP_SUCCESS ) + { + if ( p_device_info->service_description[0] != '\0' ) + { + if ( !((strlen(p_device_info->service_description)+1 <= SDP_MAX_ATTR_LEN) && + SDP_AddAttribute(handle, ATTR_ID_SERVICE_DESCRIPTION, + TEXT_STR_DESC_TYPE, + (UINT32)(strlen(p_device_info->service_description)+1), + (UINT8 *)p_device_info->service_description)) ) + result = SDP_DI_REG_FAILED; + } + } + + /* optional - if string is null, do not add attribute */ + if ( result == SDP_SUCCESS ) + { + if ( p_device_info->documentation_url[0] != '\0' ) + { + if ( !((strlen(p_device_info->documentation_url)+1 <= SDP_MAX_ATTR_LEN) && + SDP_AddAttribute(handle, ATTR_ID_DOCUMENTATION_URL, URL_DESC_TYPE, + (UINT32)(strlen(p_device_info->documentation_url)+1), + (UINT8 *)p_device_info->documentation_url)) ) + result = SDP_DI_REG_FAILED; + } + } + + /* mandatory */ + if ( result == SDP_SUCCESS) + { + p_temp = temp_u16; + UINT16_TO_BE_STREAM(p_temp, p_device_info->vendor); + if ( !(SDP_AddAttribute(handle, ATTR_ID_VENDOR_ID, UINT_DESC_TYPE, + sizeof(p_device_info->vendor), temp_u16)) ) + result = SDP_DI_REG_FAILED; + } + + /* mandatory */ + if ( result == SDP_SUCCESS) + { + p_temp = temp_u16; + UINT16_TO_BE_STREAM (p_temp, p_device_info->product); + if ( !(SDP_AddAttribute(handle, ATTR_ID_PRODUCT_ID, + UINT_DESC_TYPE, sizeof(p_device_info->product), temp_u16)) ) + result = SDP_DI_REG_FAILED; + } + + /* mandatory */ + if ( result == SDP_SUCCESS) + { + p_temp = temp_u16; + UINT16_TO_BE_STREAM (p_temp, p_device_info->version); + if ( !(SDP_AddAttribute(handle, ATTR_ID_PRODUCT_VERSION, UINT_DESC_TYPE, + sizeof(p_device_info->version), temp_u16)) ) + result = SDP_DI_REG_FAILED; + } + + /* mandatory */ + if ( result == SDP_SUCCESS) + { + u8 = (UINT8)p_device_info->primary_record; + if ( !(SDP_AddAttribute(handle, ATTR_ID_PRIMARY_RECORD, + BOOLEAN_DESC_TYPE, 1, &u8)) ) + result = SDP_DI_REG_FAILED; + } + + /* mandatory */ + if ( result == SDP_SUCCESS) + { + p_temp = temp_u16; + UINT16_TO_BE_STREAM(p_temp, p_device_info->vendor_id_source); + if ( !(SDP_AddAttribute(handle, ATTR_ID_VENDOR_ID_SOURCE, UINT_DESC_TYPE, + sizeof(p_device_info->vendor_id_source), temp_u16)) ) + result = SDP_DI_REG_FAILED; + } + + if ( result != SDP_SUCCESS ) + SDP_DeleteRecord( handle ); + else if (p_device_info->primary_record == TRUE) + sdp_cb.server_db.di_primary_handle = handle; + + return result; +#else /* SDP_SERVER_ENABLED is FALSE */ + return SDP_DI_REG_FAILED; +#endif /* if SDP_SERVER_ENABLED */ +} + +/******************************************************************************* +** +** Function SDP_SetTraceLevel +** +** Description This function sets the trace level for SDP. If called with +** a value of 0xFF, it simply reads the current trace level. +** +** Returns the new (current) trace level +** +*******************************************************************************/ +UINT8 SDP_SetTraceLevel (UINT8 new_level) +{ + if (new_level != 0xFF) + sdp_cb.trace_level = new_level; + + return(sdp_cb.trace_level); +} diff --git a/components/bt/bluedroid/stack/sdp/sdp_db.c b/components/bt/bluedroid/stack/sdp/sdp_db.c new file mode 100755 index 0000000000..ea8fa87563 --- /dev/null +++ b/components/bt/bluedroid/stack/sdp/sdp_db.c @@ -0,0 +1,1016 @@ +/****************************************************************************** + * + * Copyright (C) 1999-2012 Broadcom Corporation + * + * 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 functions that handle the database + * + ******************************************************************************/ + +#include +#include +#include + +#include "bt_target.h" + +#include "gki.h" + +#include "l2cdefs.h" +#include "hcidefs.h" +#include "hcimsgs.h" + +#include "sdp_api.h" +#include "sdpint.h" + +#if SDP_SERVER_ENABLED == TRUE +/********************************************************************************/ +/* L O C A L F U N C T I O N P R O T O T Y P E S */ +/********************************************************************************/ +static BOOLEAN find_uuid_in_seq (UINT8 *p , UINT32 seq_len, UINT8 *p_his_uuid, + UINT16 his_len, int nest_level); + + +/******************************************************************************* +** +** Function sdp_db_service_search +** +** Description This function searches for a record that contains the +** specified UIDs. It is passed either NULL to start at the +** beginning, or the previous record found. +** +** Returns Pointer to the record, or NULL if not found. +** +*******************************************************************************/ +tSDP_RECORD *sdp_db_service_search (tSDP_RECORD *p_rec, tSDP_UUID_SEQ *p_seq) +{ + UINT16 xx, yy; + tSDP_ATTRIBUTE *p_attr; + tSDP_RECORD *p_end = &sdp_cb.server_db.record[sdp_cb.server_db.num_records]; + + /* If NULL, start at the beginning, else start at the first specified record */ + if (!p_rec) + p_rec = &sdp_cb.server_db.record[0]; + else + p_rec++; + + /* Look through the records. The spec says that a match occurs if */ + /* the record contains all the passed UUIDs in it. */ + for ( ; p_rec < p_end; p_rec++) + { + for (yy = 0; yy < p_seq->num_uids; yy++) + { + p_attr = &p_rec->attribute[0]; + for (xx = 0; xx < p_rec->num_attributes; xx++, p_attr++) + { + if (p_attr->type == UUID_DESC_TYPE) + { + if (sdpu_compare_uuid_arrays (p_attr->value_ptr, p_attr->len, + &p_seq->uuid_entry[yy].value[0], + p_seq->uuid_entry[yy].len)) + break; + } + else if (p_attr->type == DATA_ELE_SEQ_DESC_TYPE) + { + if (find_uuid_in_seq (p_attr->value_ptr, p_attr->len, + &p_seq->uuid_entry[yy].value[0], + p_seq->uuid_entry[yy].len, 0)) + break; + } + } + /* If any UUID was not found, on to the next record */ + if (xx == p_rec->num_attributes) + break; + } + + /* If every UUID was found in the record, return the record */ + if (yy == p_seq->num_uids) + return (p_rec); + } + + /* If here, no more records found */ + return (NULL); +} + +/******************************************************************************* +** +** Function find_uuid_in_seq +** +** Description This function searches a data element sequenct for a UUID. +** +** Returns TRUE if found, else FALSE +** +*******************************************************************************/ +static BOOLEAN find_uuid_in_seq (UINT8 *p , UINT32 seq_len, UINT8 *p_uuid, + UINT16 uuid_len, int nest_level) +{ + UINT8 *p_end = p + seq_len; + UINT8 type; + UINT32 len; + + /* A little safety check to avoid excessive recursion */ + if (nest_level > 3) + return (FALSE); + + while (p < p_end) + { + type = *p++; + p = sdpu_get_len_from_type (p, type, &len); + type = type >> 3; + if (type == UUID_DESC_TYPE) + { + if (sdpu_compare_uuid_arrays (p, len, p_uuid, uuid_len)) + return (TRUE); + } + else if (type == DATA_ELE_SEQ_DESC_TYPE) + { + if (find_uuid_in_seq (p, len, p_uuid, uuid_len, nest_level + 1)) + return (TRUE); + } + p = p + len; + } + + /* If here, failed to match */ + return (FALSE); +} + +/******************************************************************************* +** +** Function sdp_db_find_record +** +** Description This function searches for a record with a specific handle +** It is passed the handle of the record. +** +** Returns Pointer to the record, or NULL if not found. +** +*******************************************************************************/ +tSDP_RECORD *sdp_db_find_record (UINT32 handle) +{ + tSDP_RECORD *p_rec; + tSDP_RECORD *p_end = &sdp_cb.server_db.record[sdp_cb.server_db.num_records]; + + /* Look through the records for the caller's handle */ + for (p_rec = &sdp_cb.server_db.record[0]; p_rec < p_end; p_rec++) + { + if (p_rec->record_handle == handle) + return (p_rec); + } + + /* Record with that handle not found. */ + return (NULL); +} + +/******************************************************************************* +** +** Function sdp_db_find_attr_in_rec +** +** Description This function searches a record for specific attributes. +** It is passed a pointer to the record. If the record contains +** the specified attribute, (the caller may specify be a range +** of attributes), the attribute is returned. +** +** Returns Pointer to the attribute, or NULL if not found. +** +*******************************************************************************/ +tSDP_ATTRIBUTE *sdp_db_find_attr_in_rec (tSDP_RECORD *p_rec, UINT16 start_attr, + UINT16 end_attr) +{ + tSDP_ATTRIBUTE *p_at; + UINT16 xx; + + /* Note that the attributes in a record are assumed to be in sorted order */ + for (xx = 0, p_at = &p_rec->attribute[0]; xx < p_rec->num_attributes; + xx++, p_at++) + { + if ((p_at->id >= start_attr) && (p_at->id <= end_attr)) + return (p_at); + } + + /* No matching attribute found */ + return (NULL); +} + + +/******************************************************************************* +** +** Function sdp_compose_proto_list +** +** Description This function is called to compose a data sequence from +** protocol element list struct pointer +** +** Returns the length of the data sequence +** +*******************************************************************************/ +static int sdp_compose_proto_list( UINT8 *p, UINT16 num_elem, + tSDP_PROTOCOL_ELEM *p_elem_list) +{ + UINT16 xx, yy, len; + BOOLEAN is_rfcomm_scn; + UINT8 *p_head = p; + UINT8 *p_len; + + /* First, build the protocol list. This consists of a set of data element + ** sequences, one for each layer. Each layer sequence consists of layer's + ** UUID and optional parameters + */ + for (xx = 0; xx < num_elem; xx++, p_elem_list++) + { + len = 3 + (p_elem_list->num_params * 3); + UINT8_TO_BE_STREAM (p, (DATA_ELE_SEQ_DESC_TYPE << 3) | SIZE_IN_NEXT_BYTE); + + p_len = p; + *p++ = (UINT8) len; + + UINT8_TO_BE_STREAM (p, (UUID_DESC_TYPE << 3) | SIZE_TWO_BYTES); + UINT16_TO_BE_STREAM (p, p_elem_list->protocol_uuid); + + if (p_elem_list->protocol_uuid == UUID_PROTOCOL_RFCOMM) + is_rfcomm_scn = TRUE; + else + is_rfcomm_scn = FALSE; + + for (yy = 0; yy < p_elem_list->num_params; yy++) + { + if (is_rfcomm_scn) + { + UINT8_TO_BE_STREAM (p, (UINT_DESC_TYPE << 3) | SIZE_ONE_BYTE); + UINT8_TO_BE_STREAM (p, p_elem_list->params[yy]); + + *p_len -= 1; + } + else + { + UINT8_TO_BE_STREAM (p, (UINT_DESC_TYPE << 3) | SIZE_TWO_BYTES); + UINT16_TO_BE_STREAM (p, p_elem_list->params[yy]); + } + } + } + return (p - p_head); +} + +#endif /* SDP_SERVER_ENABLED == TRUE */ + +/******************************************************************************* +** +** Function SDP_CreateRecord +** +** Description This function is called to create a record in the database. +** This would be through the SDP database maintenance API. The +** record is created empty, teh application should then call +** "add_attribute" to add the record's attributes. +** +** Returns Record handle if OK, else 0. +** +*******************************************************************************/ +UINT32 SDP_CreateRecord (void) +{ +#if SDP_SERVER_ENABLED == TRUE + UINT32 handle; + UINT8 buf[4]; + tSDP_DB *p_db = &sdp_cb.server_db; + + /* First, check if there is a free record */ + if (p_db->num_records < SDP_MAX_RECORDS) + { + memset (&p_db->record[p_db->num_records], 0, + sizeof (tSDP_RECORD)); + + /* We will use a handle of the first unreserved handle plus last record + ** number + 1 */ + if (p_db->num_records) + handle = p_db->record[p_db->num_records - 1].record_handle + 1; + else + handle = 0x10000; + + p_db->record[p_db->num_records].record_handle = handle; + + p_db->num_records++; + SDP_TRACE_DEBUG("SDP_CreateRecord ok, num_records:%d", p_db->num_records); + /* Add the first attribute (the handle) automatically */ + UINT32_TO_BE_FIELD (buf, handle); + SDP_AddAttribute (handle, ATTR_ID_SERVICE_RECORD_HDL, UINT_DESC_TYPE, + 4, buf); + + return (p_db->record[p_db->num_records - 1].record_handle); + } + else SDP_TRACE_ERROR("SDP_CreateRecord fail, exceed maximum records:%d", SDP_MAX_RECORDS); +#endif + return (0); +} + + +/******************************************************************************* +** +** Function SDP_DeleteRecord +** +** Description This function is called to add a record (or all records) +** from the database. This would be through the SDP database +** maintenance API. +** +** If a record handle of 0 is passed, all records are deleted. +** +** Returns TRUE if succeeded, else FALSE +** +*******************************************************************************/ +BOOLEAN SDP_DeleteRecord (UINT32 handle) +{ +#if SDP_SERVER_ENABLED == TRUE + UINT16 xx, yy, zz; + tSDP_RECORD *p_rec = &sdp_cb.server_db.record[0]; + + if (handle == 0 || sdp_cb.server_db.num_records == 0) + { + /* Delete all records in the database */ + sdp_cb.server_db.num_records = 0; + + /* require new DI record to be created in SDP_SetLocalDiRecord */ + sdp_cb.server_db.di_primary_handle = 0; + + return (TRUE); + } + else + { + /* Find the record in the database */ + for (xx = 0; xx < sdp_cb.server_db.num_records; xx++, p_rec++) + { + if (p_rec->record_handle == handle) + { + /* Found it. Shift everything up one */ + for (yy = xx; yy < sdp_cb.server_db.num_records; yy++, p_rec++) + { + *p_rec = *(p_rec + 1); + + /* Adjust the attribute value pointer for each attribute */ + for (zz = 0; zz < p_rec->num_attributes; zz++) + p_rec->attribute[zz].value_ptr -= sizeof(tSDP_RECORD); + } + + sdp_cb.server_db.num_records--; + + SDP_TRACE_DEBUG("SDP_DeleteRecord ok, num_records:%d", sdp_cb.server_db.num_records); + /* if we're deleting the primary DI record, clear the */ + /* value in the control block */ + if( sdp_cb.server_db.di_primary_handle == handle ) + { + sdp_cb.server_db.di_primary_handle = 0; + } + + return (TRUE); + } + } + } +#endif + return (FALSE); +} + + +/******************************************************************************* +** +** Function SDP_AddAttribute +** +** Description This function is called to add an attribute to a record. +** This would be through the SDP database maintenance API. +** If the attribute already exists in the record, it is replaced +** with the new value. +** +** NOTE Attribute values must be passed as a Big Endian stream. +** +** Returns TRUE if added OK, else FALSE +** +*******************************************************************************/ +BOOLEAN SDP_AddAttribute (UINT32 handle, UINT16 attr_id, UINT8 attr_type, + UINT32 attr_len, UINT8 *p_val) +{ +#if SDP_SERVER_ENABLED == TRUE + UINT16 xx, yy, zz; + tSDP_RECORD *p_rec = &sdp_cb.server_db.record[0]; + +#if (BT_TRACE_VERBOSE == TRUE) + if (sdp_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) + { + if ((attr_type == UINT_DESC_TYPE) || + (attr_type == TWO_COMP_INT_DESC_TYPE) || + (attr_type == UUID_DESC_TYPE) || + (attr_type == DATA_ELE_SEQ_DESC_TYPE) || + (attr_type == DATA_ELE_ALT_DESC_TYPE)) + { + UINT8 num_array[400]; + UINT32 i; + UINT32 len = (attr_len > 200) ? 200 : attr_len; + + num_array[0] ='\0'; + for (i = 0; i < len; i++) + { + sprintf((char *)&num_array[i*2],"%02X",(UINT8)(p_val[i])); + } + SDP_TRACE_DEBUG("SDP_AddAttribute: handle:%X, id:%04X, type:%d, len:%d, p_val:%p, *p_val:%s", + handle,attr_id,attr_type,attr_len,p_val,num_array); + } + else if (attr_type == BOOLEAN_DESC_TYPE) + { + SDP_TRACE_DEBUG("SDP_AddAttribute: handle:%X, id:%04X, type:%d, len:%d, p_val:%p, *p_val:%d", + handle,attr_id,attr_type,attr_len,p_val,*p_val); + } + else + { + SDP_TRACE_DEBUG("SDP_AddAttribute: handle:%X, id:%04X, type:%d, len:%d, p_val:%p, *p_val:%s", + handle,attr_id,attr_type,attr_len,p_val,p_val); + } + } +#endif + + /* Find the record in the database */ + for (zz = 0; zz < sdp_cb.server_db.num_records; zz++, p_rec++) + { + if (p_rec->record_handle == handle) + { + tSDP_ATTRIBUTE *p_attr = &p_rec->attribute[0]; + + /* Found the record. Now, see if the attribute already exists */ + for (xx = 0; xx < p_rec->num_attributes; xx++, p_attr++) + { + /* The attribute exists. replace it */ + if (p_attr->id == attr_id) + { + SDP_DeleteAttribute (handle, attr_id); + break; + } + if (p_attr->id > attr_id) + break; + } + + if (p_rec->num_attributes == SDP_MAX_REC_ATTR) + return (FALSE); + + /* If not found, see if we can allocate a new entry */ + if (xx == p_rec->num_attributes) + p_attr = &p_rec->attribute[p_rec->num_attributes]; + else + { + /* Since the attributes are kept in sorted order, insert ours here */ + for (yy = p_rec->num_attributes; yy > xx; yy--) + p_rec->attribute[yy] = p_rec->attribute[yy - 1]; + } + + p_attr->id = attr_id; + p_attr->type = attr_type; + p_attr->len = attr_len; + + if (p_rec->free_pad_ptr + attr_len >= SDP_MAX_PAD_LEN) + { + /* do truncate only for text string type descriptor */ + if (attr_type == TEXT_STR_DESC_TYPE) + { + SDP_TRACE_WARNING("SDP_AddAttribute: attr_len:%d too long. truncate to (%d)", + attr_len, SDP_MAX_PAD_LEN - p_rec->free_pad_ptr ); + + attr_len = SDP_MAX_PAD_LEN - p_rec->free_pad_ptr; + p_val[SDP_MAX_PAD_LEN - p_rec->free_pad_ptr] = '\0'; + p_val[SDP_MAX_PAD_LEN - p_rec->free_pad_ptr+1] = '\0'; + } + else + attr_len = 0; + } + + if ((attr_len > 0) && (p_val != 0)) + { + p_attr->len = attr_len; + memcpy (&p_rec->attr_pad[p_rec->free_pad_ptr], p_val, (size_t)attr_len); + p_attr->value_ptr = &p_rec->attr_pad[p_rec->free_pad_ptr]; + p_rec->free_pad_ptr += attr_len; + } + else if ((attr_len == 0 && p_attr->len != 0) || /* if truncate to 0 length, simply don't add */ + p_val == 0) + { + SDP_TRACE_ERROR("SDP_AddAttribute fail, length exceed maximum: ID %d: attr_len:%d ", + attr_id, attr_len ); + p_attr->id = p_attr->type = p_attr->len = 0; + return (FALSE); + } + p_rec->num_attributes++; + return (TRUE); + } + } +#endif + return (FALSE); +} + + +/******************************************************************************* +** +** Function SDP_AddSequence +** +** Description This function is called to add a sequence to a record. +** This would be through the SDP database maintenance API. +** If the sequence already exists in the record, it is replaced +** with the new sequence. +** +** NOTE Element values must be passed as a Big Endian stream. +** +** Returns TRUE if added OK, else FALSE +** +*******************************************************************************/ +BOOLEAN SDP_AddSequence (UINT32 handle, UINT16 attr_id, UINT16 num_elem, + UINT8 type[], UINT8 len[], UINT8 *p_val[]) +{ +#if SDP_SERVER_ENABLED == TRUE + UINT16 xx; + UINT8 *p_buff; + UINT8 *p; + UINT8 *p_head; + BOOLEAN result; + + if ((p_buff = (UINT8 *) GKI_getbuf(sizeof(UINT8) * SDP_MAX_ATTR_LEN * 2)) == NULL) + { + SDP_TRACE_ERROR("SDP_AddSequence cannot get a buffer!"); + return (FALSE); + } + p = p_buff; + + /* First, build the sequence */ + for (xx = 0; xx < num_elem; xx++) + { + p_head = p; + switch (len[xx]) + { + case 1: + UINT8_TO_BE_STREAM (p, (type[xx] << 3) | SIZE_ONE_BYTE); + break; + case 2: + UINT8_TO_BE_STREAM (p, (type[xx] << 3) | SIZE_TWO_BYTES); + break; + case 4: + UINT8_TO_BE_STREAM (p, (type[xx] << 3) | SIZE_FOUR_BYTES); + break; + case 8: + UINT8_TO_BE_STREAM (p, (type[xx] << 3) | SIZE_EIGHT_BYTES); + break; + case 16: + UINT8_TO_BE_STREAM (p, (type[xx] << 3) | SIZE_SIXTEEN_BYTES); + break; + default: + UINT8_TO_BE_STREAM (p, (type[xx] << 3) | SIZE_IN_NEXT_BYTE); + UINT8_TO_BE_STREAM (p, len[xx]); + break; + } + + ARRAY_TO_BE_STREAM (p, p_val[xx], len[xx]); + + if (p - p_buff > SDP_MAX_ATTR_LEN) + { + /* go back to before we add this element */ + p = p_head; + if(p_head == p_buff) + { + /* the first element exceed the max length */ + SDP_TRACE_ERROR ("SDP_AddSequence - too long(attribute is not added)!!"); + GKI_freebuf(p_buff); + return FALSE; + } + else + SDP_TRACE_ERROR ("SDP_AddSequence - too long, add %d elements of %d", xx, num_elem); + break; + } + } + result = SDP_AddAttribute (handle, attr_id, DATA_ELE_SEQ_DESC_TYPE,(UINT32) (p - p_buff), p_buff); + GKI_freebuf(p_buff); + return result; +#else /* SDP_SERVER_ENABLED == FALSE */ + return (FALSE); +#endif +} + + +/******************************************************************************* +** +** Function SDP_AddUuidSequence +** +** Description This function is called to add a UUID sequence to a record. +** This would be through the SDP database maintenance API. +** If the sequence already exists in the record, it is replaced +** with the new sequence. +** +** Returns TRUE if added OK, else FALSE +** +*******************************************************************************/ +BOOLEAN SDP_AddUuidSequence (UINT32 handle, UINT16 attr_id, UINT16 num_uuids, + UINT16 *p_uuids) +{ +#if SDP_SERVER_ENABLED == TRUE + UINT16 xx; + UINT8 *p_buff; + UINT8 *p; + INT32 max_len = SDP_MAX_ATTR_LEN -3; + BOOLEAN result; + + if ((p_buff = (UINT8 *) GKI_getbuf(sizeof(UINT8) * SDP_MAX_ATTR_LEN * 2)) == NULL) + { + SDP_TRACE_ERROR("SDP_AddUuidSequence cannot get a buffer!"); + return (FALSE); + } + p = p_buff; + + /* First, build the sequence */ + for (xx = 0; xx < num_uuids ; xx++, p_uuids++) + { + UINT8_TO_BE_STREAM (p, (UUID_DESC_TYPE << 3) | SIZE_TWO_BYTES); + UINT16_TO_BE_STREAM (p, *p_uuids); + + if((p - p_buff) > max_len) + { + SDP_TRACE_WARNING ("SDP_AddUuidSequence - too long, add %d uuids of %d", xx, num_uuids); + break; + } + } + + result = SDP_AddAttribute (handle, attr_id, DATA_ELE_SEQ_DESC_TYPE,(UINT32) (p - p_buff), p_buff); + GKI_freebuf(p_buff); + return result; +#else /* SDP_SERVER_ENABLED == FALSE */ + return (FALSE); +#endif +} + +/******************************************************************************* +** +** Function SDP_AddProtocolList +** +** Description This function is called to add a protocol descriptor list to +** a record. This would be through the SDP database maintenance API. +** If the protocol list already exists in the record, it is replaced +** with the new list. +** +** Returns TRUE if added OK, else FALSE +** +*******************************************************************************/ +BOOLEAN SDP_AddProtocolList (UINT32 handle, UINT16 num_elem, + tSDP_PROTOCOL_ELEM *p_elem_list) +{ +#if SDP_SERVER_ENABLED == TRUE + UINT8 *p_buff; + int offset; + BOOLEAN result; + + if ((p_buff = (UINT8 *) GKI_getbuf(sizeof(UINT8) * SDP_MAX_ATTR_LEN * 2)) == NULL) + { + SDP_TRACE_ERROR("SDP_AddProtocolList cannot get a buffer!"); + return (FALSE); + } + + offset = sdp_compose_proto_list(p_buff, num_elem, p_elem_list); + result = SDP_AddAttribute (handle, ATTR_ID_PROTOCOL_DESC_LIST,DATA_ELE_SEQ_DESC_TYPE, (UINT32) offset, p_buff); + GKI_freebuf(p_buff); + return result; +#else /* SDP_SERVER_ENABLED == FALSE */ + return (FALSE); +#endif +} + + +/******************************************************************************* +** +** Function SDP_AddAdditionProtoLists +** +** Description This function is called to add a protocol descriptor list to +** a record. This would be through the SDP database maintenance API. +** If the protocol list already exists in the record, it is replaced +** with the new list. +** +** Returns TRUE if added OK, else FALSE +** +*******************************************************************************/ +BOOLEAN SDP_AddAdditionProtoLists (UINT32 handle, UINT16 num_elem, + tSDP_PROTO_LIST_ELEM *p_proto_list) +{ +#if SDP_SERVER_ENABLED == TRUE + UINT16 xx; + UINT8 *p_buff; + UINT8 *p; + UINT8 *p_len; + int offset; + BOOLEAN result; + + if ((p_buff = (UINT8 *) GKI_getbuf(sizeof(UINT8) * SDP_MAX_ATTR_LEN * 2)) == NULL) + { + SDP_TRACE_ERROR("SDP_AddAdditionProtoLists cannot get a buffer!"); + return (FALSE); + } + p = p_buff; + + /* for each ProtocolDescriptorList */ + for (xx = 0; xx < num_elem; xx++, p_proto_list++) + { + UINT8_TO_BE_STREAM (p, (DATA_ELE_SEQ_DESC_TYPE << 3) | SIZE_IN_NEXT_BYTE); + p_len = p++; + + offset = sdp_compose_proto_list(p, p_proto_list->num_elems, + p_proto_list->list_elem); + p += offset; + + *p_len = (UINT8)(p - p_len - 1); + } + result = SDP_AddAttribute (handle, ATTR_ID_ADDITION_PROTO_DESC_LISTS,DATA_ELE_SEQ_DESC_TYPE, + (UINT32) (p - p_buff), p_buff); + GKI_freebuf(p_buff); + return result; + +#else /* SDP_SERVER_ENABLED == FALSE */ + return (FALSE); +#endif +} + +/******************************************************************************* +** +** Function SDP_AddProfileDescriptorList +** +** Description This function is called to add a profile descriptor list to +** a record. This would be through the SDP database maintenance API. +** If the version already exists in the record, it is replaced +** with the new one. +** +** Returns TRUE if added OK, else FALSE +** +*******************************************************************************/ +BOOLEAN SDP_AddProfileDescriptorList (UINT32 handle, UINT16 profile_uuid, + UINT16 version) +{ +#if SDP_SERVER_ENABLED == TRUE + UINT8 *p_buff; + UINT8 *p; + BOOLEAN result; + + if ((p_buff = (UINT8 *) GKI_getbuf(sizeof(UINT8) * SDP_MAX_ATTR_LEN)) == NULL) + { + SDP_TRACE_ERROR("SDP_AddProfileDescriptorList cannot get a buffer!"); + return (FALSE); + } + p = p_buff+2; + + /* First, build the profile descriptor list. This consists of a data element sequence. */ + /* The sequence consists of profile's UUID and version number */ + UINT8_TO_BE_STREAM (p, (UUID_DESC_TYPE << 3) | SIZE_TWO_BYTES); + UINT16_TO_BE_STREAM (p, profile_uuid); + + UINT8_TO_BE_STREAM (p, (UINT_DESC_TYPE << 3) | SIZE_TWO_BYTES); + UINT16_TO_BE_STREAM (p, version); + + /* Add in type and length fields */ + *p_buff = (UINT8) ((DATA_ELE_SEQ_DESC_TYPE << 3) | SIZE_IN_NEXT_BYTE); + *(p_buff+1) = (UINT8) (p - (p_buff+2)); + + result = SDP_AddAttribute (handle, ATTR_ID_BT_PROFILE_DESC_LIST,DATA_ELE_SEQ_DESC_TYPE, (UINT32) (p - p_buff), p_buff); + GKI_freebuf(p_buff); + return result; + +#else /* SDP_SERVER_ENABLED == FALSE */ + return (FALSE); +#endif +} + + +/******************************************************************************* +** +** Function SDP_AddLanguageBaseAttrIDList +** +** Description This function is called to add a language base attr list to +** a record. This would be through the SDP database maintenance API. +** If the version already exists in the record, it is replaced +** with the new one. +** +** Returns TRUE if added OK, else FALSE +** +*******************************************************************************/ +BOOLEAN SDP_AddLanguageBaseAttrIDList (UINT32 handle, UINT16 lang, + UINT16 char_enc, UINT16 base_id) +{ +#if SDP_SERVER_ENABLED == TRUE + UINT8 *p_buff; + UINT8 *p; + BOOLEAN result; + + if ((p_buff = (UINT8 *) GKI_getbuf(sizeof(UINT8) * SDP_MAX_ATTR_LEN)) == NULL) + { + SDP_TRACE_ERROR("SDP_AddLanguageBaseAttrIDList cannot get a buffer!"); + return (FALSE); + } + p = p_buff; + + /* First, build the language base descriptor list. This consists of a data */ + /* element sequence. The sequence consists of 9 bytes (3 UINt16 fields) */ + UINT8_TO_BE_STREAM (p, (UINT_DESC_TYPE << 3) | SIZE_TWO_BYTES); + UINT16_TO_BE_STREAM (p, lang); + + UINT8_TO_BE_STREAM (p, (UINT_DESC_TYPE << 3) | SIZE_TWO_BYTES); + UINT16_TO_BE_STREAM (p, char_enc); + + UINT8_TO_BE_STREAM (p, (UINT_DESC_TYPE << 3) | SIZE_TWO_BYTES); + UINT16_TO_BE_STREAM (p, base_id); + + result = SDP_AddAttribute (handle, ATTR_ID_LANGUAGE_BASE_ATTR_ID_LIST,DATA_ELE_SEQ_DESC_TYPE, + (UINT32) (p - p_buff), p_buff); + GKI_freebuf(p_buff); + return result; +#else /* SDP_SERVER_ENABLED == FALSE */ + return (FALSE); +#endif +} + + +/******************************************************************************* +** +** Function SDP_AddServiceClassIdList +** +** Description This function is called to add a service list to a record. +** This would be through the SDP database maintenance API. +** If the service list already exists in the record, it is replaced +** with the new list. +** +** Returns TRUE if added OK, else FALSE +** +*******************************************************************************/ +BOOLEAN SDP_AddServiceClassIdList (UINT32 handle, UINT16 num_services, + UINT16 *p_service_uuids) +{ +#if SDP_SERVER_ENABLED == TRUE + UINT16 xx; + UINT8 *p_buff; + UINT8 *p; + BOOLEAN result; + + if ((p_buff = (UINT8 *) GKI_getbuf(sizeof(UINT8) * SDP_MAX_ATTR_LEN * 2)) == NULL) + { + SDP_TRACE_ERROR("SDP_AddServiceClassIdList cannot get a buffer!"); + return (FALSE); + } + p = p_buff; + + for (xx = 0; xx < num_services; xx++, p_service_uuids++) + { + UINT8_TO_BE_STREAM (p, (UUID_DESC_TYPE << 3) | SIZE_TWO_BYTES); + UINT16_TO_BE_STREAM (p, *p_service_uuids); + } + + result = SDP_AddAttribute (handle, ATTR_ID_SERVICE_CLASS_ID_LIST,DATA_ELE_SEQ_DESC_TYPE, + (UINT32) (p - p_buff), p_buff); + GKI_freebuf(p_buff); + return result; +#else /* SDP_SERVER_ENABLED == FALSE */ + return (FALSE); +#endif +} + + +/******************************************************************************* +** +** Function SDP_DeleteAttribute +** +** Description This function is called to delete an attribute from a record. +** This would be through the SDP database maintenance API. +** +** Returns TRUE if deleted OK, else FALSE if not found +** +*******************************************************************************/ +BOOLEAN SDP_DeleteAttribute (UINT32 handle, UINT16 attr_id) +{ +#if SDP_SERVER_ENABLED == TRUE + UINT16 xx, yy; + tSDP_RECORD *p_rec = &sdp_cb.server_db.record[0]; + UINT8 *pad_ptr; + UINT32 len; /* Number of bytes in the entry */ + + /* Find the record in the database */ + for (xx = 0; xx < sdp_cb.server_db.num_records; xx++, p_rec++) + { + if (p_rec->record_handle == handle) + { + tSDP_ATTRIBUTE *p_attr = &p_rec->attribute[0]; + + SDP_TRACE_API("Deleting attr_id 0x%04x for handle 0x%x", attr_id, handle); + /* Found it. Now, find the attribute */ + for (xx = 0; xx < p_rec->num_attributes; xx++, p_attr++) + { + if (p_attr->id == attr_id) + { + pad_ptr = p_attr->value_ptr; + len = p_attr->len; + + if (len) + { + for (yy = 0; yy < p_rec->num_attributes; yy++) + { + if( p_rec->attribute[yy].value_ptr > pad_ptr ) + p_rec->attribute[yy].value_ptr -= len; + } + } + + /* Found it. Shift everything up one */ + p_rec->num_attributes--; + + for (yy = xx; yy < p_rec->num_attributes; yy++, p_attr++) + { + *p_attr = *(p_attr + 1); + } + + /* adjust attribute values if needed */ + if (len) + { + xx = (p_rec->free_pad_ptr - ((pad_ptr+len) - + &p_rec->attr_pad[0])); + for( yy=0; yyfree_pad_ptr -= len; + } + return (TRUE); + } + } + } + } +#endif + /* If here, not found */ + return (FALSE); +} + +/******************************************************************************* +** +** Function SDP_ReadRecord +** +** Description This function is called to get the raw data of the record +** with the given handle from the database. +** +** Returns -1, if the record is not found. +** Otherwise, the offset (0 or 1) to start of data in p_data. +** +** The size of data copied into p_data is in *p_data_len. +** +*******************************************************************************/ +#if (SDP_RAW_DATA_INCLUDED == TRUE) +INT32 SDP_ReadRecord(UINT32 handle, UINT8 *p_data, INT32 *p_data_len) +{ + INT32 len = 0; /* Number of bytes in the entry */ + INT32 offset = -1; /* default to not found */ +#if SDP_SERVER_ENABLED == TRUE + tSDP_RECORD *p_rec; + UINT16 start = 0; + UINT16 end = 0xffff; + tSDP_ATTRIBUTE *p_attr; + UINT16 rem_len; + UINT8 *p_rsp; + + /* Find the record in the database */ + p_rec = sdp_db_find_record(handle); + if(p_rec && p_data && p_data_len) + { + p_rsp = &p_data[3]; + while ( (p_attr = sdp_db_find_attr_in_rec (p_rec, start, end)) != NULL) + { + /* Check if attribute fits. Assume 3-byte value type/length */ + rem_len = *p_data_len - (UINT16) (p_rsp - p_data); + + if (p_attr->len > (UINT32)(rem_len - 6)) + break; + + p_rsp = sdpu_build_attrib_entry (p_rsp, p_attr); + + /* next attr id */ + start = p_attr->id + 1; + } + len = (INT32) (p_rsp - p_data); + + /* Put in the sequence header (2 or 3 bytes) */ + if (len > 255) + { + offset = 0; + p_data[0] = (UINT8) ((DATA_ELE_SEQ_DESC_TYPE << 3) | SIZE_IN_NEXT_WORD); + p_data[1] = (UINT8) ((len - 3) >> 8); + p_data[2] = (UINT8) (len - 3); + } + else + { + offset = 1; + + p_data[1] = (UINT8) ((DATA_ELE_SEQ_DESC_TYPE << 3) | SIZE_IN_NEXT_BYTE); + p_data[2] = (UINT8) (len - 3); + + len--; + } + *p_data_len = len; + } +#endif + /* If here, not found */ + return (offset); +} +#endif diff --git a/components/bt/bluedroid/stack/sdp/sdp_discovery.c b/components/bt/bluedroid/stack/sdp/sdp_discovery.c new file mode 100755 index 0000000000..646a62dd3d --- /dev/null +++ b/components/bt/bluedroid/stack/sdp/sdp_discovery.c @@ -0,0 +1,1093 @@ +/****************************************************************************** + * + * Copyright (C) 1999-2012 Broadcom Corporation + * + * 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 SDP discovery functions + * + ******************************************************************************/ + +#include +#include +#include + +#include "bt_target.h" +#include "gki.h" +#include "l2cdefs.h" +#include "hcidefs.h" +#include "hcimsgs.h" +#include "sdp_api.h" +#include "sdpint.h" +#include "btu.h" +#include "btm_api.h" + + +#ifndef SDP_DEBUG_RAW +#define SDP_DEBUG_RAW FALSE +#endif + +/********************************************************************************/ +/* L O C A L F U N C T I O N P R O T O T Y P E S */ +/********************************************************************************/ +#if SDP_CLIENT_ENABLED == TRUE +static void process_service_search_rsp (tCONN_CB *p_ccb, UINT8 *p_reply); +static void process_service_attr_rsp (tCONN_CB *p_ccb, UINT8 *p_reply); +static void process_service_search_attr_rsp (tCONN_CB *p_ccb, UINT8 *p_reply); +static UINT8 *save_attr_seq (tCONN_CB *p_ccb, UINT8 *p, UINT8 *p_msg_end); +static tSDP_DISC_REC *add_record (tSDP_DISCOVERY_DB *p_db, BD_ADDR p_bda); +static UINT8 *add_attr (UINT8 *p, tSDP_DISCOVERY_DB *p_db, tSDP_DISC_REC *p_rec, + UINT16 attr_id, tSDP_DISC_ATTR *p_parent_attr, UINT8 nest_level); + +/* Safety check in case we go crazy */ +#define MAX_NEST_LEVELS 5 + + +/******************************************************************************* +** +** Function sdpu_build_uuid_seq +** +** Description This function builds a UUID sequence from the list of +** passed UUIDs. It is also passed the address of the output +** buffer. +** +** Returns Pointer to next byte in the output buffer. +** +*******************************************************************************/ +static UINT8 *sdpu_build_uuid_seq (UINT8 *p_out, UINT16 num_uuids, tSDP_UUID *p_uuid_list) +{ + UINT16 xx; + UINT8 *p_len; + + /* First thing is the data element header */ + UINT8_TO_BE_STREAM (p_out, (DATA_ELE_SEQ_DESC_TYPE << 3) | SIZE_IN_NEXT_BYTE); + + /* Remember where the length goes. Leave space for it. */ + p_len = p_out; + p_out += 1; + + /* Now, loop through and put in all the UUID(s) */ + for (xx = 0; xx < num_uuids; xx++, p_uuid_list++) + { + if (p_uuid_list->len == 2) + { + UINT8_TO_BE_STREAM (p_out, (UUID_DESC_TYPE << 3) | SIZE_TWO_BYTES); + UINT16_TO_BE_STREAM (p_out, p_uuid_list->uu.uuid16); + } + else if (p_uuid_list->len == 4) + { + UINT8_TO_BE_STREAM (p_out, (UUID_DESC_TYPE << 3) | SIZE_FOUR_BYTES); + UINT32_TO_BE_STREAM (p_out, p_uuid_list->uu.uuid32); + } + else + { + UINT8_TO_BE_STREAM (p_out, (UUID_DESC_TYPE << 3) | SIZE_SIXTEEN_BYTES); + ARRAY_TO_BE_STREAM (p_out, p_uuid_list->uu.uuid128, p_uuid_list->len); + } + } + + /* Now, put in the length */ + xx = (UINT16)(p_out - p_len - 1); + UINT8_TO_BE_STREAM (p_len, xx); + + return (p_out); +} + +/******************************************************************************* +** +** Function sdp_snd_service_search_req +** +** Description Send a service search request to the SDP server. +** +** Returns void +** +*******************************************************************************/ +static void sdp_snd_service_search_req(tCONN_CB *p_ccb, UINT8 cont_len, UINT8 * p_cont) +{ + UINT8 *p, *p_start, *p_param_len; + BT_HDR *p_cmd; + UINT16 param_len; + + /* Get a buffer to send the packet to L2CAP */ + if ((p_cmd = (BT_HDR *) GKI_getpoolbuf (SDP_POOL_ID)) == NULL) + { + sdp_disconnect (p_ccb, SDP_NO_RESOURCES); + return; + } + + p_cmd->offset = L2CAP_MIN_OFFSET; + p = p_start = (UINT8 *)(p_cmd + 1) + L2CAP_MIN_OFFSET; + + /* Build a service search request packet */ + UINT8_TO_BE_STREAM (p, SDP_PDU_SERVICE_SEARCH_REQ); + UINT16_TO_BE_STREAM (p, p_ccb->transaction_id); + p_ccb->transaction_id++; + + /* Skip the length, we need to add it at the end */ + p_param_len = p; + p += 2; + + /* Build the UID sequence. */ +#if (defined(SDP_BROWSE_PLUS) && SDP_BROWSE_PLUS == TRUE) + p = sdpu_build_uuid_seq (p, 1, &p_ccb->p_db->uuid_filters[p_ccb->cur_uuid_idx]); +#else + p = sdpu_build_uuid_seq (p, p_ccb->p_db->num_uuid_filters, p_ccb->p_db->uuid_filters); +#endif + + /* Set max service record count */ + UINT16_TO_BE_STREAM (p, sdp_cb.max_recs_per_search); + + /* Set continuation state */ + UINT8_TO_BE_STREAM (p, cont_len); + + /* if this is not the first request */ + if(cont_len && p_cont) + { + memcpy(p, p_cont, cont_len); + p += cont_len; + } + + /* Go back and put the parameter length into the buffer */ + param_len = (UINT16)(p - p_param_len - 2); + UINT16_TO_BE_STREAM (p_param_len, param_len); + + p_ccb->disc_state = SDP_DISC_WAIT_HANDLES; + + /* Set the length of the SDP data in the buffer */ + p_cmd->len = (UINT16)(p - p_start); + +#if (SDP_DEBUG_RAW == TRUE) + SDP_TRACE_WARNING("sdp_snd_service_search_req cont_len :%d disc_state:%d",cont_len, p_ccb->disc_state); +#endif + + + L2CA_DataWrite (p_ccb->connection_id, p_cmd); + + /* Start inactivity timer */ + btu_start_timer (&p_ccb->timer_entry, BTU_TTYPE_SDP, SDP_INACT_TIMEOUT); + +} + +/******************************************************************************* +** +** Function sdp_disc_connected +** +** Description This function is called when an SDP discovery attempt is +** connected. +** +** Returns void +** +*******************************************************************************/ +void sdp_disc_connected (tCONN_CB *p_ccb) +{ + if (p_ccb->is_attr_search) + { + p_ccb->disc_state = SDP_DISC_WAIT_SEARCH_ATTR; + + process_service_search_attr_rsp (p_ccb, NULL); + } + else + { + /* First step is to get a list of the handles from the server. */ + /* We are not searching for a specific attribute, so we will */ + /* first search for the service, then get all attributes of it */ + + p_ccb->num_handles = 0; + sdp_snd_service_search_req(p_ccb, 0, NULL); + } + +} + +/******************************************************************************* +** +** Function sdp_disc_server_rsp +** +** Description This function is called when there is a response from +** the server. +** +** Returns void +** +*******************************************************************************/ +void sdp_disc_server_rsp (tCONN_CB *p_ccb, BT_HDR *p_msg) +{ + UINT8 *p, rsp_pdu; + BOOLEAN invalid_pdu = TRUE; + +#if (SDP_DEBUG_RAW == TRUE) + SDP_TRACE_WARNING("sdp_disc_server_rsp disc_state:%d", p_ccb->disc_state); +#endif + + /* stop inactivity timer when we receive a response */ + btu_stop_timer (&p_ccb->timer_entry); + + /* Got a reply!! Check what we got back */ + p = (UINT8 *)(p_msg + 1) + p_msg->offset; + + BE_STREAM_TO_UINT8 (rsp_pdu, p); + + p_msg->len--; + + switch (rsp_pdu) + { + case SDP_PDU_SERVICE_SEARCH_RSP: + if (p_ccb->disc_state == SDP_DISC_WAIT_HANDLES) + { + process_service_search_rsp (p_ccb, p); + invalid_pdu = FALSE; + } + break; + + case SDP_PDU_SERVICE_ATTR_RSP: + if (p_ccb->disc_state == SDP_DISC_WAIT_ATTR) + { + process_service_attr_rsp (p_ccb, p); + invalid_pdu = FALSE; + } + break; + + case SDP_PDU_SERVICE_SEARCH_ATTR_RSP: + if (p_ccb->disc_state == SDP_DISC_WAIT_SEARCH_ATTR) + { + process_service_search_attr_rsp (p_ccb, p); + invalid_pdu = FALSE; + } + break; + } + + if (invalid_pdu) + { + SDP_TRACE_WARNING ("SDP - Unexp. PDU: %d in state: %d", rsp_pdu, p_ccb->disc_state); + sdp_disconnect (p_ccb, SDP_GENERIC_ERROR); + } +} + +/****************************************************************************** +** +** Function process_service_search_rsp +** +** Description This function is called when there is a search response from +** the server. +** +** Returns void +** +*******************************************************************************/ +static void process_service_search_rsp (tCONN_CB *p_ccb, UINT8 *p_reply) +{ + UINT16 xx; + UINT16 total, cur_handles, orig; + UINT8 cont_len; + + /* Skip transaction, and param len */ + p_reply += 4; + BE_STREAM_TO_UINT16 (total, p_reply); + BE_STREAM_TO_UINT16 (cur_handles, p_reply); + + orig = p_ccb->num_handles; + p_ccb->num_handles += cur_handles; + if (p_ccb->num_handles == 0) + { + SDP_TRACE_WARNING ("SDP - Rcvd ServiceSearchRsp, no matches"); + sdp_disconnect (p_ccb, SDP_NO_RECS_MATCH); + return; + } + + /* Save the handles that match. We will can only process a certain number. */ + if (total > sdp_cb.max_recs_per_search) + total = sdp_cb.max_recs_per_search; + if (p_ccb->num_handles > sdp_cb.max_recs_per_search) + p_ccb->num_handles = sdp_cb.max_recs_per_search; + + for (xx = orig; xx < p_ccb->num_handles; xx++) + BE_STREAM_TO_UINT32 (p_ccb->handles[xx], p_reply); + + BE_STREAM_TO_UINT8 (cont_len, p_reply); + if(cont_len != 0) + { + if(cont_len > SDP_MAX_CONTINUATION_LEN) + { + sdp_disconnect (p_ccb, SDP_INVALID_CONT_STATE); + return; + } + /* stay in the same state */ + sdp_snd_service_search_req(p_ccb, cont_len, p_reply); + } + else + { + /* change state */ + p_ccb->disc_state = SDP_DISC_WAIT_ATTR; + + /* Kick off the first attribute request */ + process_service_attr_rsp (p_ccb, NULL); + } +} + +/******************************************************************************* +** +** Function sdp_copy_raw_data +** +** Description copy the raw data +** +** +** Returns void +** +*******************************************************************************/ +#if (SDP_RAW_DATA_INCLUDED == TRUE) +static void sdp_copy_raw_data (tCONN_CB *p_ccb, BOOLEAN offset) +{ + unsigned int cpy_len; + UINT32 list_len; + UINT8 *p; + UINT8 type; + +#if (SDP_DEBUG_RAW == TRUE) + UINT8 num_array[SDP_MAX_LIST_BYTE_COUNT]; + UINT32 i; + + for (i = 0; i < p_ccb->list_len; i++) + { + sprintf((char *)&num_array[i*2],"%02X",(UINT8)(p_ccb->rsp_list[i])); + } + SDP_TRACE_WARNING("result :%s",num_array); +#endif + + if(p_ccb->p_db->raw_data) + { + cpy_len = p_ccb->p_db->raw_size - p_ccb->p_db->raw_used; + list_len = p_ccb->list_len; + p = &p_ccb->rsp_list[0]; + + if(offset) + { + type = *p++; + p = sdpu_get_len_from_type (p, type, &list_len); + } + if(list_len && list_len < cpy_len ) + { + cpy_len = list_len; + } +#if (SDP_DEBUG_RAW == TRUE) + SDP_TRACE_WARNING("list_len :%d cpy_len:%d raw_size:%d raw_used:%d", + list_len, cpy_len, p_ccb->p_db->raw_size, p_ccb->p_db->raw_used); +#endif + memcpy (&p_ccb->p_db->raw_data[p_ccb->p_db->raw_used], p, cpy_len); + p_ccb->p_db->raw_used += cpy_len; + } +} +#endif + +/******************************************************************************* +** +** Function process_service_attr_rsp +** +** Description This function is called when there is a attribute response from +** the server. +** +** Returns void +** +*******************************************************************************/ +static void process_service_attr_rsp (tCONN_CB *p_ccb, UINT8 *p_reply) +{ + UINT8 *p_start, *p_param_len; + UINT16 param_len, list_byte_count; + BOOLEAN cont_request_needed = FALSE; + +#if (SDP_DEBUG_RAW == TRUE) + SDP_TRACE_WARNING("process_service_attr_rsp raw inc:%d", + SDP_RAW_DATA_INCLUDED); +#endif + /* If p_reply is NULL, we were called after the records handles were read */ + if (p_reply) + { +#if (SDP_DEBUG_RAW == TRUE) + SDP_TRACE_WARNING("ID & len: 0x%02x-%02x-%02x-%02x", + p_reply[0], p_reply[1], p_reply[2], p_reply[3]); +#endif + /* Skip transaction ID and length */ + p_reply += 4; + + BE_STREAM_TO_UINT16 (list_byte_count, p_reply); +#if (SDP_DEBUG_RAW == TRUE) + SDP_TRACE_WARNING("list_byte_count:%d", list_byte_count); +#endif + + /* Copy the response to the scratchpad. First, a safety check on the length */ + if ((p_ccb->list_len + list_byte_count) > SDP_MAX_LIST_BYTE_COUNT) + { + sdp_disconnect (p_ccb, SDP_INVALID_PDU_SIZE); + return; + } + +#if (SDP_DEBUG_RAW == TRUE) + SDP_TRACE_WARNING("list_len: %d, list_byte_count: %d", + p_ccb->list_len, list_byte_count); +#endif + if (p_ccb->rsp_list == NULL) + { + p_ccb->rsp_list = (UINT8 *)GKI_getbuf (SDP_MAX_LIST_BYTE_COUNT); + if (p_ccb->rsp_list == NULL) + { + SDP_TRACE_ERROR ("SDP - no gki buf to save rsp"); + sdp_disconnect (p_ccb, SDP_NO_RESOURCES); + return; + } + } + memcpy (&p_ccb->rsp_list[p_ccb->list_len], p_reply, list_byte_count); + p_ccb->list_len += list_byte_count; + p_reply += list_byte_count; +#if (SDP_DEBUG_RAW == TRUE) + SDP_TRACE_WARNING("list_len: %d(attr_rsp)", p_ccb->list_len); + + /* Check if we need to request a continuation */ + SDP_TRACE_WARNING("*p_reply:%d(%d)", *p_reply, SDP_MAX_CONTINUATION_LEN); +#endif + if (*p_reply) + { + if (*p_reply > SDP_MAX_CONTINUATION_LEN) + { + sdp_disconnect (p_ccb, SDP_INVALID_CONT_STATE); + return; + } + cont_request_needed = TRUE; + } + else + { + +#if (SDP_RAW_DATA_INCLUDED == TRUE) + SDP_TRACE_WARNING("process_service_attr_rsp"); + sdp_copy_raw_data (p_ccb, FALSE); +#endif + + /* Save the response in the database. Stop on any error */ + if (!save_attr_seq (p_ccb, &p_ccb->rsp_list[0], &p_ccb->rsp_list[p_ccb->list_len])) + { + sdp_disconnect (p_ccb, SDP_DB_FULL); + return; + } + p_ccb->list_len = 0; + p_ccb->cur_handle++; + } + } + + /* Now, ask for the next handle. Re-use the buffer we just got. */ + if (p_ccb->cur_handle < p_ccb->num_handles) + { + BT_HDR *p_msg = (BT_HDR *) GKI_getpoolbuf (SDP_POOL_ID); + UINT8 *p; + + if (!p_msg) + { + sdp_disconnect (p_ccb, SDP_NO_RESOURCES); + return; + } + + p_msg->offset = L2CAP_MIN_OFFSET; + p = p_start = (UINT8 *)(p_msg + 1) + L2CAP_MIN_OFFSET; + + /* Get all the attributes from the server */ + UINT8_TO_BE_STREAM (p, SDP_PDU_SERVICE_ATTR_REQ); + UINT16_TO_BE_STREAM (p, p_ccb->transaction_id); + p_ccb->transaction_id++; + + /* Skip the length, we need to add it at the end */ + p_param_len = p; + p += 2; + + UINT32_TO_BE_STREAM (p, p_ccb->handles[p_ccb->cur_handle]); + + /* Max attribute byte count */ + UINT16_TO_BE_STREAM (p, sdp_cb.max_attr_list_size); + + /* If no attribute filters, build a wildcard attribute sequence */ + if (p_ccb->p_db->num_attr_filters) + p = sdpu_build_attrib_seq (p, p_ccb->p_db->attr_filters, p_ccb->p_db->num_attr_filters); + else + p = sdpu_build_attrib_seq (p, NULL, 0); + + /* Was this a continuation request ? */ + if (cont_request_needed) + { + memcpy (p, p_reply, *p_reply + 1); + p += *p_reply + 1; + } + else + UINT8_TO_BE_STREAM (p, 0); + + /* Go back and put the parameter length into the buffer */ + param_len = (UINT16)(p - p_param_len - 2); + UINT16_TO_BE_STREAM (p_param_len, param_len); + + /* Set the length of the SDP data in the buffer */ + p_msg->len = (UINT16)(p - p_start); + + + L2CA_DataWrite (p_ccb->connection_id, p_msg); + + /* Start inactivity timer */ + btu_start_timer (&p_ccb->timer_entry, BTU_TTYPE_SDP, SDP_INACT_TIMEOUT); + } + else + { + sdp_disconnect (p_ccb, SDP_SUCCESS); + return; + } +} + + +/******************************************************************************* +** +** Function process_service_search_attr_rsp +** +** Description This function is called when there is a search attribute +** response from the server. +** +** Returns void +** +*******************************************************************************/ +static void process_service_search_attr_rsp (tCONN_CB *p_ccb, UINT8 *p_reply) +{ + UINT8 *p, *p_start, *p_end, *p_param_len; + UINT8 type; + UINT32 seq_len; + UINT16 param_len, lists_byte_count = 0; + BOOLEAN cont_request_needed = FALSE; + +#if (SDP_DEBUG_RAW == TRUE) + SDP_TRACE_WARNING("process_service_search_attr_rsp"); +#endif + /* If p_reply is NULL, we were called for the initial read */ + if (p_reply) + { +#if (SDP_DEBUG_RAW == TRUE) + SDP_TRACE_WARNING("ID & len: 0x%02x-%02x-%02x-%02x", + p_reply[0], p_reply[1], p_reply[2], p_reply[3]); +#endif + /* Skip transaction ID and length */ + p_reply += 4; + + BE_STREAM_TO_UINT16 (lists_byte_count, p_reply); +#if (SDP_DEBUG_RAW == TRUE) + SDP_TRACE_WARNING("lists_byte_count:%d", lists_byte_count); +#endif + + /* Copy the response to the scratchpad. First, a safety check on the length */ + if ((p_ccb->list_len + lists_byte_count) > SDP_MAX_LIST_BYTE_COUNT) + { + sdp_disconnect (p_ccb, SDP_INVALID_PDU_SIZE); + return; + } + +#if (SDP_DEBUG_RAW == TRUE) + SDP_TRACE_WARNING("list_len: %d, list_byte_count: %d", + p_ccb->list_len, lists_byte_count); +#endif + if (p_ccb->rsp_list == NULL) + { + p_ccb->rsp_list = (UINT8 *)GKI_getbuf (SDP_MAX_LIST_BYTE_COUNT); + if (p_ccb->rsp_list == NULL) + { + SDP_TRACE_ERROR ("SDP - no gki buf to save rsp"); + sdp_disconnect (p_ccb, SDP_NO_RESOURCES); + return; + } + } + memcpy (&p_ccb->rsp_list[p_ccb->list_len], p_reply, lists_byte_count); + p_ccb->list_len += lists_byte_count; + p_reply += lists_byte_count; +#if (SDP_DEBUG_RAW == TRUE) + SDP_TRACE_WARNING("list_len: %d(search_attr_rsp)", p_ccb->list_len); + + /* Check if we need to request a continuation */ + SDP_TRACE_WARNING("*p_reply:%d(%d)", *p_reply, SDP_MAX_CONTINUATION_LEN); +#endif + if (*p_reply) + { + if (*p_reply > SDP_MAX_CONTINUATION_LEN) + { + sdp_disconnect (p_ccb, SDP_INVALID_CONT_STATE); + return; + } + + cont_request_needed = TRUE; + } + } + +#if (SDP_DEBUG_RAW == TRUE) + SDP_TRACE_WARNING("cont_request_needed:%d", cont_request_needed); +#endif + /* If continuation request (or first time request) */ + if ((cont_request_needed) || (!p_reply)) + { + BT_HDR *p_msg = (BT_HDR *) GKI_getpoolbuf (SDP_POOL_ID); + UINT8 *p; + + if (!p_msg) + { + sdp_disconnect (p_ccb, SDP_NO_RESOURCES); + return; + } + + p_msg->offset = L2CAP_MIN_OFFSET; + p = p_start = (UINT8 *)(p_msg + 1) + L2CAP_MIN_OFFSET; + + /* Build a service search request packet */ + UINT8_TO_BE_STREAM (p, SDP_PDU_SERVICE_SEARCH_ATTR_REQ); + UINT16_TO_BE_STREAM (p, p_ccb->transaction_id); + p_ccb->transaction_id++; + + /* Skip the length, we need to add it at the end */ + p_param_len = p; + p += 2; + + /* Build the UID sequence. */ +#if (defined(SDP_BROWSE_PLUS) && SDP_BROWSE_PLUS == TRUE) + p = sdpu_build_uuid_seq (p, 1, &p_ccb->p_db->uuid_filters[p_ccb->cur_uuid_idx]); +#else + p = sdpu_build_uuid_seq (p, p_ccb->p_db->num_uuid_filters, p_ccb->p_db->uuid_filters); +#endif + + /* Max attribute byte count */ + UINT16_TO_BE_STREAM (p, sdp_cb.max_attr_list_size); + + /* If no attribute filters, build a wildcard attribute sequence */ + if (p_ccb->p_db->num_attr_filters) + p = sdpu_build_attrib_seq (p, p_ccb->p_db->attr_filters, p_ccb->p_db->num_attr_filters); + else + p = sdpu_build_attrib_seq (p, NULL, 0); + + /* No continuation for first request */ + if (p_reply) + { + memcpy (p, p_reply, *p_reply + 1); + p += *p_reply + 1; + } + else + UINT8_TO_BE_STREAM (p, 0); + + /* Go back and put the parameter length into the buffer */ + param_len = p - p_param_len - 2; + UINT16_TO_BE_STREAM (p_param_len, param_len); + + /* Set the length of the SDP data in the buffer */ + p_msg->len = p - p_start; + + + L2CA_DataWrite (p_ccb->connection_id, p_msg); + + /* Start inactivity timer */ + btu_start_timer (&p_ccb->timer_entry, BTU_TTYPE_SDP, SDP_INACT_TIMEOUT); + + return; + } + + + /*******************************************************************/ + /* We now have the full response, which is a sequence of sequences */ + /*******************************************************************/ + +#if (SDP_RAW_DATA_INCLUDED == TRUE) + SDP_TRACE_WARNING("process_service_search_attr_rsp"); + sdp_copy_raw_data (p_ccb, TRUE); +#endif + + p = &p_ccb->rsp_list[0]; + + /* The contents is a sequence of attribute sequences */ + type = *p++; + + if ((type >> 3) != DATA_ELE_SEQ_DESC_TYPE) + { + SDP_TRACE_WARNING ("SDP - Wrong type: 0x%02x in attr_rsp", type); + return; + } + p = sdpu_get_len_from_type (p, type, &seq_len); + + p_end = &p_ccb->rsp_list[p_ccb->list_len]; + + if ((p + seq_len) != p_end) + { + sdp_disconnect (p_ccb, SDP_INVALID_CONT_STATE); + return; + } + + while (p < p_end) + { + p = save_attr_seq (p_ccb, p, &p_ccb->rsp_list[p_ccb->list_len]); + if (!p) + { + sdp_disconnect (p_ccb, SDP_DB_FULL); + return; + } + } + + /* Since we got everything we need, disconnect the call */ + sdp_disconnect (p_ccb, SDP_SUCCESS); +} + +/******************************************************************************* +** +** Function save_attr_seq +** +** Description This function is called when there is a response from +** the server. +** +** Returns pointer to next byte or NULL if error +** +*******************************************************************************/ +static UINT8 *save_attr_seq (tCONN_CB *p_ccb, UINT8 *p, UINT8 *p_msg_end) +{ + UINT32 seq_len, attr_len; + UINT16 attr_id; + UINT8 type, *p_seq_end; + tSDP_DISC_REC *p_rec; + + type = *p++; + + if ((type >> 3) != DATA_ELE_SEQ_DESC_TYPE) + { + SDP_TRACE_WARNING ("SDP - Wrong type: 0x%02x in attr_rsp", type); + return (NULL); + } + + p = sdpu_get_len_from_type (p, type, &seq_len); + if ((p + seq_len) > p_msg_end) + { + SDP_TRACE_WARNING ("SDP - Bad len in attr_rsp %d", seq_len); + return (NULL); + } + + /* Create a record */ + p_rec = add_record (p_ccb->p_db, p_ccb->device_address); + if (!p_rec) + { + SDP_TRACE_WARNING ("SDP - DB full add_record"); + return (NULL); + } + + p_seq_end = p + seq_len; + + while (p < p_seq_end) + { + /* First get the attribute ID */ + type = *p++; + p = sdpu_get_len_from_type (p, type, &attr_len); + if (((type >> 3) != UINT_DESC_TYPE) || (attr_len != 2)) + { + SDP_TRACE_WARNING ("SDP - Bad type: 0x%02x or len: %d in attr_rsp", type, attr_len); + return (NULL); + } + BE_STREAM_TO_UINT16 (attr_id, p); + + /* Now, add the attribute value */ + p = add_attr (p, p_ccb->p_db, p_rec, attr_id, NULL, 0); + + if (!p) + { + SDP_TRACE_WARNING ("SDP - DB full add_attr"); + return (NULL); + } + } + + return (p); +} + + +/******************************************************************************* +** +** Function add_record +** +** Description This function allocates space for a record from the DB. +** +** Returns pointer to next byte in data stream +** +*******************************************************************************/ +tSDP_DISC_REC *add_record (tSDP_DISCOVERY_DB *p_db, BD_ADDR p_bda) +{ + tSDP_DISC_REC *p_rec; + + /* See if there is enough space in the database */ + if (p_db->mem_free < sizeof (tSDP_DISC_REC)) + return (NULL); + + p_rec = (tSDP_DISC_REC *) p_db->p_free_mem; + p_db->p_free_mem += sizeof (tSDP_DISC_REC); + p_db->mem_free -= sizeof (tSDP_DISC_REC); + + p_rec->p_first_attr = NULL; + p_rec->p_next_rec = NULL; + + memcpy (p_rec->remote_bd_addr, p_bda, BD_ADDR_LEN); + + /* Add the record to the end of chain */ + if (!p_db->p_first_rec) + p_db->p_first_rec = p_rec; + else + { + tSDP_DISC_REC *p_rec1 = p_db->p_first_rec; + + while (p_rec1->p_next_rec) + p_rec1 = p_rec1->p_next_rec; + + p_rec1->p_next_rec = p_rec; + } + + return (p_rec); +} + +#define SDP_ADDITIONAL_LIST_MASK 0x80 +/******************************************************************************* +** +** Function add_attr +** +** Description This function allocates space for an attribute from the DB +** and copies the data into it. +** +** Returns pointer to next byte in data stream +** +*******************************************************************************/ +static UINT8 *add_attr (UINT8 *p, tSDP_DISCOVERY_DB *p_db, tSDP_DISC_REC *p_rec, + UINT16 attr_id, tSDP_DISC_ATTR *p_parent_attr, UINT8 nest_level) +{ + tSDP_DISC_ATTR *p_attr; + UINT32 attr_len; + UINT32 total_len; + UINT16 attr_type; + UINT16 id; + UINT8 type; + UINT8 *p_end; + UINT8 is_additional_list = nest_level & SDP_ADDITIONAL_LIST_MASK; + + nest_level &= ~(SDP_ADDITIONAL_LIST_MASK); + + type = *p++; + p = sdpu_get_len_from_type (p, type, &attr_len); + + attr_len &= SDP_DISC_ATTR_LEN_MASK; + attr_type = (type >> 3) & 0x0f; + + /* See if there is enough space in the database */ + if (attr_len > 4) + total_len = attr_len - 4 + (UINT16)sizeof (tSDP_DISC_ATTR); + else + total_len = sizeof (tSDP_DISC_ATTR); + + /* Ensure it is a multiple of 4 */ + total_len = (total_len + 3) & ~3; + + /* See if there is enough space in the database */ + if (p_db->mem_free < total_len) + return (NULL); + + p_attr = (tSDP_DISC_ATTR *) p_db->p_free_mem; + p_attr->attr_id = attr_id; + p_attr->attr_len_type = (UINT16)attr_len | (attr_type << 12); + p_attr->p_next_attr = NULL; + + /* Store the attribute value */ + switch (attr_type) + { + case UINT_DESC_TYPE: + if( (is_additional_list != 0) && (attr_len == 2) ) + { + BE_STREAM_TO_UINT16 (id, p); + if(id != ATTR_ID_PROTOCOL_DESC_LIST) + p -= 2; + else + { + /* Reserve the memory for the attribute now, as we need to add sub-attributes */ + p_db->p_free_mem += sizeof (tSDP_DISC_ATTR); + p_db->mem_free -= sizeof (tSDP_DISC_ATTR); + p_end = p + attr_len; + total_len = 0; + + /* SDP_TRACE_DEBUG ("SDP - attr nest level:%d(list)", nest_level); */ + if (nest_level >= MAX_NEST_LEVELS) + { + SDP_TRACE_ERROR ("SDP - attr nesting too deep"); + return (p_end); + } + + /* Now, add the list entry */ + p = add_attr (p, p_db, p_rec, ATTR_ID_PROTOCOL_DESC_LIST, p_attr, (UINT8)(nest_level + 1)); + + break; + } + } + /* Case falls through */ + + case TWO_COMP_INT_DESC_TYPE: + switch (attr_len) + { + case 1: + p_attr->attr_value.v.u8 = *p++; + break; + case 2: + BE_STREAM_TO_UINT16 (p_attr->attr_value.v.u16, p); + break; + case 4: + BE_STREAM_TO_UINT32 (p_attr->attr_value.v.u32, p); + break; + default: + BE_STREAM_TO_ARRAY (p, p_attr->attr_value.v.array, (INT32)attr_len); + break; + } + break; + + case UUID_DESC_TYPE: + switch (attr_len) + { + case 2: + BE_STREAM_TO_UINT16 (p_attr->attr_value.v.u16, p); + break; + case 4: + BE_STREAM_TO_UINT32 (p_attr->attr_value.v.u32, p); + if (p_attr->attr_value.v.u32 < 0x10000) + { + attr_len = 2; + p_attr->attr_len_type = (UINT16)attr_len | (attr_type << 12); + p_attr->attr_value.v.u16 = (UINT16) p_attr->attr_value.v.u32; + + } + break; + case 16: + /* See if we can compress his UUID down to 16 or 32bit UUIDs */ + if (sdpu_is_base_uuid (p)) + { + if ((p[0] == 0) && (p[1] == 0)) + { + p_attr->attr_len_type = (p_attr->attr_len_type & ~SDP_DISC_ATTR_LEN_MASK) | 2; + p += 2; + BE_STREAM_TO_UINT16 (p_attr->attr_value.v.u16, p); + p += MAX_UUID_SIZE - 4; + } + else + { + p_attr->attr_len_type = (p_attr->attr_len_type & ~SDP_DISC_ATTR_LEN_MASK) | 4; + BE_STREAM_TO_UINT32 (p_attr->attr_value.v.u32, p); + p += MAX_UUID_SIZE - 4; + } + } + else + { + /* coverity[overrun-local] */ + /* + Event overrun-local: Overrun of static array "p_attr->attr_value.v.array" of size 4 at position 15 with index variable "ijk" + False-positive: SDP uses scratch buffer to hold the attribute value. + The actual size of tSDP_DISC_ATVAL does not matter. + If the array size in tSDP_DISC_ATVAL is increase, we would increase the system RAM usage unnecessarily + */ + BE_STREAM_TO_ARRAY (p, p_attr->attr_value.v.array, (INT32)attr_len); + } + break; + default: + SDP_TRACE_WARNING ("SDP - bad len in UUID attr: %d", attr_len); + return (p + attr_len); + } + break; + + case DATA_ELE_SEQ_DESC_TYPE: + case DATA_ELE_ALT_DESC_TYPE: + /* Reserve the memory for the attribute now, as we need to add sub-attributes */ + p_db->p_free_mem += sizeof (tSDP_DISC_ATTR); + p_db->mem_free -= sizeof (tSDP_DISC_ATTR); + p_end = p + attr_len; + total_len = 0; + + /* SDP_TRACE_DEBUG ("SDP - attr nest level:%d", nest_level); */ + if (nest_level >= MAX_NEST_LEVELS) + { + SDP_TRACE_ERROR ("SDP - attr nesting too deep"); + return (p_end); + } + if(is_additional_list != 0 || attr_id == ATTR_ID_ADDITION_PROTO_DESC_LISTS) + nest_level |= SDP_ADDITIONAL_LIST_MASK; + /* SDP_TRACE_DEBUG ("SDP - attr nest level:0x%x(finish)", nest_level); */ + + while (p < p_end) + { + /* Now, add the list entry */ + p = add_attr (p, p_db, p_rec, 0, p_attr, (UINT8)(nest_level + 1)); + + if (!p) + return (NULL); + } + break; + + case TEXT_STR_DESC_TYPE: + case URL_DESC_TYPE: + BE_STREAM_TO_ARRAY (p, p_attr->attr_value.v.array, (INT32)attr_len); + break; + + case BOOLEAN_DESC_TYPE: + switch (attr_len) + { + case 1: + p_attr->attr_value.v.u8 = *p++; + break; + default: + SDP_TRACE_WARNING ("SDP - bad len in boolean attr: %d", attr_len); + return (p + attr_len); + } + break; + + default: /* switch (attr_type) */ + break; + } + + p_db->p_free_mem += total_len; + p_db->mem_free -= total_len; + + /* Add the attribute to the end of the chain */ + if (!p_parent_attr) + { + if (!p_rec->p_first_attr) + p_rec->p_first_attr = p_attr; + else + { + tSDP_DISC_ATTR *p_attr1 = p_rec->p_first_attr; + + while (p_attr1->p_next_attr) + p_attr1 = p_attr1->p_next_attr; + + p_attr1->p_next_attr = p_attr; + } + } + else + { + if (!p_parent_attr->attr_value.v.p_sub_attr) + { + p_parent_attr->attr_value.v.p_sub_attr = p_attr; + /* SDP_TRACE_DEBUG ("parent:0x%x(id:%d), ch:0x%x(id:%d)", + p_parent_attr, p_parent_attr->attr_id, p_attr, p_attr->attr_id); */ + } + else + { + tSDP_DISC_ATTR *p_attr1 = p_parent_attr->attr_value.v.p_sub_attr; + /* SDP_TRACE_DEBUG ("parent:0x%x(id:%d), ch1:0x%x(id:%d)", + p_parent_attr, p_parent_attr->attr_id, p_attr1, p_attr1->attr_id); */ + + while (p_attr1->p_next_attr) + p_attr1 = p_attr1->p_next_attr; + + p_attr1->p_next_attr = p_attr; + /* SDP_TRACE_DEBUG ("new ch:0x%x(id:%d)", p_attr, p_attr->attr_id); */ + } + } + + return (p); +} + +#endif /* CLIENT_ENABLED == TRUE */ diff --git a/components/bt/bluedroid/stack/sdp/sdp_main.c b/components/bt/bluedroid/stack/sdp/sdp_main.c new file mode 100755 index 0000000000..ba3c763e4b --- /dev/null +++ b/components/bt/bluedroid/stack/sdp/sdp_main.c @@ -0,0 +1,721 @@ +/****************************************************************************** + * + * Copyright (C) 1999-2012 Broadcom Corporation + * + * 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 main SDP functions + * + ******************************************************************************/ + +#include +#include +//#include + +#include "bt_target.h" +//#include "bt_utils.h" +#include "gki.h" +#include "l2cdefs.h" +#include "hcidefs.h" +#include "hcimsgs.h" + +#include "l2c_api.h" +#include "l2cdefs.h" + +#include "btu.h" +#include "btm_api.h" + +#include "sdp_api.h" +#include "sdpint.h" + + +/********************************************************************************/ +/* G L O B A L S D P D A T A */ +/********************************************************************************/ +#if SDP_DYNAMIC_MEMORY == FALSE +tSDP_CB sdp_cb; +#endif + +/********************************************************************************/ +/* L O C A L F U N C T I O N P R O T O T Y P E S */ +/********************************************************************************/ +static void sdp_connect_ind (BD_ADDR bd_addr, UINT16 l2cap_cid, UINT16 psm, + UINT8 l2cap_id); +static void sdp_config_ind (UINT16 l2cap_cid, tL2CAP_CFG_INFO *p_cfg); +static void sdp_config_cfm (UINT16 l2cap_cid, tL2CAP_CFG_INFO *p_cfg); +static void sdp_disconnect_ind (UINT16 l2cap_cid, BOOLEAN ack_needed); +static void sdp_data_ind (UINT16 l2cap_cid, BT_HDR *p_msg); + +#if SDP_CLIENT_ENABLED == TRUE +static void sdp_connect_cfm (UINT16 l2cap_cid, UINT16 result); +static void sdp_disconnect_cfm (UINT16 l2cap_cid, UINT16 result); +#else +#define sdp_connect_cfm NULL +#define sdp_disconnect_cfm NULL +#endif + + +/******************************************************************************* +** +** Function sdp_init +** +** Description This function initializes the SDP unit. +** +** Returns void +** +*******************************************************************************/ +void sdp_init (void) +{ + /* Clears all structures and local SDP database (if Server is enabled) */ + memset (&sdp_cb, 0, sizeof (tSDP_CB)); + + /* Initialize the L2CAP configuration. We only care about MTU and flush */ + sdp_cb.l2cap_my_cfg.mtu_present = TRUE; + sdp_cb.l2cap_my_cfg.mtu = SDP_MTU_SIZE; + sdp_cb.l2cap_my_cfg.flush_to_present = TRUE; + sdp_cb.l2cap_my_cfg.flush_to = SDP_FLUSH_TO; + + sdp_cb.max_attr_list_size = SDP_MTU_SIZE - 16; + sdp_cb.max_recs_per_search = SDP_MAX_DISC_SERVER_RECS; + +#if SDP_SERVER_ENABLED == TRUE + /* Register with Security Manager for the specific security level */ + if (!BTM_SetSecurityLevel (FALSE, SDP_SERVICE_NAME, BTM_SEC_SERVICE_SDP_SERVER, + SDP_SECURITY_LEVEL, SDP_PSM, 0, 0)) + { + SDP_TRACE_ERROR ("Security Registration Server failed"); + return; + } +#endif + +#if SDP_CLIENT_ENABLED == TRUE + /* Register with Security Manager for the specific security level */ + if (!BTM_SetSecurityLevel (TRUE, SDP_SERVICE_NAME, BTM_SEC_SERVICE_SDP_SERVER, + SDP_SECURITY_LEVEL, SDP_PSM, 0, 0)) + { + SDP_TRACE_ERROR ("Security Registration for Client failed"); + return; + } +#endif + +#if defined(SDP_INITIAL_TRACE_LEVEL) + sdp_cb.trace_level = SDP_INITIAL_TRACE_LEVEL; +#else + sdp_cb.trace_level = BT_TRACE_LEVEL_NONE; /* No traces */ +#endif + + sdp_cb.reg_info.pL2CA_ConnectInd_Cb = sdp_connect_ind; + sdp_cb.reg_info.pL2CA_ConnectCfm_Cb = sdp_connect_cfm; + sdp_cb.reg_info.pL2CA_ConnectPnd_Cb = NULL; + sdp_cb.reg_info.pL2CA_ConfigInd_Cb = sdp_config_ind; + sdp_cb.reg_info.pL2CA_ConfigCfm_Cb = sdp_config_cfm; + sdp_cb.reg_info.pL2CA_DisconnectInd_Cb = sdp_disconnect_ind; + sdp_cb.reg_info.pL2CA_DisconnectCfm_Cb = sdp_disconnect_cfm; + sdp_cb.reg_info.pL2CA_QoSViolationInd_Cb = NULL; + sdp_cb.reg_info.pL2CA_DataInd_Cb = sdp_data_ind; + sdp_cb.reg_info.pL2CA_CongestionStatus_Cb = NULL; + sdp_cb.reg_info.pL2CA_TxComplete_Cb = NULL; + + /* Now, register with L2CAP */ + if (!L2CA_Register (SDP_PSM, &sdp_cb.reg_info)) + { + SDP_TRACE_ERROR ("SDP Registration failed"); + } +} + +#if (defined(SDP_DEBUG) && SDP_DEBUG == TRUE) +/******************************************************************************* +** +** Function sdp_set_max_attr_list_size +** +** Description This function sets the max attribute list size to use +** +** Returns void +** +*******************************************************************************/ +UINT16 sdp_set_max_attr_list_size (UINT16 max_size) +{ + if (max_size > (sdp_cb.l2cap_my_cfg.mtu - 16) ) + max_size = sdp_cb.l2cap_my_cfg.mtu - 16; + + sdp_cb.max_attr_list_size = max_size; + + return sdp_cb.max_attr_list_size; +} +#endif + +/******************************************************************************* +** +** Function sdp_connect_ind +** +** Description This function handles an inbound connection indication +** from L2CAP. This is the case where we are acting as a +** server. +** +** Returns void +** +*******************************************************************************/ +static void sdp_connect_ind (BD_ADDR bd_addr, UINT16 l2cap_cid, UINT16 psm, UINT8 l2cap_id) +{ + UNUSED(psm); +#if SDP_SERVER_ENABLED == TRUE + tCONN_CB *p_ccb; + + /* Allocate a new CCB. Return if none available. */ + if ((p_ccb = sdpu_allocate_ccb()) == NULL) + return; + + /* Transition to the next appropriate state, waiting for config setup. */ + p_ccb->con_state = SDP_STATE_CFG_SETUP; + + /* Save the BD Address and Channel ID. */ + memcpy (&p_ccb->device_address[0], bd_addr, sizeof (BD_ADDR)); + p_ccb->connection_id = l2cap_cid; + + /* Send response to the L2CAP layer. */ + L2CA_ConnectRsp (bd_addr, l2cap_id, l2cap_cid, L2CAP_CONN_OK, L2CAP_CONN_OK); + { + tL2CAP_CFG_INFO cfg = sdp_cb.l2cap_my_cfg; + + if (cfg.fcr_present) + { + SDP_TRACE_DEBUG("sdp_connect_ind: mode %u, txwinsz %u, max_trans %u, rtrans_tout %u, mon_tout %u, mps %u", + cfg.fcr.mode, cfg.fcr.tx_win_sz, cfg.fcr.max_transmit, + cfg.fcr.rtrans_tout,cfg.fcr.mon_tout, cfg.fcr.mps); + } + + if ((!L2CA_ConfigReq (l2cap_cid, &cfg)) && cfg.fcr_present + && cfg.fcr.mode != L2CAP_FCR_BASIC_MODE) + { + /* FCR not desired; try again in basic mode */ + cfg.fcr.mode = L2CAP_FCR_BASIC_MODE; + cfg.fcr_present = FALSE; + L2CA_ConfigReq (l2cap_cid, &cfg); + } + } + + SDP_TRACE_EVENT ("SDP - Rcvd L2CAP conn ind, sent config req, CID 0x%x", p_ccb->connection_id); +#else /* No server */ + /* Reject the connection */ + L2CA_ConnectRsp (bd_addr, l2cap_id, l2cap_cid, L2CAP_CONN_NO_PSM, 0); +#endif +} + +#if SDP_CLIENT_ENABLED == TRUE +/******************************************************************************* +** +** Function sdp_connect_cfm +** +** Description This function handles the connect confirm events +** from L2CAP. This is the case when we are acting as a +** client and have sent a connect request. +** +** Returns void +** +*******************************************************************************/ +static void sdp_connect_cfm (UINT16 l2cap_cid, UINT16 result) +{ + tCONN_CB *p_ccb; + tL2CAP_CFG_INFO cfg; + + /* Find CCB based on CID */ + if ((p_ccb = sdpu_find_ccb_by_cid (l2cap_cid)) == NULL) + { + SDP_TRACE_WARNING ("SDP - Rcvd conn cnf for unknown CID 0x%x", l2cap_cid); + return; + } + + /* If the connection response contains success status, then */ + /* Transition to the next state and startup the timer. */ + if ((result == L2CAP_CONN_OK) && (p_ccb->con_state == SDP_STATE_CONN_SETUP)) + { + p_ccb->con_state = SDP_STATE_CFG_SETUP; + + cfg = sdp_cb.l2cap_my_cfg; + + if (cfg.fcr_present) + { + SDP_TRACE_DEBUG("sdp_connect_cfm: mode %u, txwinsz %u, max_trans %u, rtrans_tout %u, mon_tout %u, mps %u", + cfg.fcr.mode, cfg.fcr.tx_win_sz, cfg.fcr.max_transmit, + cfg.fcr.rtrans_tout,cfg.fcr.mon_tout, cfg.fcr.mps); + } + + if ((!L2CA_ConfigReq (l2cap_cid, &cfg)) && cfg.fcr_present + && cfg.fcr.mode != L2CAP_FCR_BASIC_MODE) + { + /* FCR not desired; try again in basic mode */ + cfg.fcr_present = FALSE; + cfg.fcr.mode = L2CAP_FCR_BASIC_MODE; + L2CA_ConfigReq (l2cap_cid, &cfg); + } + + SDP_TRACE_EVENT ("SDP - got conn cnf, sent cfg req, CID: 0x%x", p_ccb->connection_id); + } + else + { + SDP_TRACE_WARNING ("SDP - Rcvd conn cnf with error: 0x%x CID 0x%x", result, p_ccb->connection_id); + + /* Tell the user if he has a callback */ + if (p_ccb->p_cb || p_ccb->p_cb2) + { + UINT16 err = -1; + if ((result == HCI_ERR_HOST_REJECT_SECURITY) + || (result == HCI_ERR_AUTH_FAILURE) + || (result == HCI_ERR_PAIRING_NOT_ALLOWED) + || (result == HCI_ERR_PAIRING_WITH_UNIT_KEY_NOT_SUPPORTED) + || (result == HCI_ERR_KEY_MISSING)) + err = SDP_SECURITY_ERR; + else if (result == HCI_ERR_HOST_REJECT_DEVICE) + err = SDP_CONN_REJECTED; + else + err = SDP_CONN_FAILED; + if(p_ccb->p_cb) + (*p_ccb->p_cb)(err); + else if(p_ccb->p_cb2) + (*p_ccb->p_cb2)(err, p_ccb->user_data); + + } + sdpu_release_ccb (p_ccb); + } +} +#endif /* SDP_CLIENT_ENABLED == TRUE */ + + +/******************************************************************************* +** +** Function sdp_config_ind +** +** Description This function processes the L2CAP configuration indication +** event. +** +** Returns void +** +*******************************************************************************/ +static void sdp_config_ind (UINT16 l2cap_cid, tL2CAP_CFG_INFO *p_cfg) +{ + tCONN_CB *p_ccb; + + /* Find CCB based on CID */ + if ((p_ccb = sdpu_find_ccb_by_cid (l2cap_cid)) == NULL) + { + SDP_TRACE_WARNING ("SDP - Rcvd L2CAP cfg ind, unknown CID: 0x%x", l2cap_cid); + return; + } + + /* Remember the remote MTU size */ + if (!p_cfg->mtu_present) + { + /* use min(L2CAP_DEFAULT_MTU,SDP_MTU_SIZE) for GKI buffer size reasons */ + p_ccb->rem_mtu_size = (L2CAP_DEFAULT_MTU > SDP_MTU_SIZE)?SDP_MTU_SIZE:L2CAP_DEFAULT_MTU; + } + else + { + if (p_cfg->mtu > SDP_MTU_SIZE) + p_ccb->rem_mtu_size = SDP_MTU_SIZE; + else + p_ccb->rem_mtu_size = p_cfg->mtu; + } + + /* For now, always accept configuration from the other side */ + p_cfg->flush_to_present = FALSE; + p_cfg->mtu_present = FALSE; + p_cfg->result = L2CAP_CFG_OK; + + /* Check peer config request against our rfcomm configuration */ + if (p_cfg->fcr_present) + { + /* Reject the window size if it is bigger than we want it to be */ + if (p_cfg->fcr.mode != L2CAP_FCR_BASIC_MODE) + { + if (sdp_cb.l2cap_my_cfg.fcr.mode != L2CAP_FCR_BASIC_MODE + && p_cfg->fcr.tx_win_sz > sdp_cb.l2cap_my_cfg.fcr.tx_win_sz) + { + p_cfg->fcr.tx_win_sz = sdp_cb.l2cap_my_cfg.fcr.tx_win_sz; + p_cfg->result = L2CAP_CFG_UNACCEPTABLE_PARAMS; + SDP_TRACE_DEBUG("sdp_config_ind(CONFIG) -> Please try again with SMALLER TX WINDOW"); + } + + /* Reject if locally we want basic and they don't */ + if (sdp_cb.l2cap_my_cfg.fcr.mode == L2CAP_FCR_BASIC_MODE) + { + /* Ask for a new setup */ + p_cfg->fcr.mode = L2CAP_FCR_BASIC_MODE; + p_cfg->result = L2CAP_CFG_UNACCEPTABLE_PARAMS; + SDP_TRACE_DEBUG("sdp_config_ind(CONFIG) -> Please try again with BASIC mode"); + } + /* Remain in configure state and give the peer our desired configuration */ + if (p_cfg->result != L2CAP_CFG_OK) + { + SDP_TRACE_WARNING ("SDP - Rcvd cfg ind, Unacceptable Parameters sent cfg cfm, CID: 0x%x", l2cap_cid); + L2CA_ConfigRsp (l2cap_cid, p_cfg); + return; + } + } + else /* We agree with peer's request */ + p_cfg->fcr_present = FALSE; + } + + L2CA_ConfigRsp (l2cap_cid, p_cfg); + + SDP_TRACE_EVENT ("SDP - Rcvd cfg ind, sent cfg cfm, CID: 0x%x", l2cap_cid); + + p_ccb->con_flags |= SDP_FLAGS_HIS_CFG_DONE; + + if (p_ccb->con_flags & SDP_FLAGS_MY_CFG_DONE) + { + p_ccb->con_state = SDP_STATE_CONNECTED; + + if (p_ccb->con_flags & SDP_FLAGS_IS_ORIG) + sdp_disc_connected (p_ccb); + else + /* Start inactivity timer */ + btu_start_timer (&p_ccb->timer_entry, BTU_TTYPE_SDP, SDP_INACT_TIMEOUT); + } + +} + + +/******************************************************************************* +** +** Function sdp_config_cfm +** +** Description This function processes the L2CAP configuration confirmation +** event. +** +** Returns void +** +*******************************************************************************/ +static void sdp_config_cfm (UINT16 l2cap_cid, tL2CAP_CFG_INFO *p_cfg) +{ + tCONN_CB *p_ccb; + + SDP_TRACE_EVENT ("SDP - Rcvd cfg cfm, CID: 0x%x Result: %d", l2cap_cid, p_cfg->result); + + /* Find CCB based on CID */ + if ((p_ccb = sdpu_find_ccb_by_cid (l2cap_cid)) == NULL) + { + SDP_TRACE_WARNING ("SDP - Rcvd L2CAP cfg ind, unknown CID: 0x%x", l2cap_cid); + return; + } + + /* For now, always accept configuration from the other side */ + if (p_cfg->result == L2CAP_CFG_OK) + { + p_ccb->con_flags |= SDP_FLAGS_MY_CFG_DONE; + + if (p_ccb->con_flags & SDP_FLAGS_HIS_CFG_DONE) + { + p_ccb->con_state = SDP_STATE_CONNECTED; + + if (p_ccb->con_flags & SDP_FLAGS_IS_ORIG) + sdp_disc_connected (p_ccb); + else + /* Start inactivity timer */ + btu_start_timer (&p_ccb->timer_entry, BTU_TTYPE_SDP, SDP_INACT_TIMEOUT); + } + } + else + { + /* If peer has rejected FCR and suggested basic then try basic */ + if (p_cfg->fcr_present) + { + tL2CAP_CFG_INFO cfg = sdp_cb.l2cap_my_cfg; + cfg.fcr_present = FALSE; + L2CA_ConfigReq (l2cap_cid, &cfg); + + /* Remain in configure state */ + return; + } + +#if SDP_CLIENT_ENABLED == TRUE + sdp_disconnect(p_ccb, SDP_CFG_FAILED); +#endif + } +} + +/******************************************************************************* +** +** Function sdp_disconnect_ind +** +** Description This function handles a disconnect event from L2CAP. If +** requested to, we ack the disconnect before dropping the CCB +** +** Returns void +** +*******************************************************************************/ +static void sdp_disconnect_ind (UINT16 l2cap_cid, BOOLEAN ack_needed) +{ + tCONN_CB *p_ccb; + + /* Find CCB based on CID */ + if ((p_ccb = sdpu_find_ccb_by_cid (l2cap_cid)) == NULL) + { + SDP_TRACE_WARNING ("SDP - Rcvd L2CAP disc, unknown CID: 0x%x", l2cap_cid); + return; + } + + if (ack_needed) + L2CA_DisconnectRsp (l2cap_cid); + + SDP_TRACE_EVENT ("SDP - Rcvd L2CAP disc, CID: 0x%x", l2cap_cid); +#if SDP_CLIENT_ENABLED == TRUE + /* Tell the user if he has a callback */ + if (p_ccb->p_cb) + (*p_ccb->p_cb) ((UINT16) ((p_ccb->con_state == SDP_STATE_CONNECTED) ? + SDP_SUCCESS : SDP_CONN_FAILED)); + else if (p_ccb->p_cb2) + (*p_ccb->p_cb2) ((UINT16) ((p_ccb->con_state == SDP_STATE_CONNECTED) ? + SDP_SUCCESS : SDP_CONN_FAILED), p_ccb->user_data); + +#endif + sdpu_release_ccb (p_ccb); +} + +/******************************************************************************* +** +** Function sdp_data_ind +** +** Description This function is called when data is received from L2CAP. +** if we are the originator of the connection, we are the SDP +** client, and the received message is queued up for the client. +** +** If we are the destination of the connection, we are the SDP +** server, so the message is passed to the server processing +** function. +** +** Returns void +** +*******************************************************************************/ +static void sdp_data_ind (UINT16 l2cap_cid, BT_HDR *p_msg) +{ + tCONN_CB *p_ccb; + + /* Find CCB based on CID */ + if ((p_ccb = sdpu_find_ccb_by_cid (l2cap_cid)) != NULL) + { + if (p_ccb->con_state == SDP_STATE_CONNECTED) + { + if (p_ccb->con_flags & SDP_FLAGS_IS_ORIG) + sdp_disc_server_rsp (p_ccb, p_msg); + else + sdp_server_handle_client_req (p_ccb, p_msg); + } + else + { + SDP_TRACE_WARNING ("SDP - Ignored L2CAP data while in state: %d, CID: 0x%x", + p_ccb->con_state, l2cap_cid); + } + } + else + { + SDP_TRACE_WARNING ("SDP - Rcvd L2CAP data, unknown CID: 0x%x", l2cap_cid); + } + + GKI_freebuf (p_msg); +} + + +#if SDP_CLIENT_ENABLED == TRUE +/******************************************************************************* +** +** Function sdp_conn_originate +** +** Description This function is called from the API to originate a +** connection. +** +** Returns void +** +*******************************************************************************/ +tCONN_CB* sdp_conn_originate (UINT8 *p_bd_addr) +{ + tCONN_CB *p_ccb; + UINT16 cid; + + /* Allocate a new CCB. Return if none available. */ + if ((p_ccb = sdpu_allocate_ccb()) == NULL) + { + SDP_TRACE_WARNING ("SDP - no spare CCB for orig"); + return (NULL); + } + + SDP_TRACE_EVENT ("SDP - Originate started"); + + /* We are the originator of this connection */ + p_ccb->con_flags |= SDP_FLAGS_IS_ORIG; + + /* Save the BD Address and Channel ID. */ + memcpy (&p_ccb->device_address[0], p_bd_addr, sizeof (BD_ADDR)); + + /* Transition to the next appropriate state, waiting for connection confirm. */ + p_ccb->con_state = SDP_STATE_CONN_SETUP; + + cid = L2CA_ConnectReq (SDP_PSM, p_bd_addr); + + /* Check if L2CAP started the connection process */ + if (cid != 0) + { + p_ccb->connection_id = cid; + + return (p_ccb); + } + else + { + SDP_TRACE_WARNING ("SDP - Originate failed"); + sdpu_release_ccb (p_ccb); + return (NULL); + } +} + +/******************************************************************************* +** +** Function sdp_disconnect +** +** Description This function disconnects a connection. +** +** Returns void +** +*******************************************************************************/ +void sdp_disconnect (tCONN_CB*p_ccb, UINT16 reason) +{ +#if (defined(SDP_BROWSE_PLUS) && SDP_BROWSE_PLUS == TRUE) + + /* If we are browsing for multiple UUIDs ... */ + if ((p_ccb->con_state == SDP_STATE_CONNECTED) + && (p_ccb->con_flags & SDP_FLAGS_IS_ORIG) + && ((reason == SDP_SUCCESS) || (reason == SDP_NO_RECS_MATCH))) + { + /* If the browse found something, do no more searching */ + if ((p_ccb->cur_uuid_idx == 0) && (p_ccb->p_db->p_first_rec)) + p_ccb->cur_uuid_idx = p_ccb->p_db->num_uuid_filters; + + while (++p_ccb->cur_uuid_idx < p_ccb->p_db->num_uuid_filters) + { + /* Check we have not already found the UUID (maybe through browse) */ + if ((p_ccb->p_db->uuid_filters[p_ccb->cur_uuid_idx].len == 2) + && (SDP_FindServiceInDb (p_ccb->p_db, + p_ccb->p_db->uuid_filters[p_ccb->cur_uuid_idx].uu.uuid16, + NULL))) + continue; + + if ((p_ccb->p_db->uuid_filters[p_ccb->cur_uuid_idx].len > 2) + && (SDP_FindServiceUUIDInDb (p_ccb->p_db, + &p_ccb->p_db->uuid_filters[p_ccb->cur_uuid_idx], NULL))) + continue; + + p_ccb->cur_handle = 0; + + SDP_TRACE_EVENT ("SDP - looking for for more, CID: 0x%x", + p_ccb->connection_id); + + sdp_disc_connected (p_ccb); + return; + } + } + + if ((reason == SDP_NO_RECS_MATCH) && (p_ccb->p_db->p_first_rec)) + reason = SDP_SUCCESS; + +#endif + + SDP_TRACE_EVENT ("SDP - disconnect CID: 0x%x", p_ccb->connection_id); + + /* Check if we have a connection ID */ + if (p_ccb->connection_id != 0) + { + L2CA_DisconnectReq (p_ccb->connection_id); + p_ccb->disconnect_reason = reason; + } + + /* If at setup state, we may not get callback ind from L2CAP */ + /* Call user callback immediately */ + if (p_ccb->con_state == SDP_STATE_CONN_SETUP) + { + /* Tell the user if he has a callback */ + if (p_ccb->p_cb) + (*p_ccb->p_cb) (reason); + else if (p_ccb->p_cb2) + (*p_ccb->p_cb2) (reason, p_ccb->user_data); + + sdpu_release_ccb (p_ccb); + } + +} + +/******************************************************************************* +** +** Function sdp_disconnect_cfm +** +** Description This function handles a disconnect confirm event from L2CAP. +** +** Returns void +** +*******************************************************************************/ +static void sdp_disconnect_cfm (UINT16 l2cap_cid, UINT16 result) +{ + tCONN_CB *p_ccb; + UNUSED(result); + + /* Find CCB based on CID */ + if ((p_ccb = sdpu_find_ccb_by_cid (l2cap_cid)) == NULL) + { + SDP_TRACE_WARNING ("SDP - Rcvd L2CAP disc cfm, unknown CID: 0x%x", l2cap_cid); + return; + } + + SDP_TRACE_EVENT ("SDP - Rcvd L2CAP disc cfm, CID: 0x%x", l2cap_cid); + + /* Tell the user if he has a callback */ + if (p_ccb->p_cb) + (*p_ccb->p_cb) (p_ccb->disconnect_reason); + else if (p_ccb->p_cb2) + (*p_ccb->p_cb2) (p_ccb->disconnect_reason, p_ccb->user_data); + + + sdpu_release_ccb (p_ccb); +} + +#endif /* SDP_CLIENT_ENABLED == TRUE */ + +/******************************************************************************* +** +** Function sdp_conn_timeout +** +** Description This function processes a timeout. Currently, we simply send +** a disconnect request to L2CAP. +** +** Returns void +** +*******************************************************************************/ +void sdp_conn_timeout (tCONN_CB*p_ccb) +{ + SDP_TRACE_EVENT ("SDP - CCB timeout in state: %d CID: 0x%x", + p_ccb->con_state, p_ccb->connection_id); + + L2CA_DisconnectReq (p_ccb->connection_id); +#if SDP_CLIENT_ENABLED == TRUE + /* Tell the user if he has a callback */ + if (p_ccb->p_cb) + (*p_ccb->p_cb) (SDP_CONN_FAILED); + else if (p_ccb->p_cb2) + (*p_ccb->p_cb2) (SDP_CONN_FAILED, p_ccb->user_data); +#endif + sdpu_release_ccb (p_ccb); +} + + + + diff --git a/components/bt/bluedroid/stack/sdp/sdp_server.c b/components/bt/bluedroid/stack/sdp/sdp_server.c new file mode 100755 index 0000000000..333b3e68ab --- /dev/null +++ b/components/bt/bluedroid/stack/sdp/sdp_server.c @@ -0,0 +1,908 @@ +/****************************************************************************** + * + * Copyright (C) 1999-2012 Broadcom Corporation + * + * 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 functions that handle the SDP server functions. + * This is mainly dealing with client requests + * + ******************************************************************************/ + +//#include +#include +//#include + +#include "gki.h" +#include "bt_types.h" +//#include "bt_utils.h" +#include "btu.h" +#include "bt_defs.h" +#include "l2cdefs.h" +#include "hcidefs.h" +#include "hcimsgs.h" + +#include "sdp_api.h" +#include "sdpint.h" + + +#if SDP_SERVER_ENABLED == TRUE + +/* Maximum number of bytes to reserve out of SDP MTU for response data */ +#define SDP_MAX_SERVICE_RSPHDR_LEN 12 +#define SDP_MAX_SERVATTR_RSPHDR_LEN 10 +#define SDP_MAX_ATTR_RSPHDR_LEN 10 + +/********************************************************************************/ +/* L O C A L F U N C T I O N P R O T O T Y P E S */ +/********************************************************************************/ +static void process_service_search (tCONN_CB *p_ccb, UINT16 trans_num, + UINT16 param_len, UINT8 *p_req, + UINT8 *p_req_end); + +static void process_service_attr_req (tCONN_CB *p_ccb, UINT16 trans_num, + UINT16 param_len, UINT8 *p_req, + UINT8 *p_req_end); + +static void process_service_search_attr_req (tCONN_CB *p_ccb, UINT16 trans_num, + UINT16 param_len, UINT8 *p_req, + UINT8 *p_req_end); + + +/********************************************************************************/ +/* E R R O R T E X T S T R I N G S */ +/* */ +/* The default is to have no text string, but we allow the strings to be */ +/* configured in target.h if people want them. */ +/********************************************************************************/ +#ifndef SDP_TEXT_BAD_HEADER +#define SDP_TEXT_BAD_HEADER NULL +#endif + +#ifndef SDP_TEXT_BAD_PDU +#define SDP_TEXT_BAD_PDU NULL +#endif + +#ifndef SDP_TEXT_BAD_UUID_LIST +#define SDP_TEXT_BAD_UUID_LIST NULL +#endif + +#ifndef SDP_TEXT_BAD_HANDLE +#define SDP_TEXT_BAD_HANDLE NULL +#endif + +#ifndef SDP_TEXT_BAD_ATTR_LIST +#define SDP_TEXT_BAD_ATTR_LIST NULL +#endif + +#ifndef SDP_TEXT_BAD_CONT_LEN +#define SDP_TEXT_BAD_CONT_LEN NULL +#endif + +#ifndef SDP_TEXT_BAD_CONT_INX +#define SDP_TEXT_BAD_CONT_INX NULL +#endif + +#ifndef SDP_TEXT_BAD_MAX_RECORDS_LIST +#define SDP_TEXT_BAD_MAX_RECORDS_LIST NULL +#endif + +/******************************************************************************* +** +** Function sdp_server_handle_client_req +** +** Description This is the main dispatcher of the SDP server. It is called +** when any data is received from L2CAP, and dispatches the +** request to the appropriate handler. +** +** Returns void +** +*******************************************************************************/ +void sdp_server_handle_client_req (tCONN_CB *p_ccb, BT_HDR *p_msg) +{ + UINT8 *p_req = (UINT8 *) (p_msg + 1) + p_msg->offset; + UINT8 *p_req_end = p_req + p_msg->len; + UINT8 pdu_id; + UINT16 trans_num, param_len; + + + /* Start inactivity timer */ + btu_start_timer (&p_ccb->timer_entry, BTU_TTYPE_SDP, SDP_INACT_TIMEOUT); + + /* The first byte in the message is the pdu type */ + pdu_id = *p_req++; + + /* Extract the transaction number and parameter length */ + BE_STREAM_TO_UINT16 (trans_num, p_req); + BE_STREAM_TO_UINT16 (param_len, p_req); + + if ((p_req + param_len) != p_req_end) + { + sdpu_build_n_send_error (p_ccb, trans_num, SDP_INVALID_PDU_SIZE, SDP_TEXT_BAD_HEADER); + return; + } + + switch (pdu_id) + { + case SDP_PDU_SERVICE_SEARCH_REQ: + process_service_search (p_ccb, trans_num, param_len, p_req, p_req_end); + break; + + case SDP_PDU_SERVICE_ATTR_REQ: + process_service_attr_req (p_ccb, trans_num, param_len, p_req, p_req_end); + break; + + case SDP_PDU_SERVICE_SEARCH_ATTR_REQ: + process_service_search_attr_req (p_ccb, trans_num, param_len, p_req, p_req_end); + break; + + default: + sdpu_build_n_send_error (p_ccb, trans_num, SDP_INVALID_REQ_SYNTAX, SDP_TEXT_BAD_PDU); + SDP_TRACE_WARNING ("SDP - server got unknown PDU: 0x%x", pdu_id); + break; + } +} + + + +/******************************************************************************* +** +** Function process_service_search +** +** Description This function handles a service search request from the +** client. It builds a reply message with info from the database, +** and sends the reply back to the client. +** +** Returns void +** +*******************************************************************************/ +static void process_service_search (tCONN_CB *p_ccb, UINT16 trans_num, + UINT16 param_len, UINT8 *p_req, + UINT8 *p_req_end) +{ + UINT16 max_replies, cur_handles, rem_handles, cont_offset; + tSDP_UUID_SEQ uid_seq; + UINT8 *p_rsp, *p_rsp_start, *p_rsp_param_len; + UINT16 rsp_param_len, num_rsp_handles, xx; + UINT32 rsp_handles[SDP_MAX_RECORDS] = {0}; + tSDP_RECORD *p_rec = NULL; + BT_HDR *p_buf; + BOOLEAN is_cont = FALSE; + UNUSED(p_req_end); + + p_req = sdpu_extract_uid_seq (p_req, param_len, &uid_seq); + + if ((!p_req) || (!uid_seq.num_uids)) + { + sdpu_build_n_send_error (p_ccb, trans_num, SDP_INVALID_REQ_SYNTAX, SDP_TEXT_BAD_UUID_LIST); + return; + } + + /* Get the max replies we can send. Cap it at our max anyways. */ + BE_STREAM_TO_UINT16 (max_replies, p_req); + + if (max_replies > SDP_MAX_RECORDS) + max_replies = SDP_MAX_RECORDS; + + + if ((!p_req) || (p_req > p_req_end)) + { + sdpu_build_n_send_error (p_ccb, trans_num, SDP_INVALID_REQ_SYNTAX, SDP_TEXT_BAD_MAX_RECORDS_LIST); + return; + } + + + /* Get a list of handles that match the UUIDs given to us */ + for (num_rsp_handles = 0; num_rsp_handles < max_replies; ) + { + p_rec = sdp_db_service_search (p_rec, &uid_seq); + + if (p_rec) + rsp_handles[num_rsp_handles++] = p_rec->record_handle; + else + break; + } + + /* Check if this is a continuation request */ + if (*p_req) + { + if (*p_req++ != SDP_CONTINUATION_LEN || (p_req >= p_req_end)) + { + sdpu_build_n_send_error (p_ccb, trans_num, SDP_INVALID_CONT_STATE, + SDP_TEXT_BAD_CONT_LEN); + return; + } + BE_STREAM_TO_UINT16 (cont_offset, p_req); + + if (cont_offset != p_ccb->cont_offset) + { + sdpu_build_n_send_error (p_ccb, trans_num, SDP_INVALID_CONT_STATE, + SDP_TEXT_BAD_CONT_INX); + return; + } + + rem_handles = num_rsp_handles - cont_offset; /* extract the remaining handles */ + } + else + { + rem_handles = num_rsp_handles; + cont_offset = 0; + p_ccb->cont_offset = 0; + } + + /* Calculate how many handles will fit in one PDU */ + cur_handles = (UINT16)((p_ccb->rem_mtu_size - SDP_MAX_SERVICE_RSPHDR_LEN) / 4); + + if (rem_handles <= cur_handles) + cur_handles = rem_handles; + else /* Continuation is set */ + { + p_ccb->cont_offset += cur_handles; + is_cont = TRUE; + } + + /* Get a buffer to use to build the response */ + if ((p_buf = (BT_HDR *)GKI_getpoolbuf (SDP_POOL_ID)) == NULL) + { + SDP_TRACE_ERROR ("SDP - no buf for search rsp"); + return; + } + p_buf->offset = L2CAP_MIN_OFFSET; + p_rsp = p_rsp_start = (UINT8 *)(p_buf + 1) + L2CAP_MIN_OFFSET; + + /* Start building a rsponse */ + UINT8_TO_BE_STREAM (p_rsp, SDP_PDU_SERVICE_SEARCH_RSP); + UINT16_TO_BE_STREAM (p_rsp, trans_num); + + /* Skip the length, we need to add it at the end */ + p_rsp_param_len = p_rsp; + p_rsp += 2; + + /* Put in total and current number of handles, and handles themselves */ + UINT16_TO_BE_STREAM (p_rsp, num_rsp_handles); + UINT16_TO_BE_STREAM (p_rsp, cur_handles); + +/* SDP_TRACE_DEBUG("SDP Service Rsp: tothdl %d, curhdlr %d, start %d, end %d, cont %d", + num_rsp_handles, cur_handles, cont_offset, + cont_offset + cur_handles-1, is_cont); */ + for (xx = cont_offset; xx < cont_offset + cur_handles; xx++) + UINT32_TO_BE_STREAM (p_rsp, rsp_handles[xx]); + + if (is_cont) + { + UINT8_TO_BE_STREAM (p_rsp, SDP_CONTINUATION_LEN); + UINT16_TO_BE_STREAM (p_rsp, p_ccb->cont_offset); + } + else + UINT8_TO_BE_STREAM (p_rsp, 0); + + /* Go back and put the parameter length into the buffer */ + rsp_param_len = p_rsp - p_rsp_param_len - 2; + UINT16_TO_BE_STREAM (p_rsp_param_len, rsp_param_len); + + /* Set the length of the SDP data in the buffer */ + p_buf->len = p_rsp - p_rsp_start; + + + /* Send the buffer through L2CAP */ + L2CA_DataWrite (p_ccb->connection_id, p_buf); +} + + +/******************************************************************************* +** +** Function process_service_attr_req +** +** Description This function handles an attribute request from the client. +** It builds a reply message with info from the database, +** and sends the reply back to the client. +** +** Returns void +** +*******************************************************************************/ +static void process_service_attr_req (tCONN_CB *p_ccb, UINT16 trans_num, + UINT16 param_len, UINT8 *p_req, + UINT8 *p_req_end) +{ + UINT16 max_list_len, len_to_send, cont_offset; + INT16 rem_len; + tSDP_ATTR_SEQ attr_seq, attr_seq_sav; + UINT8 *p_rsp, *p_rsp_start, *p_rsp_param_len; + UINT16 rsp_param_len, xx; + UINT32 rec_handle; + tSDP_RECORD *p_rec; + tSDP_ATTRIBUTE *p_attr; + BT_HDR *p_buf; + BOOLEAN is_cont = FALSE; + UINT16 attr_len; + + /* Extract the record handle */ + BE_STREAM_TO_UINT32 (rec_handle, p_req); + + if (p_req > p_req_end) + { + sdpu_build_n_send_error (p_ccb, trans_num, SDP_INVALID_SERV_REC_HDL, SDP_TEXT_BAD_HANDLE); + return; + } + + /* Get the max list length we can send. Cap it at MTU size minus overhead */ + BE_STREAM_TO_UINT16 (max_list_len, p_req); + + if (max_list_len > (p_ccb->rem_mtu_size - SDP_MAX_ATTR_RSPHDR_LEN)) + max_list_len = p_ccb->rem_mtu_size - SDP_MAX_ATTR_RSPHDR_LEN; + + p_req = sdpu_extract_attr_seq (p_req, param_len, &attr_seq); + + if ((!p_req) || (!attr_seq.num_attr) || (p_req > p_req_end)) + { + sdpu_build_n_send_error (p_ccb, trans_num, SDP_INVALID_REQ_SYNTAX, SDP_TEXT_BAD_ATTR_LIST); + return; + } + + memcpy(&attr_seq_sav, &attr_seq, sizeof(tSDP_ATTR_SEQ)) ; + + /* Find a record with the record handle */ + p_rec = sdp_db_find_record (rec_handle); + if (!p_rec) + { + sdpu_build_n_send_error (p_ccb, trans_num, SDP_INVALID_SERV_REC_HDL, SDP_TEXT_BAD_HANDLE); + return; + } + + /* Check if this is a continuation request */ + if (*p_req) + { + /* Free and reallocate buffer */ + if (p_ccb->rsp_list) + GKI_freebuf(p_ccb->rsp_list); + + p_ccb->rsp_list = (UINT8 *)GKI_getbuf(max_list_len); + if (p_ccb->rsp_list == NULL) + { + SDP_TRACE_ERROR("%s No scratch buf for attr rsp", __func__); + return; + } + + if (*p_req++ != SDP_CONTINUATION_LEN) + { + sdpu_build_n_send_error (p_ccb, trans_num, SDP_INVALID_CONT_STATE, SDP_TEXT_BAD_CONT_LEN); + return; + } + BE_STREAM_TO_UINT16 (cont_offset, p_req); + + if (cont_offset != p_ccb->cont_offset) + { + sdpu_build_n_send_error (p_ccb, trans_num, SDP_INVALID_CONT_STATE, SDP_TEXT_BAD_CONT_INX); + return; + } + + if (!p_ccb->rsp_list) + { + sdpu_build_n_send_error (p_ccb, trans_num, SDP_NO_RESOURCES, NULL); + return; + } + is_cont = TRUE; + + /* Initialise for continuation response */ + p_rsp = &p_ccb->rsp_list[0]; + attr_seq.attr_entry[p_ccb->cont_info.next_attr_index].start = p_ccb->cont_info.next_attr_start_id; + } + else + { + /* Get a scratch buffer to store response */ + if (!p_ccb->rsp_list || (GKI_get_buf_size(p_ccb->rsp_list) < max_list_len)) + { + /* Free and reallocate if the earlier allocated buffer is small */ + if (p_ccb->rsp_list) + { + GKI_freebuf (p_ccb->rsp_list); + } + + p_ccb->rsp_list = (UINT8 *)GKI_getbuf (max_list_len); + if (p_ccb->rsp_list == NULL) + { + SDP_TRACE_ERROR ("SDP - no scratch buf for search rsp"); + return; + } + } + + p_ccb->cont_offset = 0; + p_rsp = &p_ccb->rsp_list[3]; /* Leave space for data elem descr */ + + /* Reset continuation parameters in p_ccb */ + p_ccb->cont_info.prev_sdp_rec = NULL; + p_ccb->cont_info.next_attr_index = 0; + p_ccb->cont_info.attr_offset = 0; + } + + /* Search for attributes that match the list given to us */ + for (xx = p_ccb->cont_info.next_attr_index; xx < attr_seq.num_attr; xx++) + { + p_attr = sdp_db_find_attr_in_rec (p_rec, attr_seq.attr_entry[xx].start, attr_seq.attr_entry[xx].end); + + if (p_attr) + { + /* Check if attribute fits. Assume 3-byte value type/length */ + rem_len = max_list_len - (INT16) (p_rsp - &p_ccb->rsp_list[0]); + + /* just in case */ + if (rem_len <= 0) + { + p_ccb->cont_info.next_attr_index = xx; + p_ccb->cont_info.next_attr_start_id = p_attr->id; + break; + } + + attr_len = sdpu_get_attrib_entry_len(p_attr); + /* if there is a partial attribute pending to be sent */ + if (p_ccb->cont_info.attr_offset) + { + p_rsp = sdpu_build_partial_attrib_entry (p_rsp, p_attr, rem_len, + &p_ccb->cont_info.attr_offset); + + /* If the partial attrib could not been fully added yet */ + if (p_ccb->cont_info.attr_offset != attr_len) + break; + else /* If the partial attrib has been added in full by now */ + p_ccb->cont_info.attr_offset = 0; /* reset attr_offset */ + } + else if (rem_len < attr_len) /* Not enough space for attr... so add partially */ + { + if (attr_len >= SDP_MAX_ATTR_LEN) + { + SDP_TRACE_ERROR("SDP attr too big: max_list_len=%d,attr_len=%d", max_list_len, attr_len); + sdpu_build_n_send_error (p_ccb, trans_num, SDP_NO_RESOURCES, NULL); + return; + } + + /* add the partial attribute if possible */ + p_rsp = sdpu_build_partial_attrib_entry (p_rsp, p_attr, (UINT16)rem_len, + &p_ccb->cont_info.attr_offset); + + p_ccb->cont_info.next_attr_index = xx; + p_ccb->cont_info.next_attr_start_id = p_attr->id; + break; + } + else /* build the whole attribute */ + p_rsp = sdpu_build_attrib_entry (p_rsp, p_attr); + + /* If doing a range, stick with this one till no more attributes found */ + if (attr_seq.attr_entry[xx].start != attr_seq.attr_entry[xx].end) + { + /* Update for next time through */ + attr_seq.attr_entry[xx].start = p_attr->id + 1; + + xx--; + } + } + } + /* If all the attributes have been accomodated in p_rsp, + reset next_attr_index */ + if (xx == attr_seq.num_attr) + p_ccb->cont_info.next_attr_index = 0; + + len_to_send = (UINT16) (p_rsp - &p_ccb->rsp_list[0]); + cont_offset = 0; + + if (!is_cont) + { + p_ccb->list_len = sdpu_get_attrib_seq_len(p_rec, &attr_seq_sav) + 3; + /* Put in the sequence header (2 or 3 bytes) */ + if (p_ccb->list_len > 255) + { + p_ccb->rsp_list[0] = (UINT8) ((DATA_ELE_SEQ_DESC_TYPE << 3) | SIZE_IN_NEXT_WORD); + p_ccb->rsp_list[1] = (UINT8) ((p_ccb->list_len - 3) >> 8); + p_ccb->rsp_list[2] = (UINT8) (p_ccb->list_len - 3); + } + else + { + cont_offset = 1; + + p_ccb->rsp_list[1] = (UINT8) ((DATA_ELE_SEQ_DESC_TYPE << 3) | SIZE_IN_NEXT_BYTE); + p_ccb->rsp_list[2] = (UINT8) (p_ccb->list_len - 3); + + p_ccb->list_len--; + len_to_send--; + } + } + + /* Get a buffer to use to build the response */ + if ((p_buf = (BT_HDR *)GKI_getpoolbuf (SDP_POOL_ID)) == NULL) + { + SDP_TRACE_ERROR ("SDP - no buf for search rsp"); + return; + } + p_buf->offset = L2CAP_MIN_OFFSET; + p_rsp = p_rsp_start = (UINT8 *)(p_buf + 1) + L2CAP_MIN_OFFSET; + + /* Start building a rsponse */ + UINT8_TO_BE_STREAM (p_rsp, SDP_PDU_SERVICE_ATTR_RSP); + UINT16_TO_BE_STREAM (p_rsp, trans_num); + + /* Skip the parameter length, add it when we know the length */ + p_rsp_param_len = p_rsp; + p_rsp += 2; + + UINT16_TO_BE_STREAM (p_rsp, len_to_send); + + memcpy (p_rsp, &p_ccb->rsp_list[cont_offset], len_to_send); + p_rsp += len_to_send; + + p_ccb->cont_offset += len_to_send; + + /* If anything left to send, continuation needed */ + if (p_ccb->cont_offset < p_ccb->list_len) + { + is_cont = TRUE; + + UINT8_TO_BE_STREAM (p_rsp, SDP_CONTINUATION_LEN); + UINT16_TO_BE_STREAM (p_rsp, p_ccb->cont_offset); + } + else + UINT8_TO_BE_STREAM (p_rsp, 0); + + /* Go back and put the parameter length into the buffer */ + rsp_param_len = p_rsp - p_rsp_param_len - 2; + UINT16_TO_BE_STREAM (p_rsp_param_len, rsp_param_len); + + /* Set the length of the SDP data in the buffer */ + p_buf->len = p_rsp - p_rsp_start; + + + /* Send the buffer through L2CAP */ + L2CA_DataWrite (p_ccb->connection_id, p_buf); +} + + + +/******************************************************************************* +** +** Function process_service_search_attr_req +** +** Description This function handles a combined service search and attribute +** read request from the client. It builds a reply message with +** info from the database, and sends the reply back to the client. +** +** Returns void +** +*******************************************************************************/ +static void process_service_search_attr_req (tCONN_CB *p_ccb, UINT16 trans_num, + UINT16 param_len, UINT8 *p_req, + UINT8 *p_req_end) +{ + UINT16 max_list_len; + INT16 rem_len; + UINT16 len_to_send, cont_offset; + tSDP_UUID_SEQ uid_seq; + UINT8 *p_rsp, *p_rsp_start, *p_rsp_param_len; + UINT16 rsp_param_len, xx; + tSDP_RECORD *p_rec; + tSDP_ATTR_SEQ attr_seq, attr_seq_sav; + tSDP_ATTRIBUTE *p_attr; + BT_HDR *p_buf; + BOOLEAN maxxed_out = FALSE, is_cont = FALSE; + UINT8 *p_seq_start; + UINT16 seq_len, attr_len; + UNUSED(p_req_end); + + /* Extract the UUID sequence to search for */ + p_req = sdpu_extract_uid_seq (p_req, param_len, &uid_seq); + + if ((!p_req) || (!uid_seq.num_uids)) + { + sdpu_build_n_send_error (p_ccb, trans_num, SDP_INVALID_REQ_SYNTAX, SDP_TEXT_BAD_UUID_LIST); + return; + } + + /* Get the max list length we can send. Cap it at our max list length. */ + BE_STREAM_TO_UINT16 (max_list_len, p_req); + + if (max_list_len > (p_ccb->rem_mtu_size - SDP_MAX_SERVATTR_RSPHDR_LEN)) + max_list_len = p_ccb->rem_mtu_size - SDP_MAX_SERVATTR_RSPHDR_LEN; + + p_req = sdpu_extract_attr_seq (p_req, param_len, &attr_seq); + + if ((!p_req) || (!attr_seq.num_attr)) + { + sdpu_build_n_send_error (p_ccb, trans_num, SDP_INVALID_REQ_SYNTAX, SDP_TEXT_BAD_ATTR_LIST); + return; + } + + memcpy(&attr_seq_sav, &attr_seq, sizeof(tSDP_ATTR_SEQ)) ; + + /* Check if this is a continuation request */ + if (*p_req) + { + /* Free and reallocate buffer */ + if (p_ccb->rsp_list) + { + GKI_freebuf (p_ccb->rsp_list); + } + + p_ccb->rsp_list = (UINT8 *)GKI_getbuf (max_list_len); + if (p_ccb->rsp_list == NULL) + { + SDP_TRACE_ERROR ("SDP - no scratch buf for search rsp"); + return; + } + + if (*p_req++ != SDP_CONTINUATION_LEN) + { + sdpu_build_n_send_error (p_ccb, trans_num, SDP_INVALID_CONT_STATE, SDP_TEXT_BAD_CONT_LEN); + return; + } + BE_STREAM_TO_UINT16 (cont_offset, p_req); + + if (cont_offset != p_ccb->cont_offset) + { + sdpu_build_n_send_error (p_ccb, trans_num, SDP_INVALID_CONT_STATE, SDP_TEXT_BAD_CONT_INX); + return; + } + + if (!p_ccb->rsp_list) + { + sdpu_build_n_send_error (p_ccb, trans_num, SDP_NO_RESOURCES, NULL); + return; + } + is_cont = TRUE; + + /* Initialise for continuation response */ + p_rsp = &p_ccb->rsp_list[0]; + attr_seq.attr_entry[p_ccb->cont_info.next_attr_index].start = p_ccb->cont_info.next_attr_start_id; + } + else + { + /* Get a scratch buffer to store response */ + if (!p_ccb->rsp_list || (GKI_get_buf_size(p_ccb->rsp_list) < max_list_len)) + { + /* Free and reallocate if the earlier allocated buffer is small */ + if (p_ccb->rsp_list) + { + GKI_freebuf (p_ccb->rsp_list); + } + + p_ccb->rsp_list = (UINT8 *)GKI_getbuf (max_list_len); + if (p_ccb->rsp_list == NULL) + { + SDP_TRACE_ERROR ("SDP - no scratch buf for search rsp"); + return; + } + } + + p_ccb->cont_offset = 0; + p_rsp = &p_ccb->rsp_list[3]; /* Leave space for data elem descr */ + + /* Reset continuation parameters in p_ccb */ + p_ccb->cont_info.prev_sdp_rec = NULL; + p_ccb->cont_info.next_attr_index = 0; + p_ccb->cont_info.last_attr_seq_desc_sent = FALSE; + p_ccb->cont_info.attr_offset = 0; + } + + /* Get a list of handles that match the UUIDs given to us */ + for (p_rec = sdp_db_service_search (p_ccb->cont_info.prev_sdp_rec, &uid_seq); p_rec; p_rec = sdp_db_service_search (p_rec, &uid_seq)) + { + /* Allow space for attribute sequence type and length */ + p_seq_start = p_rsp; + if (p_ccb->cont_info.last_attr_seq_desc_sent == FALSE) + { + /* See if there is enough room to include a new service in the current response */ + rem_len = max_list_len - (INT16) (p_rsp - &p_ccb->rsp_list[0]); + if (rem_len < 3) + { + /* Not enough room. Update continuation info for next response */ + p_ccb->cont_info.next_attr_index = 0; + p_ccb->cont_info.next_attr_start_id = attr_seq.attr_entry[0].start; + break; + } + p_rsp += 3; + } + + /* Get a list of handles that match the UUIDs given to us */ + for (xx = p_ccb->cont_info.next_attr_index; xx < attr_seq.num_attr; xx++) + { + p_attr = sdp_db_find_attr_in_rec (p_rec, attr_seq.attr_entry[xx].start, attr_seq.attr_entry[xx].end); + + if (p_attr) + { + /* Check if attribute fits. Assume 3-byte value type/length */ + rem_len = max_list_len - (INT16) (p_rsp - &p_ccb->rsp_list[0]); + + /* just in case */ + if (rem_len <= 0) + { + p_ccb->cont_info.next_attr_index = xx; + p_ccb->cont_info.next_attr_start_id = p_attr->id; + maxxed_out = TRUE; + break; + } + + attr_len = sdpu_get_attrib_entry_len(p_attr); + /* if there is a partial attribute pending to be sent */ + if (p_ccb->cont_info.attr_offset) + { + p_rsp = sdpu_build_partial_attrib_entry (p_rsp, p_attr, rem_len, + &p_ccb->cont_info.attr_offset); + + /* If the partial attrib could not been fully added yet */ + if (p_ccb->cont_info.attr_offset != attr_len) + { + maxxed_out = TRUE; + break; + } + else /* If the partial attrib has been added in full by now */ + p_ccb->cont_info.attr_offset = 0; /* reset attr_offset */ + } + else if (rem_len < attr_len) /* Not enough space for attr... so add partially */ + { + if (attr_len >= SDP_MAX_ATTR_LEN) + { + SDP_TRACE_ERROR("SDP attr too big: max_list_len=%d,attr_len=%d", max_list_len, attr_len); + sdpu_build_n_send_error (p_ccb, trans_num, SDP_NO_RESOURCES, NULL); + return; + } + + /* add the partial attribute if possible */ + p_rsp = sdpu_build_partial_attrib_entry (p_rsp, p_attr, (UINT16)rem_len, + &p_ccb->cont_info.attr_offset); + + p_ccb->cont_info.next_attr_index = xx; + p_ccb->cont_info.next_attr_start_id = p_attr->id; + maxxed_out = TRUE; + break; + } + else /* build the whole attribute */ + p_rsp = sdpu_build_attrib_entry (p_rsp, p_attr); + + /* If doing a range, stick with this one till no more attributes found */ + if (attr_seq.attr_entry[xx].start != attr_seq.attr_entry[xx].end) + { + /* Update for next time through */ + attr_seq.attr_entry[xx].start = p_attr->id + 1; + + xx--; + } + } + } + + /* Go back and put the type and length into the buffer */ + if (p_ccb->cont_info.last_attr_seq_desc_sent == FALSE) + { + seq_len = sdpu_get_attrib_seq_len(p_rec, &attr_seq_sav); + if (seq_len != 0) + { + UINT8_TO_BE_STREAM (p_seq_start, (DATA_ELE_SEQ_DESC_TYPE << 3) | SIZE_IN_NEXT_WORD); + UINT16_TO_BE_STREAM (p_seq_start, seq_len); + + if (maxxed_out) + p_ccb->cont_info.last_attr_seq_desc_sent = TRUE; + } + else + p_rsp = p_seq_start; + } + + if (maxxed_out) + break; + + /* Restore the attr_seq to look for in the next sdp record */ + memcpy(&attr_seq, &attr_seq_sav, sizeof(tSDP_ATTR_SEQ)) ; + + /* Reset the next attr index */ + p_ccb->cont_info.next_attr_index = 0; + p_ccb->cont_info.prev_sdp_rec = p_rec; + p_ccb->cont_info.last_attr_seq_desc_sent = FALSE; + } + + /* response length */ + len_to_send = (UINT16) (p_rsp - &p_ccb->rsp_list[0]); + cont_offset = 0; + + // The current SDP server design has a critical flaw where it can run into an infinite + // request/response loop with the client. Here's the scenario: + // - client makes SDP request + // - server returns the first fragment of the response with a continuation token + // - an SDP record is deleted from the server + // - client issues another request with previous continuation token + // - server has nothing to send back because the record is unavailable but in the + // first fragment, it had specified more response bytes than are now available + // - server sends back no additional response bytes and returns the same continuation token + // - client issues another request with the continuation token, and the process repeats + // + // We work around this design flaw here by checking if we will make forward progress + // (i.e. we will send > 0 response bytes) on a continued request. If not, we must have + // run into the above situation and we tell the peer an error occurred. + // + // TODO(sharvil): rewrite SDP server. + if (is_cont && len_to_send == 0) { + sdpu_build_n_send_error(p_ccb, trans_num, SDP_INVALID_CONT_STATE, NULL); + return; + } + + /* If first response, insert sequence header */ + if (!is_cont) + { + /* Get the total list length for requested uid and attribute sequence */ + p_ccb->list_len = sdpu_get_list_len(&uid_seq, &attr_seq_sav) + 3; + /* Put in the sequence header (2 or 3 bytes) */ + if (p_ccb->list_len > 255) + { + p_ccb->rsp_list[0] = (UINT8) ((DATA_ELE_SEQ_DESC_TYPE << 3) | SIZE_IN_NEXT_WORD); + p_ccb->rsp_list[1] = (UINT8) ((p_ccb->list_len - 3) >> 8); + p_ccb->rsp_list[2] = (UINT8) (p_ccb->list_len - 3); + } + else + { + cont_offset = 1; + + p_ccb->rsp_list[1] = (UINT8) ((DATA_ELE_SEQ_DESC_TYPE << 3) | SIZE_IN_NEXT_BYTE); + p_ccb->rsp_list[2] = (UINT8) (p_ccb->list_len - 3); + + p_ccb->list_len--; + len_to_send--; + } + } + + /* Get a buffer to use to build the response */ + if ((p_buf = (BT_HDR *)GKI_getpoolbuf (SDP_POOL_ID)) == NULL) + { + SDP_TRACE_ERROR ("SDP - no buf for search rsp"); + return; + } + p_buf->offset = L2CAP_MIN_OFFSET; + p_rsp = p_rsp_start = (UINT8 *)(p_buf + 1) + L2CAP_MIN_OFFSET; + + /* Start building a rsponse */ + UINT8_TO_BE_STREAM (p_rsp, SDP_PDU_SERVICE_SEARCH_ATTR_RSP); + UINT16_TO_BE_STREAM (p_rsp, trans_num); + + /* Skip the parameter length, add it when we know the length */ + p_rsp_param_len = p_rsp; + p_rsp += 2; + + /* Stream the list length to send */ + UINT16_TO_BE_STREAM (p_rsp, len_to_send); + + /* copy from rsp_list to the actual buffer to be sent */ + memcpy (p_rsp, &p_ccb->rsp_list[cont_offset], len_to_send); + p_rsp += len_to_send; + + p_ccb->cont_offset += len_to_send; + + /* If anything left to send, continuation needed */ + if (p_ccb->cont_offset < p_ccb->list_len) + { + is_cont = TRUE; + + UINT8_TO_BE_STREAM (p_rsp, SDP_CONTINUATION_LEN); + UINT16_TO_BE_STREAM (p_rsp, p_ccb->cont_offset); + } + else + UINT8_TO_BE_STREAM (p_rsp, 0); + + /* Go back and put the parameter length into the buffer */ + rsp_param_len = p_rsp - p_rsp_param_len - 2; + UINT16_TO_BE_STREAM (p_rsp_param_len, rsp_param_len); + + /* Set the length of the SDP data in the buffer */ + p_buf->len = p_rsp - p_rsp_start; + + + /* Send the buffer through L2CAP */ + L2CA_DataWrite (p_ccb->connection_id, p_buf); +} + +#endif /* SDP_SERVER_ENABLED == TRUE */ diff --git a/components/bt/bluedroid/stack/sdp/sdp_utils.c b/components/bt/bluedroid/stack/sdp/sdp_utils.c new file mode 100755 index 0000000000..6e3130b53d --- /dev/null +++ b/components/bt/bluedroid/stack/sdp/sdp_utils.c @@ -0,0 +1,1062 @@ +/****************************************************************************** + * + * Copyright (C) 1999-2012 Broadcom Corporation + * + * 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 SDP utility functions + * + ******************************************************************************/ + +#include +#include +//#include +//#include + +#include "bt_defs.h" + +#include "gki.h" +#include "bt_types.h" + +#include "l2cdefs.h" +#include "hcidefs.h" +#include "hcimsgs.h" + +#include "sdp_api.h" +#include "sdpint.h" + +#include "btu.h" + + +static const UINT8 sdp_base_uuid[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, + 0x80, 0x00, 0x00, 0x80, 0x5F, 0x9B, 0x34, 0xFB}; + +/******************************************************************************* +** +** Function sdpu_find_ccb_by_cid +** +** Description This function searches the CCB table for an entry with the +** passed CID. +** +** Returns the CCB address, or NULL if not found. +** +*******************************************************************************/ +tCONN_CB *sdpu_find_ccb_by_cid (UINT16 cid) +{ + UINT16 xx; + tCONN_CB *p_ccb; + + /* Look through each connection control block */ + for (xx = 0, p_ccb = sdp_cb.ccb; xx < SDP_MAX_CONNECTIONS; xx++, p_ccb++) + { + if ((p_ccb->con_state != SDP_STATE_IDLE) && (p_ccb->connection_id == cid)) + return (p_ccb); + } + + /* If here, not found */ + return (NULL); +} + + +/******************************************************************************* +** +** Function sdpu_find_ccb_by_db +** +** Description This function searches the CCB table for an entry with the +** passed discovery db. +** +** Returns the CCB address, or NULL if not found. +** +*******************************************************************************/ +tCONN_CB *sdpu_find_ccb_by_db (tSDP_DISCOVERY_DB *p_db) +{ +#if SDP_CLIENT_ENABLED == TRUE + UINT16 xx; + tCONN_CB *p_ccb; + + if (p_db) + { + /* Look through each connection control block */ + for (xx = 0, p_ccb = sdp_cb.ccb; xx < SDP_MAX_CONNECTIONS; xx++, p_ccb++) + { + if ((p_ccb->con_state != SDP_STATE_IDLE) && (p_ccb->p_db == p_db)) + return (p_ccb); + } + } +#endif + /* If here, not found */ + return (NULL); +} + + +/******************************************************************************* +** +** Function sdpu_allocate_ccb +** +** Description This function allocates a new CCB. +** +** Returns CCB address, or NULL if none available. +** +*******************************************************************************/ +tCONN_CB *sdpu_allocate_ccb (void) +{ + UINT16 xx; + tCONN_CB *p_ccb; + + /* Look through each connection control block for a free one */ + for (xx = 0, p_ccb = sdp_cb.ccb; xx < SDP_MAX_CONNECTIONS; xx++, p_ccb++) + { + if (p_ccb->con_state == SDP_STATE_IDLE) + { + memset (p_ccb, 0, sizeof (tCONN_CB)); + + p_ccb->timer_entry.param = (UINT32) p_ccb; + + return (p_ccb); + } + } + + /* If here, no free CCB found */ + return (NULL); +} + + +/******************************************************************************* +** +** Function sdpu_release_ccb +** +** Description This function releases a CCB. +** +** Returns void +** +*******************************************************************************/ +void sdpu_release_ccb (tCONN_CB *p_ccb) +{ + /* Ensure timer is stopped */ + btu_stop_timer (&p_ccb->timer_entry); + + /* Drop any response pointer we may be holding */ + p_ccb->con_state = SDP_STATE_IDLE; +#if SDP_CLIENT_ENABLED == TRUE + p_ccb->is_attr_search = FALSE; +#endif + + /* Free the response buffer */ + if (p_ccb->rsp_list) + { + SDP_TRACE_DEBUG("releasing SDP rsp_list"); + + GKI_freebuf(p_ccb->rsp_list); + p_ccb->rsp_list = NULL; + } +} + + +/******************************************************************************* +** +** Function sdpu_build_attrib_seq +** +** Description This function builds an attribute sequence from the list of +** passed attributes. It is also passed the address of the output +** buffer. +** +** Returns Pointer to next byte in the output buffer. +** +*******************************************************************************/ +UINT8 *sdpu_build_attrib_seq (UINT8 *p_out, UINT16 *p_attr, UINT16 num_attrs) +{ + UINT16 xx; + + /* First thing is the data element header. See if the length fits 1 byte */ + /* If no attributes, assume a 4-byte wildcard */ + if (!p_attr) + xx = 5; + else + xx = num_attrs * 3; + + if (xx > 255) + { + UINT8_TO_BE_STREAM (p_out, (DATA_ELE_SEQ_DESC_TYPE << 3) | SIZE_IN_NEXT_WORD); + UINT16_TO_BE_STREAM (p_out, xx); + } + else + { + UINT8_TO_BE_STREAM (p_out, (DATA_ELE_SEQ_DESC_TYPE << 3) | SIZE_IN_NEXT_BYTE); + UINT8_TO_BE_STREAM (p_out, xx); + } + + /* If there are no attributes specified, assume caller wants wildcard */ + if (!p_attr) + { + UINT8_TO_BE_STREAM (p_out, (UINT_DESC_TYPE << 3) | SIZE_FOUR_BYTES); + UINT16_TO_BE_STREAM (p_out, 0); + UINT16_TO_BE_STREAM (p_out, 0xFFFF); + } + else + { + /* Loop through and put in all the attributes(s) */ + for (xx = 0; xx < num_attrs; xx++, p_attr++) + { + UINT8_TO_BE_STREAM (p_out, (UINT_DESC_TYPE << 3) | SIZE_TWO_BYTES); + UINT16_TO_BE_STREAM (p_out, *p_attr); + } + } + + return (p_out); +} + + +/******************************************************************************* +** +** Function sdpu_build_attrib_entry +** +** Description This function builds an attribute entry from the passed +** attribute record. It is also passed the address of the output +** buffer. +** +** Returns Pointer to next byte in the output buffer. +** +*******************************************************************************/ +UINT8 *sdpu_build_attrib_entry (UINT8 *p_out, tSDP_ATTRIBUTE *p_attr) +{ + /* First, store the attribute ID. Goes as a UINT */ + UINT8_TO_BE_STREAM (p_out, (UINT_DESC_TYPE << 3) | SIZE_TWO_BYTES); + UINT16_TO_BE_STREAM (p_out, p_attr->id); + + /* the attribute is in the db record. + * assuming the attribute len is less than SDP_MAX_ATTR_LEN */ + switch(p_attr->type) + { + case TEXT_STR_DESC_TYPE: /* 4 */ + case DATA_ELE_SEQ_DESC_TYPE:/* 6 */ + case DATA_ELE_ALT_DESC_TYPE:/* 7 */ + case URL_DESC_TYPE: /* 8 */ +#if (SDP_MAX_ATTR_LEN > 0xFFFF) + if(p_attr->len > 0xFFFF) + { + UINT8_TO_BE_STREAM (p_out, (p_attr->type << 3) | SIZE_IN_NEXT_LONG); + UINT32_TO_BE_STREAM (p_out, p_attr->len); + } + else + +#endif /* 0xFFFF - 0xFF */ +#if (SDP_MAX_ATTR_LEN > 0xFF) + if(p_attr->len > 0xFF) + { + UINT8_TO_BE_STREAM (p_out, (p_attr->type << 3) | SIZE_IN_NEXT_WORD); + UINT16_TO_BE_STREAM (p_out, p_attr->len); + } + else + +#endif /* 0xFF and less*/ + { + UINT8_TO_BE_STREAM (p_out, (p_attr->type << 3) | SIZE_IN_NEXT_BYTE); + UINT8_TO_BE_STREAM (p_out, p_attr->len); + } + + if (p_attr->value_ptr != NULL) { + ARRAY_TO_BE_STREAM (p_out, p_attr->value_ptr, (int)p_attr->len); + } + + return (p_out); + } + + /* Now, store the attribute value */ + switch (p_attr->len) + { + case 1: + UINT8_TO_BE_STREAM (p_out, (p_attr->type << 3) | SIZE_ONE_BYTE); + break; + case 2: + UINT8_TO_BE_STREAM (p_out, (p_attr->type << 3) | SIZE_TWO_BYTES); + break; + case 4: + UINT8_TO_BE_STREAM (p_out, (p_attr->type << 3) | SIZE_FOUR_BYTES); + break; + case 8: + UINT8_TO_BE_STREAM (p_out, (p_attr->type << 3) | SIZE_EIGHT_BYTES); + break; + case 16: + UINT8_TO_BE_STREAM (p_out, (p_attr->type << 3) | SIZE_SIXTEEN_BYTES); + break; + default: + UINT8_TO_BE_STREAM (p_out, (p_attr->type << 3) | SIZE_IN_NEXT_BYTE); + UINT8_TO_BE_STREAM (p_out, p_attr->len); + break; + } + + if (p_attr->value_ptr != NULL) { + ARRAY_TO_BE_STREAM (p_out, p_attr->value_ptr, (int)p_attr->len); + } + + return (p_out); +} + + +/******************************************************************************* +** +** Function sdpu_build_n_send_error +** +** Description This function builds and sends an error packet. +** +** Returns void +** +*******************************************************************************/ +void sdpu_build_n_send_error (tCONN_CB *p_ccb, UINT16 trans_num, UINT16 error_code, char *p_error_text) +{ + UINT8 *p_rsp, *p_rsp_start, *p_rsp_param_len; + UINT16 rsp_param_len; + BT_HDR *p_buf; + + + SDP_TRACE_WARNING ("SDP - sdpu_build_n_send_error code: 0x%x CID: 0x%x", + error_code, p_ccb->connection_id); + + /* Get a buffer to use to build and send the packet to L2CAP */ + if ((p_buf = (BT_HDR *)GKI_getpoolbuf (SDP_POOL_ID)) == NULL) + { + SDP_TRACE_ERROR ("SDP - no buf for err msg"); + return; + } + p_buf->offset = L2CAP_MIN_OFFSET; + p_rsp = p_rsp_start = (UINT8 *)(p_buf + 1) + L2CAP_MIN_OFFSET; + + UINT8_TO_BE_STREAM (p_rsp, SDP_PDU_ERROR_RESPONSE); + UINT16_TO_BE_STREAM (p_rsp, trans_num); + + /* Skip the parameter length, we need to add it at the end */ + p_rsp_param_len = p_rsp; + p_rsp += 2; + + UINT16_TO_BE_STREAM (p_rsp, error_code); + + /* Unplugfest example traces do not have any error text */ + if (p_error_text) + ARRAY_TO_BE_STREAM (p_rsp, p_error_text, (int) strlen (p_error_text)); + + /* Go back and put the parameter length into the buffer */ + rsp_param_len = p_rsp - p_rsp_param_len - 2; + UINT16_TO_BE_STREAM (p_rsp_param_len, rsp_param_len); + + /* Set the length of the SDP data in the buffer */ + p_buf->len = p_rsp - p_rsp_start; + + + /* Send the buffer through L2CAP */ + L2CA_DataWrite (p_ccb->connection_id, p_buf); +} + + + +/******************************************************************************* +** +** Function sdpu_extract_uid_seq +** +** Description This function extracts a UUID sequence from the passed input +** buffer, and puts it into the passed output list. +** +** Returns Pointer to next byte in the input buffer after the sequence. +** +*******************************************************************************/ +UINT8 *sdpu_extract_uid_seq (UINT8 *p, UINT16 param_len, tSDP_UUID_SEQ *p_seq) +{ + UINT8 *p_seq_end; + UINT8 descr, type, size; + UINT32 seq_len, uuid_len; + + /* Assume none found */ + p_seq->num_uids = 0; + + /* A UID sequence is composed of a bunch of UIDs. */ + + BE_STREAM_TO_UINT8 (descr, p); + type = descr >> 3; + size = descr & 7; + + if (type != DATA_ELE_SEQ_DESC_TYPE) + return (NULL); + + switch (size) + { + case SIZE_TWO_BYTES: + seq_len = 2; + break; + case SIZE_FOUR_BYTES: + seq_len = 4; + break; + case SIZE_SIXTEEN_BYTES: + seq_len = 16; + break; + case SIZE_IN_NEXT_BYTE: + BE_STREAM_TO_UINT8 (seq_len, p); + break; + case SIZE_IN_NEXT_WORD: + BE_STREAM_TO_UINT16 (seq_len, p); + break; + case SIZE_IN_NEXT_LONG: + BE_STREAM_TO_UINT32 (seq_len, p); + break; + default: + return (NULL); + } + + if (seq_len >= param_len) + return (NULL); + + p_seq_end = p + seq_len; + + /* Loop through, extracting the UIDs */ + for ( ; p < p_seq_end ; ) + { + BE_STREAM_TO_UINT8 (descr, p); + type = descr >> 3; + size = descr & 7; + + if (type != UUID_DESC_TYPE) + return (NULL); + + switch (size) + { + case SIZE_TWO_BYTES: + uuid_len = 2; + break; + case SIZE_FOUR_BYTES: + uuid_len = 4; + break; + case SIZE_SIXTEEN_BYTES: + uuid_len = 16; + break; + case SIZE_IN_NEXT_BYTE: + BE_STREAM_TO_UINT8 (uuid_len, p); + break; + case SIZE_IN_NEXT_WORD: + BE_STREAM_TO_UINT16 (uuid_len, p); + break; + case SIZE_IN_NEXT_LONG: + BE_STREAM_TO_UINT32 (uuid_len, p); + break; + default: + return (NULL); + } + + /* If UUID length is valid, copy it across */ + if ((uuid_len == 2) || (uuid_len == 4) || (uuid_len == 16)) + { + p_seq->uuid_entry[p_seq->num_uids].len = (UINT16) uuid_len; + BE_STREAM_TO_ARRAY (p, p_seq->uuid_entry[p_seq->num_uids].value, (int)uuid_len); + p_seq->num_uids++; + } + else + return (NULL); + + /* We can only do so many */ + if (p_seq->num_uids >= MAX_UUIDS_PER_SEQ) + return (NULL); + } + + if (p != p_seq_end) + return (NULL); + + return (p); +} + + + +/******************************************************************************* +** +** Function sdpu_extract_attr_seq +** +** Description This function extracts an attribute sequence from the passed +** input buffer, and puts it into the passed output list. +** +** Returns Pointer to next byte in the input buffer after the sequence. +** +*******************************************************************************/ +UINT8 *sdpu_extract_attr_seq (UINT8 *p, UINT16 param_len, tSDP_ATTR_SEQ *p_seq) +{ + UINT8 *p_end_list; + UINT8 descr, type, size; + UINT32 list_len, attr_len; + + /* Assume none found */ + p_seq->num_attr = 0; + + /* Get attribute sequence info */ + BE_STREAM_TO_UINT8 (descr, p); + type = descr >> 3; + size = descr & 7; + + if (type != DATA_ELE_SEQ_DESC_TYPE) + return (p); + + switch (size) + { + case SIZE_IN_NEXT_BYTE: + BE_STREAM_TO_UINT8 (list_len, p); + break; + + case SIZE_IN_NEXT_WORD: + BE_STREAM_TO_UINT16 (list_len, p); + break; + + case SIZE_IN_NEXT_LONG: + BE_STREAM_TO_UINT32 (list_len, p); + break; + + default: + return (p); + } + + if (list_len > param_len) + return (p); + + p_end_list = p + list_len; + + /* Loop through, extracting the attribute IDs */ + for ( ; p < p_end_list ; ) + { + BE_STREAM_TO_UINT8 (descr, p); + type = descr >> 3; + size = descr & 7; + + if (type != UINT_DESC_TYPE) + return (p); + + switch (size) + { + case SIZE_TWO_BYTES: + attr_len = 2; + break; + case SIZE_FOUR_BYTES: + attr_len = 4; + break; + case SIZE_IN_NEXT_BYTE: + BE_STREAM_TO_UINT8 (attr_len, p); + break; + case SIZE_IN_NEXT_WORD: + BE_STREAM_TO_UINT16 (attr_len, p); + break; + case SIZE_IN_NEXT_LONG: + BE_STREAM_TO_UINT32 (attr_len, p); + break; + default: + return (NULL); + break; + } + + /* Attribute length must be 2-bytes or 4-bytes for a paired entry. */ + if (attr_len == 2) + { + BE_STREAM_TO_UINT16 (p_seq->attr_entry[p_seq->num_attr].start, p); + p_seq->attr_entry[p_seq->num_attr].end = p_seq->attr_entry[p_seq->num_attr].start; + } + else if (attr_len == 4) + { + BE_STREAM_TO_UINT16 (p_seq->attr_entry[p_seq->num_attr].start, p); + BE_STREAM_TO_UINT16 (p_seq->attr_entry[p_seq->num_attr].end, p); + } + else + return (NULL); + + /* We can only do so many */ + if (++p_seq->num_attr >= MAX_ATTR_PER_SEQ) + return (NULL); + } + + return (p); +} + + +/******************************************************************************* +** +** Function sdpu_get_len_from_type +** +** Description This function gets the length +** +** Returns void +** +*******************************************************************************/ +UINT8 *sdpu_get_len_from_type (UINT8 *p, UINT8 type, UINT32 *p_len) +{ + UINT8 u8; + UINT16 u16; + UINT32 u32; + + switch (type & 7) + { + case SIZE_ONE_BYTE: + *p_len = 1; + break; + case SIZE_TWO_BYTES: + *p_len = 2; + break; + case SIZE_FOUR_BYTES: + *p_len = 4; + break; + case SIZE_EIGHT_BYTES: + *p_len = 8; + break; + case SIZE_SIXTEEN_BYTES: + *p_len = 16; + break; + case SIZE_IN_NEXT_BYTE: + BE_STREAM_TO_UINT8 (u8, p); + *p_len = u8; + break; + case SIZE_IN_NEXT_WORD: + BE_STREAM_TO_UINT16 (u16, p); + *p_len = u16; + break; + case SIZE_IN_NEXT_LONG: + BE_STREAM_TO_UINT32 (u32, p); + *p_len = (UINT16) u32; + break; + } + + return (p); +} + + +/******************************************************************************* +** +** Function sdpu_is_base_uuid +** +** Description This function checks a 128-bit UUID with the base to see if +** it matches. Only the last 12 bytes are compared. +** +** Returns TRUE if matched, else FALSE +** +*******************************************************************************/ +BOOLEAN sdpu_is_base_uuid (UINT8 *p_uuid) +{ + UINT16 xx; + + for (xx = 4; xx < MAX_UUID_SIZE; xx++) + if (p_uuid[xx] != sdp_base_uuid[xx]) + return (FALSE); + + /* If here, matched */ + return (TRUE); +} + + +/******************************************************************************* +** +** Function sdpu_compare_uuid_arrays +** +** Description This function compares 2 BE UUIDs. If needed, they are expanded +** to 128-bit UUIDs, then compared. +** +** NOTE it is assumed that the arrays are in Big Endian format +** +** Returns TRUE if matched, else FALSE +** +*******************************************************************************/ +BOOLEAN sdpu_compare_uuid_arrays (UINT8 *p_uuid1, UINT32 len1, UINT8 *p_uuid2, UINT16 len2) +{ + UINT8 nu1[MAX_UUID_SIZE]; + UINT8 nu2[MAX_UUID_SIZE]; + + if( ((len1 != 2) && (len1 != 4) && (len1 != 16)) || + ((len2 != 2) && (len2 != 4) && (len2 != 16)) ) + { + SDP_TRACE_ERROR("%s: invalid length", __func__); + return FALSE; + } + + /* If lengths match, do a straight compare */ + if (len1 == len2) + { + if (len1 == 2) + return ((p_uuid1[0] == p_uuid2[0]) && (p_uuid1[1] == p_uuid2[1])); + if (len1 == 4) + return ( (p_uuid1[0] == p_uuid2[0]) && (p_uuid1[1] == p_uuid2[1]) + && (p_uuid1[2] == p_uuid2[2]) && (p_uuid1[3] == p_uuid2[3]) ); + else + return (memcmp (p_uuid1, p_uuid2, (size_t)len1) == 0); + } + else if (len1 > len2) + { + /* If the len1 was 4-byte, (so len2 is 2-byte), compare on the fly */ + if (len1 == 4) + { + return ( (p_uuid1[0] == 0) && (p_uuid1[1] == 0) + && (p_uuid1[2] == p_uuid2[0]) && (p_uuid1[3] == p_uuid2[1]) ); + } + else + { + /* Normalize UUIDs to 16-byte form, then compare. Len1 must be 16 */ + memcpy (nu1, p_uuid1, MAX_UUID_SIZE); + memcpy (nu2, sdp_base_uuid, MAX_UUID_SIZE); + + if (len2 == 4) + memcpy (nu2, p_uuid2, len2); + else if (len2 == 2) + memcpy (nu2 + 2, p_uuid2, len2); + + return (memcmp (nu1, nu2, MAX_UUID_SIZE) == 0); + } + } + else + { + /* len2 is greater than len1 */ + /* If the len2 was 4-byte, (so len1 is 2-byte), compare on the fly */ + if (len2 == 4) + { + return ( (p_uuid2[0] == 0) && (p_uuid2[1] == 0) + && (p_uuid2[2] == p_uuid1[0]) && (p_uuid2[3] == p_uuid1[1]) ); + } + else + { + /* Normalize UUIDs to 16-byte form, then compare. Len1 must be 16 */ + memcpy (nu2, p_uuid2, MAX_UUID_SIZE); + memcpy (nu1, sdp_base_uuid, MAX_UUID_SIZE); + + if (len1 == 4) + memcpy (nu1, p_uuid1, (size_t)len1); + else if (len1 == 2) + memcpy (nu1 + 2, p_uuid1, (size_t)len1); + + return (memcmp (nu1, nu2, MAX_UUID_SIZE) == 0); + } + } +} + + +/******************************************************************************* +** +** Function sdpu_compare_bt_uuids +** +** Description This function compares 2 BT UUID structures. +** +** NOTE it is assumed that BT UUID structures are compressed to the +** smallest possible UUIDs (by removing the base SDP UUID) +** +** Returns TRUE if matched, else FALSE +** +*******************************************************************************/ +BOOLEAN sdpu_compare_bt_uuids (tBT_UUID *p_uuid1, tBT_UUID *p_uuid2) +{ + /* Lengths must match for BT UUIDs to match */ + if (p_uuid1->len == p_uuid2->len) + { + if (p_uuid1->len == 2) + return (p_uuid1->uu.uuid16 == p_uuid2->uu.uuid16); + else if (p_uuid1->len == 4) + return (p_uuid1->uu.uuid32 == p_uuid2->uu.uuid32); + else if (!memcmp (p_uuid1->uu.uuid128, p_uuid2->uu.uuid128, 16)) + return (TRUE); + } + + return (FALSE); +} + + +/******************************************************************************* +** +** Function sdpu_compare_uuid_with_attr +** +** Description This function compares a BT UUID structure with the UUID in an +** SDP attribute record. If needed, they are expanded to 128-bit +** UUIDs, then compared. +** +** NOTE - it is assumed that BT UUID structures are compressed to the +** smallest possible UUIDs (by removing the base SDP UUID). +** - it is also assumed that the discovery atribute is compressed +** to the smallest possible +** +** Returns TRUE if matched, else FALSE +** +*******************************************************************************/ +BOOLEAN sdpu_compare_uuid_with_attr (tBT_UUID *p_btuuid, tSDP_DISC_ATTR *p_attr) +{ + UINT16 attr_len = SDP_DISC_ATTR_LEN (p_attr->attr_len_type); + + /* Since both UUIDs are compressed, lengths must match */ + if (p_btuuid->len != attr_len) + return (FALSE); + + if (p_btuuid->len == 2) + return (BOOLEAN)(p_btuuid->uu.uuid16 == p_attr->attr_value.v.u16); + else if (p_btuuid->len == 4) + return (BOOLEAN)(p_btuuid->uu.uuid32 == p_attr->attr_value.v.u32); + /* coverity[overrun-buffer-arg] */ + /* + Event overrun-buffer-arg: Overrun of static array "&p_attr->attr_value.v.array" of size 4 bytes by passing it to a function which indexes it with argument "16U" at byte position 15 + FALSE-POSITIVE error from Coverity test tool. Please do NOT remove following comment. + False-positive: SDP uses scratch buffer to hold the attribute value. + The actual size of tSDP_DISC_ATVAL does not matter. + If the array size in tSDP_DISC_ATVAL is increase, we would increase the system RAM usage unnecessarily + */ + else if (!memcmp (p_btuuid->uu.uuid128,(void*) p_attr->attr_value.v.array, MAX_UUID_SIZE)) + return (TRUE); + + return (FALSE); +} + +/******************************************************************************* +** +** Function sdpu_sort_attr_list +** +** Description sorts a list of attributes in numeric order from lowest to +** highest to conform to SDP specification +** +** Returns void +** +*******************************************************************************/ +void sdpu_sort_attr_list( UINT16 num_attr, tSDP_DISCOVERY_DB *p_db ) +{ + UINT16 i; + UINT16 x; + + /* Done if no attributes to sort */ + if (num_attr <= 1) + { + return; + } + else if (num_attr > SDP_MAX_ATTR_FILTERS) + { + num_attr = SDP_MAX_ATTR_FILTERS; + } + + num_attr--; /* for the for-loop */ + for( i = 0; i < num_attr; ) + { + if( p_db->attr_filters[i] > p_db->attr_filters[i+1] ) + { + /* swap the attribute IDs and start from the beginning */ + x = p_db->attr_filters[i]; + p_db->attr_filters[i] = p_db->attr_filters[i+1]; + p_db->attr_filters[i+1] = x; + + i = 0; + } + else + i++; + } +} + + +/******************************************************************************* +** +** Function sdpu_get_list_len +** +** Description gets the total list length in the sdp database for a given +** uid sequence and attr sequence +** +** Returns void +** +*******************************************************************************/ +UINT16 sdpu_get_list_len(tSDP_UUID_SEQ *uid_seq, tSDP_ATTR_SEQ *attr_seq) +{ + tSDP_RECORD *p_rec; + UINT16 len = 0; + UINT16 len1; + + for (p_rec = sdp_db_service_search (NULL, uid_seq); p_rec; p_rec = sdp_db_service_search (p_rec, uid_seq)) + { + len += 3; + + len1 = sdpu_get_attrib_seq_len(p_rec, attr_seq ); + + if (len1 != 0) + len += len1; + else + len -= 3; + } + return len; +} + +/******************************************************************************* +** +** Function sdpu_get_attrib_seq_len +** +** Description gets the length of the specific attributes in a given +** sdp record +** +** Returns void +** +*******************************************************************************/ +UINT16 sdpu_get_attrib_seq_len(tSDP_RECORD *p_rec, tSDP_ATTR_SEQ *attr_seq) +{ + tSDP_ATTRIBUTE *p_attr; + UINT16 len1 = 0; + UINT16 xx; + BOOLEAN is_range = FALSE; + UINT16 start_id=0, end_id=0; + + for (xx = 0; xx < attr_seq->num_attr; xx++) + { + if (is_range == FALSE) + { + start_id = attr_seq->attr_entry[xx].start; + end_id = attr_seq->attr_entry[xx].end; + } + p_attr = sdp_db_find_attr_in_rec (p_rec, + start_id, + end_id); + if (p_attr) + { + len1 += sdpu_get_attrib_entry_len (p_attr); + + /* If doing a range, stick with this one till no more attributes found */ + if (start_id != end_id) + { + /* Update for next time through */ + start_id = p_attr->id + 1; + xx--; + is_range = TRUE; + } + else + is_range = FALSE; + } + else + is_range = FALSE; + } + return len1; +} + +/******************************************************************************* +** +** Function sdpu_get_attrib_entry_len +** +** Description gets the length of a specific attribute +** +** Returns void +** +*******************************************************************************/ +UINT16 sdpu_get_attrib_entry_len(tSDP_ATTRIBUTE *p_attr) +{ + UINT16 len = 3; + + /* the attribute is in the db record. + * assuming the attribute len is less than SDP_MAX_ATTR_LEN */ + switch(p_attr->type) + { + case TEXT_STR_DESC_TYPE: /* 4 */ + case DATA_ELE_SEQ_DESC_TYPE:/* 6 */ + case DATA_ELE_ALT_DESC_TYPE:/* 7 */ + case URL_DESC_TYPE: /* 8 */ +#if (SDP_MAX_ATTR_LEN > 0xFFFF) + if(p_attr->len > 0xFFFF) + { + len += 5; + } + else + +#endif/* 0xFFFF - 0xFF */ +#if (SDP_MAX_ATTR_LEN > 0xFF) + if(p_attr->len > 0xFF) + { + len += 3; + } + else + +#endif /* 0xFF and less*/ + { + len += 2; + } + len += p_attr->len; + return len; + } + + /* Now, the attribute value */ + switch (p_attr->len) + { + case 1: + case 2: + case 4: + case 8: + case 16: + len += 1; + break; + default: + len += 2; + break; + } + + len += p_attr->len; + return len; +} + + +/******************************************************************************* +** +** Function sdpu_build_partial_attrib_entry +** +** Description This function fills a buffer with partial attribute. It is +** assumed that the maximum size of any attribute is 256 bytes. +** +** p_out: output buffer +** p_attr: attribute to be copied partially into p_out +** rem_len: num bytes to copy into p_out +** offset: current start offset within the attr that needs to be copied +** +** Returns Pointer to next byte in the output buffer. +** offset is also updated +** +*******************************************************************************/ +UINT8 *sdpu_build_partial_attrib_entry (UINT8 *p_out, tSDP_ATTRIBUTE *p_attr, UINT16 len, UINT16 *offset) +{ + UINT8 *p_attr_buff; + UINT8 *p_tmp_attr; + size_t len_to_copy; + UINT16 attr_len; + + if ((p_attr_buff = (UINT8 *) GKI_getbuf(sizeof(UINT8) * SDP_MAX_ATTR_LEN )) == NULL) + { + SDP_TRACE_ERROR("sdpu_build_partial_attrib_entry cannot get a buffer!"); + return NULL; + } + p_tmp_attr = p_attr_buff; + + sdpu_build_attrib_entry(p_tmp_attr, p_attr); + attr_len = sdpu_get_attrib_entry_len(p_attr); + + len_to_copy = ((attr_len - *offset) < len) ? (attr_len - *offset): len; + + memcpy(p_out, &p_attr_buff[*offset], len_to_copy); + + p_out = &p_out[len_to_copy]; + *offset += len_to_copy; + + GKI_freebuf(p_attr_buff); + return p_out; +} + +/******************************************************************************* +** +** Function sdpu_uuid16_to_uuid128 +** +** Description This function converts UUID-16 to UUID-128 by including the base UUID +** +** uuid16: 2-byte UUID +** p_uuid128: Expanded 128-bit UUID +** +** Returns None +** +*******************************************************************************/ + +void sdpu_uuid16_to_uuid128(UINT16 uuid16, UINT8* p_uuid128) +{ + UINT16 uuid16_bo; + memset(p_uuid128, 0, 16); + + memcpy(p_uuid128, sdp_base_uuid, MAX_UUID_SIZE); + uuid16_bo = ntohs(uuid16); + memcpy(p_uuid128+ 2, &uuid16_bo, sizeof(uint16_t)); +} diff --git a/components/bt/bluedroid/stack/smp/aes.c b/components/bt/bluedroid/stack/smp/aes.c new file mode 100755 index 0000000000..38c336b7b6 --- /dev/null +++ b/components/bt/bluedroid/stack/smp/aes.c @@ -0,0 +1,935 @@ +/* + --------------------------------------------------------------------------- + Copyright (c) 1998-2008, Brian Gladman, Worcester, UK. All rights reserved. + + LICENSE TERMS + + The redistribution and use of this software (with or without changes) + is allowed without the payment of fees or royalties provided that: + + 1. source code distributions include the above copyright notice, this + list of conditions and the following disclaimer; + + 2. binary distributions include the above copyright notice, this list + of conditions and the following disclaimer in their documentation; + + 3. the name of the copyright holder is not used to endorse products + built using this software without specific written permission. + + DISCLAIMER + + This software is provided 'as is' with no explicit or implied warranties + in respect of its properties, including, but not limited to, correctness + and/or fitness for purpose. + --------------------------------------------------------------------------- + Issue 09/09/2006 + + This is an AES implementation that uses only 8-bit byte operations on the + cipher state (there are options to use 32-bit types if available). + + The combination of mix columns and byte substitution used here is based on + that developed by Karl Malbrain. His contribution is acknowledged. + */ + +/* define if you have a fast memcpy function on your system */ +#if 1 +# define HAVE_MEMCPY +# include +#if 0 +# if defined( _MSC_VER ) +# include +# pragma intrinsic( memcpy ) +# endif +#endif +#endif + +#include + +/* add the target configuration to allow using internal data types and compilation options */ +#include "bt_target.h" + +/* define if you have fast 32-bit types on your system */ +#if 1 +# define HAVE_UINT_32T +#endif + +/* define if you don't want any tables */ +#if 1 +# define USE_TABLES +#endif + +/* On Intel Core 2 duo VERSION_1 is faster */ + +/* alternative versions (test for performance on your system) */ +#if 1 +# define VERSION_1 +#endif + +#include "aes.h" + +#if defined( HAVE_UINT_32T ) + typedef UINT32 uint_32t; +#endif + +/* functions for finite field multiplication in the AES Galois field */ + +#define WPOLY 0x011b +#define BPOLY 0x1b +#define DPOLY 0x008d + +#define f1(x) (x) +#define f2(x) ((x << 1) ^ (((x >> 7) & 1) * WPOLY)) +#define f4(x) ((x << 2) ^ (((x >> 6) & 1) * WPOLY) ^ (((x >> 6) & 2) * WPOLY)) +#define f8(x) ((x << 3) ^ (((x >> 5) & 1) * WPOLY) ^ (((x >> 5) & 2) * WPOLY) \ + ^ (((x >> 5) & 4) * WPOLY)) +#define d2(x) (((x) >> 1) ^ ((x) & 1 ? DPOLY : 0)) + +#define f3(x) (f2(x) ^ x) +#define f9(x) (f8(x) ^ x) +#define fb(x) (f8(x) ^ f2(x) ^ x) +#define fd(x) (f8(x) ^ f4(x) ^ x) +#define fe(x) (f8(x) ^ f4(x) ^ f2(x)) + +#if defined( USE_TABLES ) + +#define sb_data(w) { /* S Box data values */ \ + w(0x63), w(0x7c), w(0x77), w(0x7b), w(0xf2), w(0x6b), w(0x6f), w(0xc5),\ + w(0x30), w(0x01), w(0x67), w(0x2b), w(0xfe), w(0xd7), w(0xab), w(0x76),\ + w(0xca), w(0x82), w(0xc9), w(0x7d), w(0xfa), w(0x59), w(0x47), w(0xf0),\ + w(0xad), w(0xd4), w(0xa2), w(0xaf), w(0x9c), w(0xa4), w(0x72), w(0xc0),\ + w(0xb7), w(0xfd), w(0x93), w(0x26), w(0x36), w(0x3f), w(0xf7), w(0xcc),\ + w(0x34), w(0xa5), w(0xe5), w(0xf1), w(0x71), w(0xd8), w(0x31), w(0x15),\ + w(0x04), w(0xc7), w(0x23), w(0xc3), w(0x18), w(0x96), w(0x05), w(0x9a),\ + w(0x07), w(0x12), w(0x80), w(0xe2), w(0xeb), w(0x27), w(0xb2), w(0x75),\ + w(0x09), w(0x83), w(0x2c), w(0x1a), w(0x1b), w(0x6e), w(0x5a), w(0xa0),\ + w(0x52), w(0x3b), w(0xd6), w(0xb3), w(0x29), w(0xe3), w(0x2f), w(0x84),\ + w(0x53), w(0xd1), w(0x00), w(0xed), w(0x20), w(0xfc), w(0xb1), w(0x5b),\ + w(0x6a), w(0xcb), w(0xbe), w(0x39), w(0x4a), w(0x4c), w(0x58), w(0xcf),\ + w(0xd0), w(0xef), w(0xaa), w(0xfb), w(0x43), w(0x4d), w(0x33), w(0x85),\ + w(0x45), w(0xf9), w(0x02), w(0x7f), w(0x50), w(0x3c), w(0x9f), w(0xa8),\ + w(0x51), w(0xa3), w(0x40), w(0x8f), w(0x92), w(0x9d), w(0x38), w(0xf5),\ + w(0xbc), w(0xb6), w(0xda), w(0x21), w(0x10), w(0xff), w(0xf3), w(0xd2),\ + w(0xcd), w(0x0c), w(0x13), w(0xec), w(0x5f), w(0x97), w(0x44), w(0x17),\ + w(0xc4), w(0xa7), w(0x7e), w(0x3d), w(0x64), w(0x5d), w(0x19), w(0x73),\ + w(0x60), w(0x81), w(0x4f), w(0xdc), w(0x22), w(0x2a), w(0x90), w(0x88),\ + w(0x46), w(0xee), w(0xb8), w(0x14), w(0xde), w(0x5e), w(0x0b), w(0xdb),\ + w(0xe0), w(0x32), w(0x3a), w(0x0a), w(0x49), w(0x06), w(0x24), w(0x5c),\ + w(0xc2), w(0xd3), w(0xac), w(0x62), w(0x91), w(0x95), w(0xe4), w(0x79),\ + w(0xe7), w(0xc8), w(0x37), w(0x6d), w(0x8d), w(0xd5), w(0x4e), w(0xa9),\ + w(0x6c), w(0x56), w(0xf4), w(0xea), w(0x65), w(0x7a), w(0xae), w(0x08),\ + w(0xba), w(0x78), w(0x25), w(0x2e), w(0x1c), w(0xa6), w(0xb4), w(0xc6),\ + w(0xe8), w(0xdd), w(0x74), w(0x1f), w(0x4b), w(0xbd), w(0x8b), w(0x8a),\ + w(0x70), w(0x3e), w(0xb5), w(0x66), w(0x48), w(0x03), w(0xf6), w(0x0e),\ + w(0x61), w(0x35), w(0x57), w(0xb9), w(0x86), w(0xc1), w(0x1d), w(0x9e),\ + w(0xe1), w(0xf8), w(0x98), w(0x11), w(0x69), w(0xd9), w(0x8e), w(0x94),\ + w(0x9b), w(0x1e), w(0x87), w(0xe9), w(0xce), w(0x55), w(0x28), w(0xdf),\ + w(0x8c), w(0xa1), w(0x89), w(0x0d), w(0xbf), w(0xe6), w(0x42), w(0x68),\ + w(0x41), w(0x99), w(0x2d), w(0x0f), w(0xb0), w(0x54), w(0xbb), w(0x16) } + +#define isb_data(w) { /* inverse S Box data values */ \ + w(0x52), w(0x09), w(0x6a), w(0xd5), w(0x30), w(0x36), w(0xa5), w(0x38),\ + w(0xbf), w(0x40), w(0xa3), w(0x9e), w(0x81), w(0xf3), w(0xd7), w(0xfb),\ + w(0x7c), w(0xe3), w(0x39), w(0x82), w(0x9b), w(0x2f), w(0xff), w(0x87),\ + w(0x34), w(0x8e), w(0x43), w(0x44), w(0xc4), w(0xde), w(0xe9), w(0xcb),\ + w(0x54), w(0x7b), w(0x94), w(0x32), w(0xa6), w(0xc2), w(0x23), w(0x3d),\ + w(0xee), w(0x4c), w(0x95), w(0x0b), w(0x42), w(0xfa), w(0xc3), w(0x4e),\ + w(0x08), w(0x2e), w(0xa1), w(0x66), w(0x28), w(0xd9), w(0x24), w(0xb2),\ + w(0x76), w(0x5b), w(0xa2), w(0x49), w(0x6d), w(0x8b), w(0xd1), w(0x25),\ + w(0x72), w(0xf8), w(0xf6), w(0x64), w(0x86), w(0x68), w(0x98), w(0x16),\ + w(0xd4), w(0xa4), w(0x5c), w(0xcc), w(0x5d), w(0x65), w(0xb6), w(0x92),\ + w(0x6c), w(0x70), w(0x48), w(0x50), w(0xfd), w(0xed), w(0xb9), w(0xda),\ + w(0x5e), w(0x15), w(0x46), w(0x57), w(0xa7), w(0x8d), w(0x9d), w(0x84),\ + w(0x90), w(0xd8), w(0xab), w(0x00), w(0x8c), w(0xbc), w(0xd3), w(0x0a),\ + w(0xf7), w(0xe4), w(0x58), w(0x05), w(0xb8), w(0xb3), w(0x45), w(0x06),\ + w(0xd0), w(0x2c), w(0x1e), w(0x8f), w(0xca), w(0x3f), w(0x0f), w(0x02),\ + w(0xc1), w(0xaf), w(0xbd), w(0x03), w(0x01), w(0x13), w(0x8a), w(0x6b),\ + w(0x3a), w(0x91), w(0x11), w(0x41), w(0x4f), w(0x67), w(0xdc), w(0xea),\ + w(0x97), w(0xf2), w(0xcf), w(0xce), w(0xf0), w(0xb4), w(0xe6), w(0x73),\ + w(0x96), w(0xac), w(0x74), w(0x22), w(0xe7), w(0xad), w(0x35), w(0x85),\ + w(0xe2), w(0xf9), w(0x37), w(0xe8), w(0x1c), w(0x75), w(0xdf), w(0x6e),\ + w(0x47), w(0xf1), w(0x1a), w(0x71), w(0x1d), w(0x29), w(0xc5), w(0x89),\ + w(0x6f), w(0xb7), w(0x62), w(0x0e), w(0xaa), w(0x18), w(0xbe), w(0x1b),\ + w(0xfc), w(0x56), w(0x3e), w(0x4b), w(0xc6), w(0xd2), w(0x79), w(0x20),\ + w(0x9a), w(0xdb), w(0xc0), w(0xfe), w(0x78), w(0xcd), w(0x5a), w(0xf4),\ + w(0x1f), w(0xdd), w(0xa8), w(0x33), w(0x88), w(0x07), w(0xc7), w(0x31),\ + w(0xb1), w(0x12), w(0x10), w(0x59), w(0x27), w(0x80), w(0xec), w(0x5f),\ + w(0x60), w(0x51), w(0x7f), w(0xa9), w(0x19), w(0xb5), w(0x4a), w(0x0d),\ + w(0x2d), w(0xe5), w(0x7a), w(0x9f), w(0x93), w(0xc9), w(0x9c), w(0xef),\ + w(0xa0), w(0xe0), w(0x3b), w(0x4d), w(0xae), w(0x2a), w(0xf5), w(0xb0),\ + w(0xc8), w(0xeb), w(0xbb), w(0x3c), w(0x83), w(0x53), w(0x99), w(0x61),\ + w(0x17), w(0x2b), w(0x04), w(0x7e), w(0xba), w(0x77), w(0xd6), w(0x26),\ + w(0xe1), w(0x69), w(0x14), w(0x63), w(0x55), w(0x21), w(0x0c), w(0x7d) } + +#define mm_data(w) { /* basic data for forming finite field tables */ \ + w(0x00), w(0x01), w(0x02), w(0x03), w(0x04), w(0x05), w(0x06), w(0x07),\ + w(0x08), w(0x09), w(0x0a), w(0x0b), w(0x0c), w(0x0d), w(0x0e), w(0x0f),\ + w(0x10), w(0x11), w(0x12), w(0x13), w(0x14), w(0x15), w(0x16), w(0x17),\ + w(0x18), w(0x19), w(0x1a), w(0x1b), w(0x1c), w(0x1d), w(0x1e), w(0x1f),\ + w(0x20), w(0x21), w(0x22), w(0x23), w(0x24), w(0x25), w(0x26), w(0x27),\ + w(0x28), w(0x29), w(0x2a), w(0x2b), w(0x2c), w(0x2d), w(0x2e), w(0x2f),\ + w(0x30), w(0x31), w(0x32), w(0x33), w(0x34), w(0x35), w(0x36), w(0x37),\ + w(0x38), w(0x39), w(0x3a), w(0x3b), w(0x3c), w(0x3d), w(0x3e), w(0x3f),\ + w(0x40), w(0x41), w(0x42), w(0x43), w(0x44), w(0x45), w(0x46), w(0x47),\ + w(0x48), w(0x49), w(0x4a), w(0x4b), w(0x4c), w(0x4d), w(0x4e), w(0x4f),\ + w(0x50), w(0x51), w(0x52), w(0x53), w(0x54), w(0x55), w(0x56), w(0x57),\ + w(0x58), w(0x59), w(0x5a), w(0x5b), w(0x5c), w(0x5d), w(0x5e), w(0x5f),\ + w(0x60), w(0x61), w(0x62), w(0x63), w(0x64), w(0x65), w(0x66), w(0x67),\ + w(0x68), w(0x69), w(0x6a), w(0x6b), w(0x6c), w(0x6d), w(0x6e), w(0x6f),\ + w(0x70), w(0x71), w(0x72), w(0x73), w(0x74), w(0x75), w(0x76), w(0x77),\ + w(0x78), w(0x79), w(0x7a), w(0x7b), w(0x7c), w(0x7d), w(0x7e), w(0x7f),\ + w(0x80), w(0x81), w(0x82), w(0x83), w(0x84), w(0x85), w(0x86), w(0x87),\ + w(0x88), w(0x89), w(0x8a), w(0x8b), w(0x8c), w(0x8d), w(0x8e), w(0x8f),\ + w(0x90), w(0x91), w(0x92), w(0x93), w(0x94), w(0x95), w(0x96), w(0x97),\ + w(0x98), w(0x99), w(0x9a), w(0x9b), w(0x9c), w(0x9d), w(0x9e), w(0x9f),\ + w(0xa0), w(0xa1), w(0xa2), w(0xa3), w(0xa4), w(0xa5), w(0xa6), w(0xa7),\ + w(0xa8), w(0xa9), w(0xaa), w(0xab), w(0xac), w(0xad), w(0xae), w(0xaf),\ + w(0xb0), w(0xb1), w(0xb2), w(0xb3), w(0xb4), w(0xb5), w(0xb6), w(0xb7),\ + w(0xb8), w(0xb9), w(0xba), w(0xbb), w(0xbc), w(0xbd), w(0xbe), w(0xbf),\ + w(0xc0), w(0xc1), w(0xc2), w(0xc3), w(0xc4), w(0xc5), w(0xc6), w(0xc7),\ + w(0xc8), w(0xc9), w(0xca), w(0xcb), w(0xcc), w(0xcd), w(0xce), w(0xcf),\ + w(0xd0), w(0xd1), w(0xd2), w(0xd3), w(0xd4), w(0xd5), w(0xd6), w(0xd7),\ + w(0xd8), w(0xd9), w(0xda), w(0xdb), w(0xdc), w(0xdd), w(0xde), w(0xdf),\ + w(0xe0), w(0xe1), w(0xe2), w(0xe3), w(0xe4), w(0xe5), w(0xe6), w(0xe7),\ + w(0xe8), w(0xe9), w(0xea), w(0xeb), w(0xec), w(0xed), w(0xee), w(0xef),\ + w(0xf0), w(0xf1), w(0xf2), w(0xf3), w(0xf4), w(0xf5), w(0xf6), w(0xf7),\ + w(0xf8), w(0xf9), w(0xfa), w(0xfb), w(0xfc), w(0xfd), w(0xfe), w(0xff) } + +static const uint_8t sbox[256] = sb_data(f1); +static const uint_8t isbox[256] = isb_data(f1); + +static const uint_8t gfm2_sbox[256] = sb_data(f2); +static const uint_8t gfm3_sbox[256] = sb_data(f3); + +static const uint_8t gfmul_9[256] = mm_data(f9); +static const uint_8t gfmul_b[256] = mm_data(fb); +static const uint_8t gfmul_d[256] = mm_data(fd); +static const uint_8t gfmul_e[256] = mm_data(fe); + +#define s_box(x) sbox[(x)] +#define is_box(x) isbox[(x)] +#define gfm2_sb(x) gfm2_sbox[(x)] +#define gfm3_sb(x) gfm3_sbox[(x)] +#define gfm_9(x) gfmul_9[(x)] +#define gfm_b(x) gfmul_b[(x)] +#define gfm_d(x) gfmul_d[(x)] +#define gfm_e(x) gfmul_e[(x)] + +#else + +/* this is the high bit of x right shifted by 1 */ +/* position. Since the starting polynomial has */ +/* 9 bits (0x11b), this right shift keeps the */ +/* values of all top bits within a byte */ + +static uint_8t hibit(const uint_8t x) +{ uint_8t r = (uint_8t)((x >> 1) | (x >> 2)); + + r |= (r >> 2); + r |= (r >> 4); + return (r + 1) >> 1; +} + +/* return the inverse of the finite field element x */ + +static uint_8t gf_inv(const uint_8t x) +{ uint_8t p1 = x, p2 = BPOLY, n1 = hibit(x), n2 = 0x80, v1 = 1, v2 = 0; + + if(x < 2) + return x; + + for( ; ; ) + { + if(n1) + while(n2 >= n1) /* divide polynomial p2 by p1 */ + { + n2 /= n1; /* shift smaller polynomial left */ + p2 ^= (p1 * n2) & 0xff; /* and remove from larger one */ + v2 ^= (v1 * n2); /* shift accumulated value and */ + n2 = hibit(p2); /* add into result */ + } + else + return v1; + + if(n2) /* repeat with values swapped */ + while(n1 >= n2) + { + n1 /= n2; + p1 ^= p2 * n1; + v1 ^= v2 * n1; + n1 = hibit(p1); + } + else + return v2; + } +} + +/* The forward and inverse affine transformations used in the S-box */ +uint_8t fwd_affine(const uint_8t x) +{ +#if defined( HAVE_UINT_32T ) + uint_32t w = x; + w ^= (w << 1) ^ (w << 2) ^ (w << 3) ^ (w << 4); + return 0x63 ^ ((w ^ (w >> 8)) & 0xff); +#else + return 0x63 ^ x ^ (x << 1) ^ (x << 2) ^ (x << 3) ^ (x << 4) + ^ (x >> 7) ^ (x >> 6) ^ (x >> 5) ^ (x >> 4); +#endif +} + +uint_8t inv_affine(const uint_8t x) +{ +#if defined( HAVE_UINT_32T ) + uint_32t w = x; + w = (w << 1) ^ (w << 3) ^ (w << 6); + return 0x05 ^ ((w ^ (w >> 8)) & 0xff); +#else + return 0x05 ^ (x << 1) ^ (x << 3) ^ (x << 6) + ^ (x >> 7) ^ (x >> 5) ^ (x >> 2); +#endif +} + +#define s_box(x) fwd_affine(gf_inv(x)) +#define is_box(x) gf_inv(inv_affine(x)) +#define gfm2_sb(x) f2(s_box(x)) +#define gfm3_sb(x) f3(s_box(x)) +#define gfm_9(x) f9(x) +#define gfm_b(x) fb(x) +#define gfm_d(x) fd(x) +#define gfm_e(x) fe(x) + +#endif + +#if defined( HAVE_MEMCPY ) +# define block_copy_nn(d, s, l) memcpy(d, s, l) +# define block_copy(d, s) memcpy(d, s, N_BLOCK) +#else +# define block_copy_nn(d, s, l) copy_block_nn(d, s, l) +# define block_copy(d, s) copy_block(d, s) +#endif + +#if !defined( HAVE_MEMCPY ) +static void copy_block( void *d, const void *s ) +{ +#if defined( HAVE_UINT_32T ) + ((uint_32t*)d)[ 0] = ((uint_32t*)s)[ 0]; + ((uint_32t*)d)[ 1] = ((uint_32t*)s)[ 1]; + ((uint_32t*)d)[ 2] = ((uint_32t*)s)[ 2]; + ((uint_32t*)d)[ 3] = ((uint_32t*)s)[ 3]; +#else + ((uint_8t*)d)[ 0] = ((uint_8t*)s)[ 0]; + ((uint_8t*)d)[ 1] = ((uint_8t*)s)[ 1]; + ((uint_8t*)d)[ 2] = ((uint_8t*)s)[ 2]; + ((uint_8t*)d)[ 3] = ((uint_8t*)s)[ 3]; + ((uint_8t*)d)[ 4] = ((uint_8t*)s)[ 4]; + ((uint_8t*)d)[ 5] = ((uint_8t*)s)[ 5]; + ((uint_8t*)d)[ 6] = ((uint_8t*)s)[ 6]; + ((uint_8t*)d)[ 7] = ((uint_8t*)s)[ 7]; + ((uint_8t*)d)[ 8] = ((uint_8t*)s)[ 8]; + ((uint_8t*)d)[ 9] = ((uint_8t*)s)[ 9]; + ((uint_8t*)d)[10] = ((uint_8t*)s)[10]; + ((uint_8t*)d)[11] = ((uint_8t*)s)[11]; + ((uint_8t*)d)[12] = ((uint_8t*)s)[12]; + ((uint_8t*)d)[13] = ((uint_8t*)s)[13]; + ((uint_8t*)d)[14] = ((uint_8t*)s)[14]; + ((uint_8t*)d)[15] = ((uint_8t*)s)[15]; +#endif +} + +static void copy_block_nn( void * d, const void *s, uint_8t nn ) +{ + while( nn-- ) + *((uint_8t*)d)++ = *((uint_8t*)s)++; +} +#endif + +static void xor_block( void *d, const void *s ) +{ +#if defined( HAVE_UINT_32T ) + ((uint_32t*)d)[ 0] ^= ((uint_32t*)s)[ 0]; + ((uint_32t*)d)[ 1] ^= ((uint_32t*)s)[ 1]; + ((uint_32t*)d)[ 2] ^= ((uint_32t*)s)[ 2]; + ((uint_32t*)d)[ 3] ^= ((uint_32t*)s)[ 3]; +#else + ((uint_8t*)d)[ 0] ^= ((uint_8t*)s)[ 0]; + ((uint_8t*)d)[ 1] ^= ((uint_8t*)s)[ 1]; + ((uint_8t*)d)[ 2] ^= ((uint_8t*)s)[ 2]; + ((uint_8t*)d)[ 3] ^= ((uint_8t*)s)[ 3]; + ((uint_8t*)d)[ 4] ^= ((uint_8t*)s)[ 4]; + ((uint_8t*)d)[ 5] ^= ((uint_8t*)s)[ 5]; + ((uint_8t*)d)[ 6] ^= ((uint_8t*)s)[ 6]; + ((uint_8t*)d)[ 7] ^= ((uint_8t*)s)[ 7]; + ((uint_8t*)d)[ 8] ^= ((uint_8t*)s)[ 8]; + ((uint_8t*)d)[ 9] ^= ((uint_8t*)s)[ 9]; + ((uint_8t*)d)[10] ^= ((uint_8t*)s)[10]; + ((uint_8t*)d)[11] ^= ((uint_8t*)s)[11]; + ((uint_8t*)d)[12] ^= ((uint_8t*)s)[12]; + ((uint_8t*)d)[13] ^= ((uint_8t*)s)[13]; + ((uint_8t*)d)[14] ^= ((uint_8t*)s)[14]; + ((uint_8t*)d)[15] ^= ((uint_8t*)s)[15]; +#endif +} + +static void copy_and_key( void *d, const void *s, const void *k ) +{ +#if defined( HAVE_UINT_32T ) + ((uint_32t*)d)[ 0] = ((uint_32t*)s)[ 0] ^ ((uint_32t*)k)[ 0]; + ((uint_32t*)d)[ 1] = ((uint_32t*)s)[ 1] ^ ((uint_32t*)k)[ 1]; + ((uint_32t*)d)[ 2] = ((uint_32t*)s)[ 2] ^ ((uint_32t*)k)[ 2]; + ((uint_32t*)d)[ 3] = ((uint_32t*)s)[ 3] ^ ((uint_32t*)k)[ 3]; +#elif 1 + ((uint_8t*)d)[ 0] = ((uint_8t*)s)[ 0] ^ ((uint_8t*)k)[ 0]; + ((uint_8t*)d)[ 1] = ((uint_8t*)s)[ 1] ^ ((uint_8t*)k)[ 1]; + ((uint_8t*)d)[ 2] = ((uint_8t*)s)[ 2] ^ ((uint_8t*)k)[ 2]; + ((uint_8t*)d)[ 3] = ((uint_8t*)s)[ 3] ^ ((uint_8t*)k)[ 3]; + ((uint_8t*)d)[ 4] = ((uint_8t*)s)[ 4] ^ ((uint_8t*)k)[ 4]; + ((uint_8t*)d)[ 5] = ((uint_8t*)s)[ 5] ^ ((uint_8t*)k)[ 5]; + ((uint_8t*)d)[ 6] = ((uint_8t*)s)[ 6] ^ ((uint_8t*)k)[ 6]; + ((uint_8t*)d)[ 7] = ((uint_8t*)s)[ 7] ^ ((uint_8t*)k)[ 7]; + ((uint_8t*)d)[ 8] = ((uint_8t*)s)[ 8] ^ ((uint_8t*)k)[ 8]; + ((uint_8t*)d)[ 9] = ((uint_8t*)s)[ 9] ^ ((uint_8t*)k)[ 9]; + ((uint_8t*)d)[10] = ((uint_8t*)s)[10] ^ ((uint_8t*)k)[10]; + ((uint_8t*)d)[11] = ((uint_8t*)s)[11] ^ ((uint_8t*)k)[11]; + ((uint_8t*)d)[12] = ((uint_8t*)s)[12] ^ ((uint_8t*)k)[12]; + ((uint_8t*)d)[13] = ((uint_8t*)s)[13] ^ ((uint_8t*)k)[13]; + ((uint_8t*)d)[14] = ((uint_8t*)s)[14] ^ ((uint_8t*)k)[14]; + ((uint_8t*)d)[15] = ((uint_8t*)s)[15] ^ ((uint_8t*)k)[15]; +#else + block_copy(d, s); + xor_block(d, k); +#endif +} + +static void add_round_key( uint_8t d[N_BLOCK], const uint_8t k[N_BLOCK] ) +{ + xor_block(d, k); +} + +static void shift_sub_rows( uint_8t st[N_BLOCK] ) +{ uint_8t tt; + + st[ 0] = s_box(st[ 0]); st[ 4] = s_box(st[ 4]); + st[ 8] = s_box(st[ 8]); st[12] = s_box(st[12]); + + tt = st[1]; st[ 1] = s_box(st[ 5]); st[ 5] = s_box(st[ 9]); + st[ 9] = s_box(st[13]); st[13] = s_box( tt ); + + tt = st[2]; st[ 2] = s_box(st[10]); st[10] = s_box( tt ); + tt = st[6]; st[ 6] = s_box(st[14]); st[14] = s_box( tt ); + + tt = st[15]; st[15] = s_box(st[11]); st[11] = s_box(st[ 7]); + st[ 7] = s_box(st[ 3]); st[ 3] = s_box( tt ); +} + +static void inv_shift_sub_rows( uint_8t st[N_BLOCK] ) +{ uint_8t tt; + + st[ 0] = is_box(st[ 0]); st[ 4] = is_box(st[ 4]); + st[ 8] = is_box(st[ 8]); st[12] = is_box(st[12]); + + tt = st[13]; st[13] = is_box(st[9]); st[ 9] = is_box(st[5]); + st[ 5] = is_box(st[1]); st[ 1] = is_box( tt ); + + tt = st[2]; st[ 2] = is_box(st[10]); st[10] = is_box( tt ); + tt = st[6]; st[ 6] = is_box(st[14]); st[14] = is_box( tt ); + + tt = st[3]; st[ 3] = is_box(st[ 7]); st[ 7] = is_box(st[11]); + st[11] = is_box(st[15]); st[15] = is_box( tt ); +} + +#if defined( VERSION_1 ) + static void mix_sub_columns( uint_8t dt[N_BLOCK] ) + { uint_8t st[N_BLOCK]; + block_copy(st, dt); +#else + static void mix_sub_columns( uint_8t dt[N_BLOCK], uint_8t st[N_BLOCK] ) + { +#endif + dt[ 0] = gfm2_sb(st[0]) ^ gfm3_sb(st[5]) ^ s_box(st[10]) ^ s_box(st[15]); + dt[ 1] = s_box(st[0]) ^ gfm2_sb(st[5]) ^ gfm3_sb(st[10]) ^ s_box(st[15]); + dt[ 2] = s_box(st[0]) ^ s_box(st[5]) ^ gfm2_sb(st[10]) ^ gfm3_sb(st[15]); + dt[ 3] = gfm3_sb(st[0]) ^ s_box(st[5]) ^ s_box(st[10]) ^ gfm2_sb(st[15]); + + dt[ 4] = gfm2_sb(st[4]) ^ gfm3_sb(st[9]) ^ s_box(st[14]) ^ s_box(st[3]); + dt[ 5] = s_box(st[4]) ^ gfm2_sb(st[9]) ^ gfm3_sb(st[14]) ^ s_box(st[3]); + dt[ 6] = s_box(st[4]) ^ s_box(st[9]) ^ gfm2_sb(st[14]) ^ gfm3_sb(st[3]); + dt[ 7] = gfm3_sb(st[4]) ^ s_box(st[9]) ^ s_box(st[14]) ^ gfm2_sb(st[3]); + + dt[ 8] = gfm2_sb(st[8]) ^ gfm3_sb(st[13]) ^ s_box(st[2]) ^ s_box(st[7]); + dt[ 9] = s_box(st[8]) ^ gfm2_sb(st[13]) ^ gfm3_sb(st[2]) ^ s_box(st[7]); + dt[10] = s_box(st[8]) ^ s_box(st[13]) ^ gfm2_sb(st[2]) ^ gfm3_sb(st[7]); + dt[11] = gfm3_sb(st[8]) ^ s_box(st[13]) ^ s_box(st[2]) ^ gfm2_sb(st[7]); + + dt[12] = gfm2_sb(st[12]) ^ gfm3_sb(st[1]) ^ s_box(st[6]) ^ s_box(st[11]); + dt[13] = s_box(st[12]) ^ gfm2_sb(st[1]) ^ gfm3_sb(st[6]) ^ s_box(st[11]); + dt[14] = s_box(st[12]) ^ s_box(st[1]) ^ gfm2_sb(st[6]) ^ gfm3_sb(st[11]); + dt[15] = gfm3_sb(st[12]) ^ s_box(st[1]) ^ s_box(st[6]) ^ gfm2_sb(st[11]); + } + +#if defined( VERSION_1 ) + static void inv_mix_sub_columns( uint_8t dt[N_BLOCK] ) + { uint_8t st[N_BLOCK]; + block_copy(st, dt); +#else + static void inv_mix_sub_columns( uint_8t dt[N_BLOCK], uint_8t st[N_BLOCK] ) + { +#endif + dt[ 0] = is_box(gfm_e(st[ 0]) ^ gfm_b(st[ 1]) ^ gfm_d(st[ 2]) ^ gfm_9(st[ 3])); + dt[ 5] = is_box(gfm_9(st[ 0]) ^ gfm_e(st[ 1]) ^ gfm_b(st[ 2]) ^ gfm_d(st[ 3])); + dt[10] = is_box(gfm_d(st[ 0]) ^ gfm_9(st[ 1]) ^ gfm_e(st[ 2]) ^ gfm_b(st[ 3])); + dt[15] = is_box(gfm_b(st[ 0]) ^ gfm_d(st[ 1]) ^ gfm_9(st[ 2]) ^ gfm_e(st[ 3])); + + dt[ 4] = is_box(gfm_e(st[ 4]) ^ gfm_b(st[ 5]) ^ gfm_d(st[ 6]) ^ gfm_9(st[ 7])); + dt[ 9] = is_box(gfm_9(st[ 4]) ^ gfm_e(st[ 5]) ^ gfm_b(st[ 6]) ^ gfm_d(st[ 7])); + dt[14] = is_box(gfm_d(st[ 4]) ^ gfm_9(st[ 5]) ^ gfm_e(st[ 6]) ^ gfm_b(st[ 7])); + dt[ 3] = is_box(gfm_b(st[ 4]) ^ gfm_d(st[ 5]) ^ gfm_9(st[ 6]) ^ gfm_e(st[ 7])); + + dt[ 8] = is_box(gfm_e(st[ 8]) ^ gfm_b(st[ 9]) ^ gfm_d(st[10]) ^ gfm_9(st[11])); + dt[13] = is_box(gfm_9(st[ 8]) ^ gfm_e(st[ 9]) ^ gfm_b(st[10]) ^ gfm_d(st[11])); + dt[ 2] = is_box(gfm_d(st[ 8]) ^ gfm_9(st[ 9]) ^ gfm_e(st[10]) ^ gfm_b(st[11])); + dt[ 7] = is_box(gfm_b(st[ 8]) ^ gfm_d(st[ 9]) ^ gfm_9(st[10]) ^ gfm_e(st[11])); + + dt[12] = is_box(gfm_e(st[12]) ^ gfm_b(st[13]) ^ gfm_d(st[14]) ^ gfm_9(st[15])); + dt[ 1] = is_box(gfm_9(st[12]) ^ gfm_e(st[13]) ^ gfm_b(st[14]) ^ gfm_d(st[15])); + dt[ 6] = is_box(gfm_d(st[12]) ^ gfm_9(st[13]) ^ gfm_e(st[14]) ^ gfm_b(st[15])); + dt[11] = is_box(gfm_b(st[12]) ^ gfm_d(st[13]) ^ gfm_9(st[14]) ^ gfm_e(st[15])); + } + +#if defined( AES_ENC_PREKEYED ) || defined( AES_DEC_PREKEYED ) + +/* Set the cipher key for the pre-keyed version */ +/* NOTE: If the length_type used for the key length is an + unsigned 8-bit character, a key length of 256 bits must + be entered as a length in bytes (valid inputs are hence + 128, 192, 16, 24 and 32). +*/ + +return_type aes_set_key( const unsigned char key[], length_type keylen, aes_context ctx[1] ) +{ + uint_8t cc, rc, hi; + + switch( keylen ) + { + case 16: + case 128: /* length in bits (128 = 8*16) */ + keylen = 16; + break; + case 24: + case 192: /* length in bits (192 = 8*24) */ + keylen = 24; + break; + case 32: +/* case 256: length in bits (256 = 8*32) */ + keylen = 32; + break; + default: + ctx->rnd = 0; + return (return_type)-1; + } + block_copy_nn(ctx->ksch, key, keylen); + hi = (keylen + 28) << 2; + ctx->rnd = (hi >> 4) - 1; + for( cc = keylen, rc = 1; cc < hi; cc += 4 ) + { uint_8t tt, t0, t1, t2, t3; + + t0 = ctx->ksch[cc - 4]; + t1 = ctx->ksch[cc - 3]; + t2 = ctx->ksch[cc - 2]; + t3 = ctx->ksch[cc - 1]; + if( cc % keylen == 0 ) + { + tt = t0; + t0 = s_box(t1) ^ rc; + t1 = s_box(t2); + t2 = s_box(t3); + t3 = s_box(tt); + rc = f2(rc); + } + else if( keylen > 24 && cc % keylen == 16 ) + { + t0 = s_box(t0); + t1 = s_box(t1); + t2 = s_box(t2); + t3 = s_box(t3); + } + tt = cc - keylen; + ctx->ksch[cc + 0] = ctx->ksch[tt + 0] ^ t0; + ctx->ksch[cc + 1] = ctx->ksch[tt + 1] ^ t1; + ctx->ksch[cc + 2] = ctx->ksch[tt + 2] ^ t2; + ctx->ksch[cc + 3] = ctx->ksch[tt + 3] ^ t3; + } + return 0; +} + +#endif + +#if defined( AES_ENC_PREKEYED ) + +/* Encrypt a single block of 16 bytes */ + +/* @breif change the name by snake for avoid the conflict with libcrypto */ +return_type bluedroid_aes_encrypt( const unsigned char in[N_BLOCK], unsigned char out[N_BLOCK], const aes_context ctx[1] ) +{ + if( ctx->rnd ) + { + uint_8t s1[N_BLOCK], r; + copy_and_key( s1, in, ctx->ksch ); + + for( r = 1 ; r < ctx->rnd ; ++r ) +#if defined( VERSION_1 ) + { + mix_sub_columns( s1 ); + add_round_key( s1, ctx->ksch + r * N_BLOCK); + } +#else + { uint_8t s2[N_BLOCK]; + mix_sub_columns( s2, s1 ); + copy_and_key( s1, s2, ctx->ksch + r * N_BLOCK); + } +#endif + shift_sub_rows( s1 ); + copy_and_key( out, s1, ctx->ksch + r * N_BLOCK ); + } + else + return (return_type)-1; + return 0; +} + +/* CBC encrypt a number of blocks (input and return an IV) */ + +return_type aes_cbc_encrypt( const unsigned char *in, unsigned char *out, + int n_block, unsigned char iv[N_BLOCK], const aes_context ctx[1] ) +{ + + while(n_block--) + { + xor_block(iv, in); + if(bluedroid_aes_encrypt(iv, iv, ctx) != EXIT_SUCCESS) + return EXIT_FAILURE; + memcpy(out, iv, N_BLOCK); + in += N_BLOCK; + out += N_BLOCK; + } + return EXIT_SUCCESS; +} + +#endif + +#if defined( AES_DEC_PREKEYED ) + +/* Decrypt a single block of 16 bytes */ + +return_type bluedroid_aes_decrypt( const unsigned char in[N_BLOCK], unsigned char out[N_BLOCK], const aes_context ctx[1] ) +{ + if( ctx->rnd ) + { + uint_8t s1[N_BLOCK], r; + copy_and_key( s1, in, ctx->ksch + ctx->rnd * N_BLOCK ); + inv_shift_sub_rows( s1 ); + + for( r = ctx->rnd ; --r ; ) +#if defined( VERSION_1 ) + { + add_round_key( s1, ctx->ksch + r * N_BLOCK ); + inv_mix_sub_columns( s1 ); + } +#else + { uint_8t s2[N_BLOCK]; + copy_and_key( s2, s1, ctx->ksch + r * N_BLOCK ); + inv_mix_sub_columns( s1, s2 ); + } +#endif + copy_and_key( out, s1, ctx->ksch ); + } + else + return (return_type)-1; + return 0; +} + +/* CBC decrypt a number of blocks (input and return an IV) */ + +return_type aes_cbc_decrypt( const unsigned char *in, unsigned char *out, + int n_block, unsigned char iv[N_BLOCK], const aes_context ctx[1] ) +{ + while(n_block--) + { uint_8t tmp[N_BLOCK]; + + memcpy(tmp, in, N_BLOCK); + if(bluedroid_aes_decrypt(in, out, ctx) != EXIT_SUCCESS) + return EXIT_FAILURE; + xor_block(out, iv); + memcpy(iv, tmp, N_BLOCK); + in += N_BLOCK; + out += N_BLOCK; + } + return EXIT_SUCCESS; +} + +#endif + +#if defined( AES_ENC_128_OTFK ) + +/* The 'on the fly' encryption key update for for 128 bit keys */ + +static void update_encrypt_key_128( uint_8t k[N_BLOCK], uint_8t *rc ) +{ uint_8t cc; + + k[0] ^= s_box(k[13]) ^ *rc; + k[1] ^= s_box(k[14]); + k[2] ^= s_box(k[15]); + k[3] ^= s_box(k[12]); + *rc = f2( *rc ); + + for(cc = 4; cc < 16; cc += 4 ) + { + k[cc + 0] ^= k[cc - 4]; + k[cc + 1] ^= k[cc - 3]; + k[cc + 2] ^= k[cc - 2]; + k[cc + 3] ^= k[cc - 1]; + } +} + +/* Encrypt a single block of 16 bytes with 'on the fly' 128 bit keying */ + +void bluedroid_aes_encrypt_128( const unsigned char in[N_BLOCK], unsigned char out[N_BLOCK], + const unsigned char key[N_BLOCK], unsigned char o_key[N_BLOCK] ) +{ uint_8t s1[N_BLOCK], r, rc = 1; + + if(o_key != key) + block_copy( o_key, key ); + copy_and_key( s1, in, o_key ); + + for( r = 1 ; r < 10 ; ++r ) +#if defined( VERSION_1 ) + { + mix_sub_columns( s1 ); + update_encrypt_key_128( o_key, &rc ); + add_round_key( s1, o_key ); + } +#else + { uint_8t s2[N_BLOCK]; + mix_sub_columns( s2, s1 ); + update_encrypt_key_128( o_key, &rc ); + copy_and_key( s1, s2, o_key ); + } +#endif + + shift_sub_rows( s1 ); + update_encrypt_key_128( o_key, &rc ); + copy_and_key( out, s1, o_key ); +} + +#endif + +#if defined( AES_DEC_128_OTFK ) + +/* The 'on the fly' decryption key update for for 128 bit keys */ + +static void update_decrypt_key_128( uint_8t k[N_BLOCK], uint_8t *rc ) +{ uint_8t cc; + + for( cc = 12; cc > 0; cc -= 4 ) + { + k[cc + 0] ^= k[cc - 4]; + k[cc + 1] ^= k[cc - 3]; + k[cc + 2] ^= k[cc - 2]; + k[cc + 3] ^= k[cc - 1]; + } + *rc = d2(*rc); + k[0] ^= s_box(k[13]) ^ *rc; + k[1] ^= s_box(k[14]); + k[2] ^= s_box(k[15]); + k[3] ^= s_box(k[12]); +} + +/* Decrypt a single block of 16 bytes with 'on the fly' 128 bit keying */ + +void bluedroid_aes_decrypt_128( const unsigned char in[N_BLOCK], unsigned char out[N_BLOCK], + const unsigned char key[N_BLOCK], unsigned char o_key[N_BLOCK] ) +{ + uint_8t s1[N_BLOCK], r, rc = 0x6c; + if(o_key != key) + block_copy( o_key, key ); + + copy_and_key( s1, in, o_key ); + inv_shift_sub_rows( s1 ); + + for( r = 10 ; --r ; ) +#if defined( VERSION_1 ) + { + update_decrypt_key_128( o_key, &rc ); + add_round_key( s1, o_key ); + inv_mix_sub_columns( s1 ); + } +#else + { uint_8t s2[N_BLOCK]; + update_decrypt_key_128( o_key, &rc ); + copy_and_key( s2, s1, o_key ); + inv_mix_sub_columns( s1, s2 ); + } +#endif + update_decrypt_key_128( o_key, &rc ); + copy_and_key( out, s1, o_key ); +} + +#endif + +#if defined( AES_ENC_256_OTFK ) + +/* The 'on the fly' encryption key update for for 256 bit keys */ + +static void update_encrypt_key_256( uint_8t k[2 * N_BLOCK], uint_8t *rc ) +{ uint_8t cc; + + k[0] ^= s_box(k[29]) ^ *rc; + k[1] ^= s_box(k[30]); + k[2] ^= s_box(k[31]); + k[3] ^= s_box(k[28]); + *rc = f2( *rc ); + + for(cc = 4; cc < 16; cc += 4) + { + k[cc + 0] ^= k[cc - 4]; + k[cc + 1] ^= k[cc - 3]; + k[cc + 2] ^= k[cc - 2]; + k[cc + 3] ^= k[cc - 1]; + } + + k[16] ^= s_box(k[12]); + k[17] ^= s_box(k[13]); + k[18] ^= s_box(k[14]); + k[19] ^= s_box(k[15]); + + for( cc = 20; cc < 32; cc += 4 ) + { + k[cc + 0] ^= k[cc - 4]; + k[cc + 1] ^= k[cc - 3]; + k[cc + 2] ^= k[cc - 2]; + k[cc + 3] ^= k[cc - 1]; + } +} + +/* Encrypt a single block of 16 bytes with 'on the fly' 256 bit keying */ + +void bluedroid_aes_encrypt_256( const unsigned char in[N_BLOCK], unsigned char out[N_BLOCK], + const unsigned char key[2 * N_BLOCK], unsigned char o_key[2 * N_BLOCK] ) +{ + uint_8t s1[N_BLOCK], r, rc = 1; + if(o_key != key) + { + block_copy( o_key, key ); + block_copy( o_key + 16, key + 16 ); + } + copy_and_key( s1, in, o_key ); + + for( r = 1 ; r < 14 ; ++r ) +#if defined( VERSION_1 ) + { + mix_sub_columns(s1); + if( r & 1 ) + add_round_key( s1, o_key + 16 ); + else + { + update_encrypt_key_256( o_key, &rc ); + add_round_key( s1, o_key ); + } + } +#else + { uint_8t s2[N_BLOCK]; + mix_sub_columns( s2, s1 ); + if( r & 1 ) + copy_and_key( s1, s2, o_key + 16 ); + else + { + update_encrypt_key_256( o_key, &rc ); + copy_and_key( s1, s2, o_key ); + } + } +#endif + + shift_sub_rows( s1 ); + update_encrypt_key_256( o_key, &rc ); + copy_and_key( out, s1, o_key ); +} + +#endif + +#if defined( AES_DEC_256_OTFK ) + +/* The 'on the fly' encryption key update for for 256 bit keys */ + +static void update_decrypt_key_256( uint_8t k[2 * N_BLOCK], uint_8t *rc ) +{ uint_8t cc; + + for(cc = 28; cc > 16; cc -= 4) + { + k[cc + 0] ^= k[cc - 4]; + k[cc + 1] ^= k[cc - 3]; + k[cc + 2] ^= k[cc - 2]; + k[cc + 3] ^= k[cc - 1]; + } + + k[16] ^= s_box(k[12]); + k[17] ^= s_box(k[13]); + k[18] ^= s_box(k[14]); + k[19] ^= s_box(k[15]); + + for(cc = 12; cc > 0; cc -= 4) + { + k[cc + 0] ^= k[cc - 4]; + k[cc + 1] ^= k[cc - 3]; + k[cc + 2] ^= k[cc - 2]; + k[cc + 3] ^= k[cc - 1]; + } + + *rc = d2(*rc); + k[0] ^= s_box(k[29]) ^ *rc; + k[1] ^= s_box(k[30]); + k[2] ^= s_box(k[31]); + k[3] ^= s_box(k[28]); +} + +/* Decrypt a single block of 16 bytes with 'on the fly' + 256 bit keying +*/ +void bluedroid_aes_decrypt_256( const unsigned char in[N_BLOCK], unsigned char out[N_BLOCK], + const unsigned char key[2 * N_BLOCK], unsigned char o_key[2 * N_BLOCK] ) +{ + uint_8t s1[N_BLOCK], r, rc = 0x80; + + if(o_key != key) + { + block_copy( o_key, key ); + block_copy( o_key + 16, key + 16 ); + } + + copy_and_key( s1, in, o_key ); + inv_shift_sub_rows( s1 ); + + for( r = 14 ; --r ; ) +#if defined( VERSION_1 ) + { + if( ( r & 1 ) ) + { + update_decrypt_key_256( o_key, &rc ); + add_round_key( s1, o_key + 16 ); + } + else + add_round_key( s1, o_key ); + inv_mix_sub_columns( s1 ); + } +#else + { uint_8t s2[N_BLOCK]; + if( ( r & 1 ) ) + { + update_decrypt_key_256( o_key, &rc ); + copy_and_key( s2, s1, o_key + 16 ); + } + else + copy_and_key( s2, s1, o_key ); + inv_mix_sub_columns( s1, s2 ); + } +#endif + copy_and_key( out, s1, o_key ); +} + +#endif diff --git a/components/bt/bluedroid/stack/smp/p_256_curvepara.c b/components/bt/bluedroid/stack/smp/p_256_curvepara.c new file mode 100755 index 0000000000..131e769359 --- /dev/null +++ b/components/bt/bluedroid/stack/smp/p_256_curvepara.c @@ -0,0 +1,80 @@ +/****************************************************************************** + * + * Copyright (C) 2006-2015 Broadcom Corporation + * + * 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 simple pairing algorithms + * + ******************************************************************************/ + +#include +#include "p_256_ecc_pp.h" + +void p_256_init_curve(UINT32 keyLength) +{ + elliptic_curve_t *ec; + + if(keyLength == KEY_LENGTH_DWORDS_P256) + { + ec = &curve_p256; + + ec->p[7] = 0xFFFFFFFF; + ec->p[6] = 0x00000001; + ec->p[5] = 0x0; + ec->p[4] = 0x0; + ec->p[3] = 0x0; + ec->p[2] = 0xFFFFFFFF; + ec->p[1] = 0xFFFFFFFF; + ec->p[0] = 0xFFFFFFFF; + + memset(ec->omega, 0, KEY_LENGTH_DWORDS_P256); + memset(ec->a, 0, KEY_LENGTH_DWORDS_P256); + + ec->a_minus3 = TRUE; + + //b + ec->b[7] = 0x5ac635d8; + ec->b[6] = 0xaa3a93e7; + ec->b[5] = 0xb3ebbd55; + ec->b[4] = 0x769886bc; + ec->b[3] = 0x651d06b0; + ec->b[2] = 0xcc53b0f6; + ec->b[1] = 0x3bce3c3e; + ec->b[0] = 0x27d2604b; + + //base point + ec->G.x[7] = 0x6b17d1f2; + ec->G.x[6] = 0xe12c4247; + ec->G.x[5] = 0xf8bce6e5; + ec->G.x[4] = 0x63a440f2; + ec->G.x[3] = 0x77037d81; + ec->G.x[2] = 0x2deb33a0; + ec->G.x[1] = 0xf4a13945; + ec->G.x[0] = 0xd898c296; + + ec->G.y[7] = 0x4fe342e2; + ec->G.y[6] = 0xfe1a7f9b; + ec->G.y[5] = 0x8ee7eb4a; + ec->G.y[4] = 0x7c0f9e16; + ec->G.y[3] = 0x2bce3357; + ec->G.y[2] = 0x6b315ece; + ec->G.y[1] = 0xcbb64068; + ec->G.y[0] = 0x37bf51f5; + } +} + diff --git a/components/bt/bluedroid/stack/smp/p_256_ecc_pp.c b/components/bt/bluedroid/stack/smp/p_256_ecc_pp.c new file mode 100755 index 0000000000..d203adc86f --- /dev/null +++ b/components/bt/bluedroid/stack/smp/p_256_ecc_pp.c @@ -0,0 +1,262 @@ +/****************************************************************************** + * + * Copyright (C) 2006-2015 Broadcom Corporation + * + * 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 simple pairing algorithms using Elliptic Curve Cryptography for private public key + * + ******************************************************************************/ +//#include +//#include +#include +#include "p_256_ecc_pp.h" +#include "p_256_multprecision.h" + +elliptic_curve_t curve; +elliptic_curve_t curve_p256; + +static void p_256_init_point(Point *q) +{ + memset(q, 0, sizeof(Point)); +} + +static void p_256_copy_point(Point *q, Point *p) +{ + memcpy(q, p, sizeof(Point)); +} + +// q=2q +static void ECC_Double(Point *q, Point *p, uint32_t keyLength) +{ + DWORD t1[KEY_LENGTH_DWORDS_P256]; + DWORD t2[KEY_LENGTH_DWORDS_P256]; + DWORD t3[KEY_LENGTH_DWORDS_P256]; + DWORD *x1; + DWORD *x3; + DWORD *y1; + DWORD *y3; + DWORD *z1; + DWORD *z3; + + if (multiprecision_iszero(p->z, keyLength)) + { + multiprecision_init(q->z, keyLength); + return; // return infinity + } + + x1=p->x; y1=p->y; z1=p->z; + x3=q->x; y3=q->y; z3=q->z; + + multiprecision_mersenns_squa_mod(t1, z1, keyLength); // t1=z1^2 + multiprecision_sub_mod(t2, x1, t1, keyLength); // t2=x1-t1 + multiprecision_add_mod(t1, x1, t1, keyLength); // t1=x1+t1 + multiprecision_mersenns_mult_mod(t2, t1, t2, keyLength); // t2=t2*t1 + multiprecision_lshift_mod(t3, t2, keyLength); + multiprecision_add_mod(t2, t3, t2, keyLength); // t2=3t2 + + multiprecision_mersenns_mult_mod(z3, y1, z1, keyLength); // z3=y1*z1 + multiprecision_lshift_mod(z3, z3, keyLength); + + multiprecision_mersenns_squa_mod(y3, y1, keyLength); // y3=y1^2 + multiprecision_lshift_mod(y3, y3, keyLength); + multiprecision_mersenns_mult_mod(t3, y3, x1, keyLength); // t3=y3*x1=x1*y1^2 + multiprecision_lshift_mod(t3, t3, keyLength); + multiprecision_mersenns_squa_mod(y3, y3, keyLength); // y3=y3^2=y1^4 + multiprecision_lshift_mod(y3, y3, keyLength); + + multiprecision_mersenns_squa_mod(x3, t2, keyLength); // x3=t2^2 + multiprecision_lshift_mod(t1, t3, keyLength); // t1=2t3 + multiprecision_sub_mod(x3, x3, t1, keyLength); // x3=x3-t1 + multiprecision_sub_mod(t1, t3, x3, keyLength); // t1=t3-x3 + multiprecision_mersenns_mult_mod(t1, t1, t2, keyLength); // t1=t1*t2 + multiprecision_sub_mod(y3, t1, y3, keyLength); // y3=t1-y3 +} + +// q=q+p, zp must be 1 +static void ECC_Add(Point *r, Point *p, Point *q, uint32_t keyLength) +{ + DWORD t1[KEY_LENGTH_DWORDS_P256]; + DWORD t2[KEY_LENGTH_DWORDS_P256]; + DWORD *x1; + DWORD *x2; + DWORD *x3; + DWORD *y1; + DWORD *y2; + DWORD *y3; + DWORD *z1; + DWORD *z2; + DWORD *z3; + + x1=p->x; y1=p->y; z1=p->z; + x2=q->x; y2=q->y; z2=q->z; + x3=r->x; y3=r->y; z3=r->z; + + // if Q=infinity, return p + if (multiprecision_iszero(z2, keyLength)) + { + p_256_copy_point(r, p); + return; + } + + // if P=infinity, return q + if (multiprecision_iszero(z1, keyLength)) + { + p_256_copy_point(r, q); + return; + } + + multiprecision_mersenns_squa_mod(t1, z1, keyLength); // t1=z1^2 + multiprecision_mersenns_mult_mod(t2, z1, t1, keyLength); // t2=t1*z1 + multiprecision_mersenns_mult_mod(t1, x2, t1, keyLength); // t1=t1*x2 + multiprecision_mersenns_mult_mod(t2, y2, t2, keyLength); // t2=t2*y2 + + multiprecision_sub_mod(t1, t1, x1, keyLength); // t1=t1-x1 + multiprecision_sub_mod(t2, t2, y1, keyLength); // t2=t2-y1 + + if (multiprecision_iszero(t1, keyLength)) + { + if (multiprecision_iszero(t2, keyLength)) + { + ECC_Double(r, q, keyLength) ; + return; + } + else + { + multiprecision_init(z3, keyLength); + return; // return infinity + } + } + + multiprecision_mersenns_mult_mod(z3, z1, t1, keyLength); // z3=z1*t1 + multiprecision_mersenns_squa_mod(y3, t1, keyLength); // t3=t1^2 + multiprecision_mersenns_mult_mod(z1, y3, t1, keyLength); // t4=t3*t1 + multiprecision_mersenns_mult_mod(y3, y3, x1, keyLength); // t3=t3*x1 + multiprecision_lshift_mod(t1, y3, keyLength); // t1=2*t3 + multiprecision_mersenns_squa_mod(x3, t2, keyLength); // x3=t2^2 + multiprecision_sub_mod(x3, x3, t1, keyLength); // x3=x3-t1 + multiprecision_sub_mod(x3, x3, z1, keyLength); // x3=x3-t4 + multiprecision_sub_mod(y3, y3, x3, keyLength); // t3=t3-x3 + multiprecision_mersenns_mult_mod(y3, y3, t2, keyLength); // t3=t3*t2 + multiprecision_mersenns_mult_mod(z1, z1, y1, keyLength); // t4=t4*t1 + multiprecision_sub_mod(y3, y3, z1, keyLength); +} + +// Computing the Non-Adjacent Form of a positive integer +static void ECC_NAF(uint8_t *naf, uint32_t *NumNAF, DWORD *k, uint32_t keyLength) +{ + uint32_t sign; + int i=0; + int j; + uint32_t var; + + while ((var = multiprecision_most_signbits(k, keyLength))>=1) + { + if (k[0] & 0x01) // k is odd + { + sign = (k[0] & 0x03); // 1 or 3 + + // k = k-naf[i] + if (sign == 1) + k[0] = k[0] & 0xFFFFFFFE; + else + { + k[0] = k[0] + 1; + if (k[0] == 0) //overflow + { + j = 1; + do + { + k[j]++; + } while (k[j++]==0); //overflow + } + } + } + else + sign = 0; + + multiprecision_rshift(k, k, keyLength); + naf[i / 4] |= (sign) << ((i % 4) * 2); + i++; + } + + *NumNAF=i; +} + +// Binary Non-Adjacent Form for point multiplication +void ECC_PointMult_Bin_NAF(Point *q, Point *p, DWORD *n, uint32_t keyLength) +{ + uint32_t sign; + UINT8 naf[256 / 4 +1]; + uint32_t NumNaf; + Point minus_p; + Point r; + DWORD *modp; + + if (keyLength == KEY_LENGTH_DWORDS_P256) + { + modp = curve_p256.p; + } + else + { + modp = curve.p; + } + + p_256_init_point(&r); + multiprecision_init(p->z, keyLength); + p->z[0] = 1; + + // initialization + p_256_init_point(q); + + // -p + multiprecision_copy(minus_p.x, p->x, keyLength); + multiprecision_sub(minus_p.y, modp, p->y, keyLength); + + multiprecision_init(minus_p.z, keyLength); + minus_p.z[0]=1; + + // NAF + memset(naf, 0, sizeof(naf)); + ECC_NAF(naf, &NumNaf, n, keyLength); + + for (int i = NumNaf - 1; i >= 0; i--) + { + p_256_copy_point(&r, q); + ECC_Double(q, &r, keyLength); + sign = (naf[i / 4] >> ((i % 4) * 2)) & 0x03; + + if (sign == 1) + { + p_256_copy_point(&r, q); + ECC_Add(q, &r, p, keyLength); + } + else if (sign == 3) + { + p_256_copy_point(&r, q); + ECC_Add(q, &r, &minus_p, keyLength); + } + } + + multiprecision_inv_mod(minus_p.x, q->z, keyLength); + multiprecision_mersenns_squa_mod(q->z, minus_p.x, keyLength); + multiprecision_mersenns_mult_mod(q->x, q->x, q->z, keyLength); + multiprecision_mersenns_mult_mod(q->z, q->z, minus_p.x, keyLength); + multiprecision_mersenns_mult_mod(q->y, q->y, q->z, keyLength); +} + + diff --git a/components/bt/bluedroid/stack/smp/p_256_multprecision.c b/components/bt/bluedroid/stack/smp/p_256_multprecision.c new file mode 100755 index 0000000000..f939809572 --- /dev/null +++ b/components/bt/bluedroid/stack/smp/p_256_multprecision.c @@ -0,0 +1,704 @@ +/****************************************************************************** + * + * Copyright (C) 2006-2015 Broadcom Corporation + * + * 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 simple pairing algorithms + * + ******************************************************************************/ + +#include +#include "bt_target.h" +#include "p_256_ecc_pp.h" +#include "p_256_multprecision.h" + +void multiprecision_init(DWORD *c, uint32_t keyLength) +{ + for (uint32_t i = 0; i < keyLength; i++) + c[i] = 0; +} + +void multiprecision_copy(DWORD *c, DWORD *a, uint32_t keyLength) +{ + for (uint32_t i = 0; i < keyLength; i++) + c[i] = a[i]; +} + +int multiprecision_compare(DWORD *a, DWORD *b, uint32_t keyLength) +{ + for (int i = keyLength - 1; i >= 0; i--) + { + if (a[i] > b[i]) + return 1; + if (a[i] < b[i]) + return -1; + } + return 0; +} + +int multiprecision_iszero(DWORD *a, uint32_t keyLength) +{ + for (uint32_t i = 0; i < keyLength; i++) + if (a[i]) + return 0; + + return 1; +} + +UINT32 multiprecision_dword_bits(DWORD a) +{ + uint32_t i; + for (i = 0; i < DWORD_BITS; i++, a >>= 1) + if (a == 0) + break; + + return i; +} + +UINT32 multiprecision_most_signdwords(DWORD *a, uint32_t keyLength) +{ + int i; + for (i = keyLength - 1; i >= 0; i--) + if (a[i]) + break; + return (i + 1); +} + +UINT32 multiprecision_most_signbits(DWORD *a, uint32_t keyLength) +{ + int aMostSignDWORDs; + + aMostSignDWORDs = multiprecision_most_signdwords(a, keyLength); + if (aMostSignDWORDs == 0) + return 0; + + return (((aMostSignDWORDs-1) << DWORD_BITS_SHIFT) + + multiprecision_dword_bits(a[aMostSignDWORDs-1]) ); +} + +DWORD multiprecision_add(DWORD *c, DWORD *a, DWORD *b, uint32_t keyLength) +{ + DWORD carrier; + DWORD temp; + + carrier=0; + for (uint32_t i = 0; i < keyLength; i++) + { + temp = a[i] + carrier; + carrier = (temp < carrier); + temp += b[i]; + carrier |= (temp < b[i]); + c[i]=temp; + } + + return carrier; +} + +//c=a-b +DWORD multiprecision_sub(DWORD *c, DWORD *a, DWORD *b, uint32_t keyLength) +{ + DWORD borrow; + DWORD temp; + + borrow=0; + for (uint32_t i=0; i < keyLength; i++) + { + temp = a[i] - borrow; + borrow = (temp > a[i]); + c[i] = temp - b[i]; + borrow |= (c[i] > temp); + } + + return borrow; +} + +// c = a << 1 +void multiprecision_lshift_mod(DWORD * c, DWORD * a, uint32_t keyLength) +{ + DWORD carrier; + DWORD *modp; + + if (keyLength == KEY_LENGTH_DWORDS_P192) + { + modp = curve.p; + } + else if (keyLength == KEY_LENGTH_DWORDS_P256) + { + modp = curve_p256.p; + } + else + return; + + carrier = multiprecision_lshift(c, a, keyLength); + if (carrier) + { + multiprecision_sub(c, c, modp, keyLength); + } + else if (multiprecision_compare(c, modp, keyLength)>=0) + { + multiprecision_sub(c, c, modp, keyLength); + } +} + +// c=a>>1 +void multiprecision_rshift(DWORD * c, DWORD * a, uint32_t keyLength) +{ + int j; + DWORD b = 1; + + j = DWORD_BITS - b; + + DWORD carrier = 0; + DWORD temp; + for (int i = keyLength-1; i >= 0; i--) + { + temp = a[i]; // in case of c==a + c[i] = (temp >> b) | carrier; + carrier = temp << j; + } +} + +// Curve specific optimization when p is a pseudo-Mersenns prime, p=2^(KEY_LENGTH_BITS)-omega +void multiprecision_mersenns_mult_mod(DWORD *c, DWORD *a, DWORD *b, uint32_t keyLength) +{ + DWORD cc[2*KEY_LENGTH_DWORDS_P256]; + + multiprecision_mult(cc, a, b, keyLength); + if (keyLength == 6) + { + multiprecision_fast_mod(c, cc); + } + else if (keyLength == 8) + { + multiprecision_fast_mod_P256(c, cc); + } +} + +// Curve specific optimization when p is a pseudo-Mersenns prime +void multiprecision_mersenns_squa_mod(DWORD *c, DWORD *a, uint32_t keyLength) +{ + multiprecision_mersenns_mult_mod(c, a, a, keyLength); +} + +// c=(a+b) mod p, b= 0) + { + multiprecision_sub(c, c, modp, keyLength); + } +} + +// c=(a-b) mod p, a> j; + } + + return carrier; +} + +// c=a*b; c must have a buffer of 2*Key_LENGTH_DWORDS, c != a != b +void multiprecision_mult(DWORD *c, DWORD *a, DWORD *b, uint32_t keyLength) +{ + DWORD W; + DWORD U; + DWORD V; + + U = V = W = 0; + multiprecision_init(c, keyLength); + + //assume little endian right now + for (uint32_t i = 0; i < keyLength; i++) + { + U = 0; + for (uint32_t j = 0; j < keyLength; j++) + { + uint64_t result; + result = ((UINT64)a[i]) * ((uint64_t) b[j]); + W = result >> 32; + V = a[i] * b[j]; + V = V + U; + U = (V < U); + U += W; + V = V + c[i+j]; + U += (V < c[i+j]); + c[i+j] = V; + } + c[i+keyLength] = U; + } +} + +void multiprecision_fast_mod(DWORD *c, DWORD *a) +{ + DWORD U; + DWORD V; + DWORD *modp = curve.p; + + c[0] = a[0] + a[6]; + U=c[0] < a[0]; + c[0] += a[10]; + U += c[0] < a[10]; + + c[1] = a[1] + U; + U = c[1] < a[1]; + c[1] += a[7]; + U += c[1] < a[7]; + c[1] += a[11]; + U += c[1]< a[11]; + + c[2] = a[2] + U; + U = c[2] < a[2]; + c[2] += a[6]; + U += c[2] < a[6]; + c[2] += a[8]; + U += c[2] < a[8]; + c[2] += a[10]; + U += c[2] < a[10]; + + c[3] = a[3]+U; + U = c[3] < a[3]; + c[3] += a[7]; + U += c[3] < a[7]; + c[3] += a[9]; + U += c[3] < a[9]; + c[3] += a[11]; + U += c[3] < a[11]; + + c[4] = a[4]+U; + U = c[4] < a[4]; + c[4] += a[8]; + U += c[4] < a[8]; + c[4] += a[10]; + U += c[4] < a[10]; + + c[5] = a[5]+U; + U = c[5] < a[5]; + c[5] += a[9]; + U += c[5] < a[9]; + c[5] += a[11]; + U += c[5] < a[11]; + + c[0] += U; + V = c[0] < U; + c[1] += V; + V = c[1] < V; + c[2] += V; + V = c[2] < V; + c[2] += U; + V = c[2] < U; + c[3] += V; + V = c[3] < V; + c[4] += V; + V = c[4] < V; + c[5] += V; + V = c[5] < V; + + if (V) + { + multiprecision_sub(c, c, modp, KEY_LENGTH_DWORDS_P192); + } + else if(multiprecision_compare(c, modp, KEY_LENGTH_DWORDS_P192) >= 0) + { + multiprecision_sub(c, c, modp, KEY_LENGTH_DWORDS_P192); + } +} + +void multiprecision_fast_mod_P256(DWORD *c, DWORD *a) +{ + DWORD A; + DWORD B; + DWORD C; + DWORD D; + DWORD E; + DWORD F; + DWORD G; + uint8_t UA; + uint8_t UB; + uint8_t UC; + uint8_t UD; + uint8_t UE; + uint8_t UF; + uint8_t UG; + DWORD U; + DWORD *modp = curve_p256.p; + + // C = a[13] + a[14] + a[15]; + C = a[13]; + C += a[14]; + UC = (C < a[14]); + C += a[15]; + UC += (C < a[15]); + + // E = a[8] + a[9]; + E = a[8]; + E += a[9]; + UE = (E < a[9]); + + // F = a[9] + a[10]; + F = a[9]; + F += a[10]; + UF = (F < a[10]); + + // G = a[10] + a[11] + G = a[10]; + G += a[11]; + UG = (G < a[11]); + + // B = a[12] + a[13] + a[14] + a[15] == C + a[12] + B = C; + UB = UC; + B += a[12]; + UB += (B < a[12]); + + // A = a[11] + a[12] + a[13] + a[14] == B + a[11] - a[15] + A = B; + UA = UB; + A += a[11]; + UA += (A < a[11]); + UA -= (A < a[15]); + A -= a[15]; + + // D = a[10] + a[11] + a[12] + a[13] == A + a[10] - a[14] + D = A; + UD = UA; + D += a[10]; + UD += (D < a[10]); + UD -= (D < a[14]); + D -= a[14]; + + c[0] = a[0]; + c[0] += E; + U = (c[0] < E); + U += UE; + U -= (c[0] < A); + U -= UA; + c[0] -= A; + + if (U & 0x80000000) + { + DWORD UU; + UU = 0 - U; + U = (a[1] < UU); + c[1] = a[1] - UU; + } + else + { + c[1] = a[1] + U; + U = (c[1] < a[1]); + } + + c[1] += F; + U += (c[1] < F); + U += UF; + U -= (c[1] < B); + U -= UB; + c[1] -= B; + + if (U & 0x80000000) + { + DWORD UU; + UU = 0 - U; + U = (a[2] < UU); + c[2] = a[2] - UU; + } + else + { + c[2] = a[2] + U; + U = (c[2] < a[2]); + } + + c[2] += G; + U += (c[2] < G); + U += UG; + U -= (c[2] < C); + U -= UC; + c[2] -= C; + + if (U & 0x80000000) + { + DWORD UU; + UU = 0 - U; + U = (a[3] < UU); + c[3] = a[3] - UU; + } + else + { + c[3] = a[3] + U; + U = (c[3] < a[3]); + } + + c[3] += A; + U += (c[3] < A); + U += UA; + c[3] += a[11]; + U += (c[3] < a[11]); + c[3] += a[12]; + U += (c[3] < a[12]); + U -= (c[3] < a[14]); + c[3] -= a[14]; + U -= (c[3] < a[15]); + c[3] -= a[15]; + U -= (c[3] < E); + U -= UE; + c[3] -= E; + + if (U & 0x80000000) + { + DWORD UU; + UU = 0 - U; + U = (a[4] < UU); + c[4] = a[4] - UU; + } + else + { + c[4] = a[4] + U; + U = (c[4] < a[4]); + } + + c[4] += B; + U += (c[4] < B); + U += UB; + U -= (c[4] < a[15]); + c[4] -= a[15]; + c[4] += a[12]; + U += (c[4] < a[12]); + c[4] += a[13]; + U += (c[4] < a[13]); + U -= (c[4] < F); + U -= UF; + c[4] -= F; + + if (U & 0x80000000) + { + DWORD UU; + UU = 0 - U; + U = (a[5] < UU); + c[5] = a[5] - UU; + } + else + { + c[5] = a[5] + U; + U = (c[5] < a[5]); + } + + c[5] += C; + U += (c[5] < C); + U += UC; + c[5] += a[13]; + U += (c[5] < a[13]); + c[5] += a[14]; + U += (c[5] < a[14]); + U -= (c[5] < G); + U -= UG; + c[5] -= G; + + if (U & 0x80000000) + { + DWORD UU; + UU = 0 - U; + U = (a[6] < UU); + c[6] = a[6] - UU; + } + else + { + c[6] = a[6] + U; + U = (c[6] < a[6]); + } + + c[6] += C; + U += (c[6] < C); + U += UC; + c[6] += a[14]; + U += (c[6] < a[14]); + c[6] += a[14]; + U += (c[6] < a[14]); + c[6] += a[15]; + U += (c[6] < a[15]); + U -= (c[6] < E); + U -= UE; + c[6] -= E; + + if (U & 0x80000000) + { + DWORD UU; + UU = 0 - U; + U = (a[7] < UU); + c[7] = a[7] - UU; + } + else + { + c[7] = a[7] + U; + U = (c[7] < a[7]); + } + + c[7] += a[15]; + U += (c[7] < a[15]); + c[7] += a[15]; + U += (c[7] < a[15]); + c[7] += a[15]; + U += (c[7] < a[15]); + c[7] += a[8]; + U += (c[7] < a[8]); + U -= (c[7] < D); + U -= UD; + c[7] -= D; + + if (U & 0x80000000) + { + while (U) + { + multiprecision_add(c, c, modp, KEY_LENGTH_DWORDS_P256); + U++; + } + } + else if (U) + { + while (U) + { + multiprecision_sub(c, c, modp, KEY_LENGTH_DWORDS_P256); + U--; + } + } + + if (multiprecision_compare(c, modp, KEY_LENGTH_DWORDS_P256)>=0) + multiprecision_sub(c, c, modp, KEY_LENGTH_DWORDS_P256); + +} + +void multiprecision_inv_mod(DWORD *aminus, DWORD *u, uint32_t keyLength) +{ + DWORD v[KEY_LENGTH_DWORDS_P256]; + DWORD A[KEY_LENGTH_DWORDS_P256+1]; + DWORD C[KEY_LENGTH_DWORDS_P256+1]; + DWORD *modp; + + if(keyLength == KEY_LENGTH_DWORDS_P256) + { + modp = curve_p256.p; + } + else + { + modp = curve.p; + } + + multiprecision_copy(v, modp, keyLength); + multiprecision_init(A, keyLength); + multiprecision_init(C, keyLength); + A[0] = 1; + + while (!multiprecision_iszero(u, keyLength)) + { + while (!(u[0] & 0x01)) // u is even + { + multiprecision_rshift(u, u, keyLength); + if(!(A[0] & 0x01)) // A is even + multiprecision_rshift(A, A, keyLength); + else + { + A[keyLength]=multiprecision_add(A, A, modp, keyLength); // A =A+p + multiprecision_rshift(A, A, keyLength); + A[keyLength-1] |= (A[keyLength]<<31); + } + } + + while (!(v[0] & 0x01)) // v is even + { + multiprecision_rshift(v, v, keyLength); + if (!(C[0] & 0x01)) // C is even + { + multiprecision_rshift(C, C, keyLength); + } + else + { + C[keyLength] = multiprecision_add(C, C, modp, keyLength); // C =C+p + multiprecision_rshift(C, C, keyLength); + C[keyLength-1] |= (C[keyLength] << 31); + } + } + + if (multiprecision_compare(u, v, keyLength) >= 0) + { + multiprecision_sub(u, u, v, keyLength); + multiprecision_sub_mod(A, A, C, keyLength); + } + else + { + multiprecision_sub(v, v, u, keyLength); + multiprecision_sub_mod(C, C, A, keyLength); + } + } + + if (multiprecision_compare(C, modp, keyLength) >= 0) + multiprecision_sub(aminus, C, modp, keyLength); + else + multiprecision_copy(aminus, C, keyLength); +} + diff --git a/components/bt/bluedroid/stack/smp/smp_act.c b/components/bt/bluedroid/stack/smp/smp_act.c new file mode 100755 index 0000000000..a17b1c5a08 --- /dev/null +++ b/components/bt/bluedroid/stack/smp/smp_act.c @@ -0,0 +1,2135 @@ +/****************************************************************************** + * + * Copyright (C) 2003-2012 Broadcom Corporation + * + * 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. + * + ******************************************************************************/ + +#include +#include "interop.h" +#include "bt_target.h" +#include "btm_int.h" +#include "l2c_api.h" +#include "smp_int.h" +//#include "utils/include/bt_utils.h" + +#if SMP_INCLUDED == TRUE +const UINT8 smp_association_table[2][SMP_IO_CAP_MAX][SMP_IO_CAP_MAX] = +{ + /* initiator */ + {{SMP_MODEL_ENCRYPTION_ONLY, SMP_MODEL_ENCRYPTION_ONLY, SMP_MODEL_PASSKEY, SMP_MODEL_ENCRYPTION_ONLY, SMP_MODEL_PASSKEY}, /* Display Only */ + {SMP_MODEL_ENCRYPTION_ONLY, SMP_MODEL_ENCRYPTION_ONLY, SMP_MODEL_PASSKEY, SMP_MODEL_ENCRYPTION_ONLY, SMP_MODEL_PASSKEY}, /* SMP_CAP_IO = 1 */ + {SMP_MODEL_KEY_NOTIF, SMP_MODEL_KEY_NOTIF, SMP_MODEL_PASSKEY, SMP_MODEL_ENCRYPTION_ONLY, SMP_MODEL_KEY_NOTIF}, /* keyboard only */ + {SMP_MODEL_ENCRYPTION_ONLY, SMP_MODEL_ENCRYPTION_ONLY, SMP_MODEL_ENCRYPTION_ONLY, SMP_MODEL_ENCRYPTION_ONLY, SMP_MODEL_ENCRYPTION_ONLY},/* No Input No Output */ + {SMP_MODEL_KEY_NOTIF, SMP_MODEL_KEY_NOTIF, SMP_MODEL_PASSKEY, SMP_MODEL_ENCRYPTION_ONLY, SMP_MODEL_KEY_NOTIF}}, /* keyboard display */ + /* responder */ + {{SMP_MODEL_ENCRYPTION_ONLY, SMP_MODEL_ENCRYPTION_ONLY, SMP_MODEL_KEY_NOTIF, SMP_MODEL_ENCRYPTION_ONLY, SMP_MODEL_KEY_NOTIF}, /* Display Only */ + {SMP_MODEL_ENCRYPTION_ONLY, SMP_MODEL_ENCRYPTION_ONLY, SMP_MODEL_KEY_NOTIF, SMP_MODEL_ENCRYPTION_ONLY, SMP_MODEL_KEY_NOTIF}, /* SMP_CAP_IO = 1 */ + {SMP_MODEL_PASSKEY, SMP_MODEL_PASSKEY, SMP_MODEL_PASSKEY, SMP_MODEL_ENCRYPTION_ONLY, SMP_MODEL_PASSKEY}, /* keyboard only */ + {SMP_MODEL_ENCRYPTION_ONLY, SMP_MODEL_ENCRYPTION_ONLY, SMP_MODEL_ENCRYPTION_ONLY, SMP_MODEL_ENCRYPTION_ONLY, SMP_MODEL_ENCRYPTION_ONLY},/* No Input No Output */ + {SMP_MODEL_PASSKEY, SMP_MODEL_PASSKEY, SMP_MODEL_KEY_NOTIF, SMP_MODEL_ENCRYPTION_ONLY, SMP_MODEL_PASSKEY}} /* keyboard display */ + /* display only */ /*SMP_CAP_IO = 1 */ /* keyboard only */ /* No InputOutput */ /* keyboard display */ +}; + +#define SMP_KEY_DIST_TYPE_MAX 4 +const tSMP_ACT smp_distribute_act [] = +{ + smp_generate_ltk, + smp_send_id_info, + smp_generate_csrk, + smp_set_derive_link_key +}; + +static bool lmp_version_below(BD_ADDR bda, uint8_t version) +{ + tACL_CONN *acl = btm_bda_to_acl(bda, BT_TRANSPORT_LE); + if (acl == NULL || acl->lmp_version == 0) + { + SMP_TRACE_WARNING("%s cannot retrieve LMP version...", __func__); + return false; + } + SMP_TRACE_WARNING("%s LMP version %d < %d", __func__, acl->lmp_version, version); + return acl->lmp_version < version; +} + +/******************************************************************************* +** Function smp_update_key_mask +** Description This function updates the key mask for sending or receiving. +*******************************************************************************/ +static void smp_update_key_mask (tSMP_CB *p_cb, UINT8 key_type, BOOLEAN recv) +{ + SMP_TRACE_DEBUG("%s before update role=%d recv=%d local_i_key = %02x, local_r_key = %02x", + __func__, p_cb->role, recv, p_cb->local_i_key, p_cb->local_r_key); + + if (((p_cb->le_secure_connections_mode_is_used) || + (p_cb->smp_over_br)) && + ((key_type == SMP_SEC_KEY_TYPE_ENC) || (key_type == SMP_SEC_KEY_TYPE_LK))) + { + /* in LE SC mode LTK, CSRK and BR/EDR LK are derived locally instead of + ** being exchanged with the peer */ + p_cb->local_i_key &= ~key_type; + p_cb->local_r_key &= ~key_type; + } + else + if (p_cb->role == HCI_ROLE_SLAVE) + { + if (recv) + p_cb->local_i_key &= ~key_type; + else + p_cb->local_r_key &= ~key_type; + } + else + { + if (recv) + p_cb->local_r_key &= ~key_type; + else + p_cb->local_i_key &= ~key_type; + } + + SMP_TRACE_DEBUG("updated local_i_key = %02x, local_r_key = %02x", p_cb->local_i_key, + p_cb->local_r_key); +} + +/******************************************************************************* +** Function smp_send_app_cback +** Description notifies application about the events the application is interested in +*******************************************************************************/ +void smp_send_app_cback(tSMP_CB *p_cb, tSMP_INT_DATA *p_data) +{ + tSMP_EVT_DATA cb_data; + tSMP_STATUS callback_rc; + SMP_TRACE_DEBUG("%s p_cb->cb_evt=%d", __func__, p_cb->cb_evt); + if (p_cb->p_callback && p_cb->cb_evt != 0) + { + switch (p_cb->cb_evt) + { + case SMP_IO_CAP_REQ_EVT: + cb_data.io_req.auth_req = p_cb->peer_auth_req; + cb_data.io_req.oob_data = SMP_OOB_NONE; + cb_data.io_req.io_cap = SMP_DEFAULT_IO_CAPS; + cb_data.io_req.max_key_size = SMP_MAX_ENC_KEY_SIZE; + cb_data.io_req.init_keys = p_cb->local_i_key ; + cb_data.io_req.resp_keys = p_cb->local_r_key ; + SMP_TRACE_WARNING ( "io_cap = %d",cb_data.io_req.io_cap); + break; + + case SMP_NC_REQ_EVT: + cb_data.passkey = p_data->passkey; + break; + case SMP_SC_OOB_REQ_EVT: + cb_data.req_oob_type = p_data->req_oob_type; + break; + case SMP_SC_LOC_OOB_DATA_UP_EVT: + cb_data.loc_oob_data = p_cb->sc_oob_data.loc_oob_data; + break; + + case SMP_BR_KEYS_REQ_EVT: + cb_data.io_req.auth_req = 0; + cb_data.io_req.oob_data = SMP_OOB_NONE; + cb_data.io_req.io_cap = 0; + cb_data.io_req.max_key_size = SMP_MAX_ENC_KEY_SIZE; + cb_data.io_req.init_keys = SMP_BR_SEC_DEFAULT_KEY; + cb_data.io_req.resp_keys = SMP_BR_SEC_DEFAULT_KEY; + break; + + default: + break; + } + + callback_rc = (*p_cb->p_callback)(p_cb->cb_evt, p_cb->pairing_bda, &cb_data); + + SMP_TRACE_DEBUG("callback_rc=%d p_cb->cb_evt=%d",callback_rc, p_cb->cb_evt ); + + if (callback_rc == SMP_SUCCESS) + { + switch (p_cb->cb_evt) + { + case SMP_IO_CAP_REQ_EVT: + p_cb->loc_auth_req = cb_data.io_req.auth_req; + p_cb->local_io_capability = cb_data.io_req.io_cap; + p_cb->loc_oob_flag = cb_data.io_req.oob_data; + p_cb->loc_enc_size = cb_data.io_req.max_key_size; + p_cb->local_i_key = cb_data.io_req.init_keys; + p_cb->local_r_key = cb_data.io_req.resp_keys; + + if (!(p_cb->loc_auth_req & SMP_AUTH_BOND)) + { + SMP_TRACE_WARNING ("Non bonding: No keys will be exchanged"); + p_cb->local_i_key = 0; + p_cb->local_r_key = 0; + } + + SMP_TRACE_WARNING ( "rcvd auth_req: 0x%02x, io_cap: %d \ + loc_oob_flag: %d loc_enc_size: %d," + "local_i_key: 0x%02x, local_r_key: 0x%02x", + p_cb->loc_auth_req, p_cb->local_io_capability, p_cb->loc_oob_flag, + p_cb->loc_enc_size, p_cb->local_i_key, p_cb->local_r_key); + + p_cb->secure_connections_only_mode_required = + (btm_cb.security_mode == BTM_SEC_MODE_SC) ? TRUE : FALSE; + + if (p_cb->secure_connections_only_mode_required) + { + p_cb->loc_auth_req |= SMP_SC_SUPPORT_BIT; + } + + if (!(p_cb->loc_auth_req & SMP_SC_SUPPORT_BIT) + || lmp_version_below(p_cb->pairing_bda, HCI_PROTO_VERSION_4_2) + || interop_match(INTEROP_DISABLE_LE_SECURE_CONNECTIONS, + (const bt_bdaddr_t *)&p_cb->pairing_bda)) + { + p_cb->loc_auth_req &= ~SMP_KP_SUPPORT_BIT; + p_cb->local_i_key &= ~SMP_SEC_KEY_TYPE_LK; + p_cb->local_r_key &= ~SMP_SEC_KEY_TYPE_LK; + } + + SMP_TRACE_WARNING("set auth_req: 0x%02x, local_i_key: 0x%02x, local_r_key: 0x%02x", + p_cb->loc_auth_req, p_cb->local_i_key, p_cb->local_r_key); + + smp_sm_event(p_cb, SMP_IO_RSP_EVT, NULL); + break; + + case SMP_BR_KEYS_REQ_EVT: + p_cb->loc_enc_size = cb_data.io_req.max_key_size; + p_cb->local_i_key = cb_data.io_req.init_keys; + p_cb->local_r_key = cb_data.io_req.resp_keys; + + p_cb->local_i_key &= ~SMP_SEC_KEY_TYPE_LK; + p_cb->local_r_key &= ~SMP_SEC_KEY_TYPE_LK; + + SMP_TRACE_WARNING ( "for SMP over BR max_key_size: 0x%02x,\ + local_i_key: 0x%02x, local_r_key: 0x%02x", + p_cb->loc_enc_size, p_cb->local_i_key, p_cb->local_r_key); + + smp_br_state_machine_event(p_cb, SMP_BR_KEYS_RSP_EVT, NULL); + break; + } + } + } + + if (!p_cb->cb_evt && p_cb->discard_sec_req) + { + p_cb->discard_sec_req = FALSE; + smp_sm_event(p_cb, SMP_DISCARD_SEC_REQ_EVT, NULL); + } + + SMP_TRACE_DEBUG("%s return", __func__); +} + +/******************************************************************************* +** Function smp_send_pair_fail +** Description pairing failure to peer device if needed. +*******************************************************************************/ +void smp_send_pair_fail(tSMP_CB *p_cb, tSMP_INT_DATA *p_data) +{ + p_cb->status = *(UINT8 *)p_data; + p_cb->failure = *(UINT8 *)p_data; + + SMP_TRACE_DEBUG("%s status=%d failure=%d ", __func__, p_cb->status, p_cb->failure); + + if (p_cb->status <= SMP_MAX_FAIL_RSN_PER_SPEC && p_cb->status != SMP_SUCCESS) + { + smp_send_cmd(SMP_OPCODE_PAIRING_FAILED, p_cb); + p_cb->wait_for_authorization_complete = TRUE; + } +} + +/******************************************************************************* +** Function smp_send_pair_req +** Description actions related to sending pairing request +*******************************************************************************/ +void smp_send_pair_req(tSMP_CB *p_cb, tSMP_INT_DATA *p_data) +{ + tBTM_SEC_DEV_REC *p_dev_rec = btm_find_dev (p_cb->pairing_bda); + SMP_TRACE_DEBUG("%s", __func__); + + /* erase all keys when master sends pairing req*/ + if (p_dev_rec) + btm_sec_clear_ble_keys(p_dev_rec); + /* do not manipulate the key, let app decide, + leave out to BTM to mandate key distribution for bonding case */ + smp_send_cmd(SMP_OPCODE_PAIRING_REQ, p_cb); +} + +/******************************************************************************* +** Function smp_send_pair_rsp +** Description actions related to sending pairing response +*******************************************************************************/ +void smp_send_pair_rsp(tSMP_CB *p_cb, tSMP_INT_DATA *p_data) +{ + SMP_TRACE_DEBUG("%s", __func__); + + p_cb->local_i_key &= p_cb->peer_i_key; + p_cb->local_r_key &= p_cb->peer_r_key; + + if (smp_send_cmd (SMP_OPCODE_PAIRING_RSP, p_cb)) + { + if (p_cb->selected_association_model == SMP_MODEL_SEC_CONN_OOB) + smp_use_oob_private_key(p_cb, NULL); + else + smp_decide_association_model(p_cb, NULL); + } +} + +/******************************************************************************* +** Function smp_send_confirm +** Description send confirmation to the peer +*******************************************************************************/ +void smp_send_confirm(tSMP_CB *p_cb, tSMP_INT_DATA *p_data) +{ + SMP_TRACE_DEBUG("%s", __func__); + smp_send_cmd(SMP_OPCODE_CONFIRM, p_cb); +} + +/******************************************************************************* +** Function smp_send_init +** Description process pairing initializer to slave device +*******************************************************************************/ +void smp_send_init(tSMP_CB *p_cb, tSMP_INT_DATA *p_data) +{ + SMP_TRACE_DEBUG("%s", __func__); + smp_send_cmd(SMP_OPCODE_INIT, p_cb); +} + +/******************************************************************************* +** Function smp_send_rand +** Description send pairing random to the peer +*******************************************************************************/ +void smp_send_rand(tSMP_CB *p_cb, tSMP_INT_DATA *p_data) +{ + SMP_TRACE_DEBUG("%s", __func__); + smp_send_cmd(SMP_OPCODE_RAND, p_cb); +} + +/******************************************************************************* +** Function smp_send_pair_public_key +** Description send pairing public key command to the peer +*******************************************************************************/ +void smp_send_pair_public_key(tSMP_CB *p_cb, tSMP_INT_DATA *p_data) +{ + SMP_TRACE_DEBUG("%s", __func__); + smp_send_cmd(SMP_OPCODE_PAIR_PUBLIC_KEY, p_cb); +} + +/******************************************************************************* +** Function SMP_SEND_COMMITMENT +** Description send commitment command to the peer +*******************************************************************************/ +void smp_send_commitment(tSMP_CB *p_cb, tSMP_INT_DATA *p_data) +{ + SMP_TRACE_DEBUG("%s", __func__); + smp_send_cmd(SMP_OPCODE_PAIR_COMMITM, p_cb); +} + +/******************************************************************************* +** Function smp_send_dhkey_check +** Description send DHKey Check command to the peer +*******************************************************************************/ +void smp_send_dhkey_check(tSMP_CB *p_cb, tSMP_INT_DATA *p_data) +{ + SMP_TRACE_DEBUG("%s", __func__); + smp_send_cmd(SMP_OPCODE_PAIR_DHKEY_CHECK, p_cb); +} + +/******************************************************************************* +** Function smp_send_keypress_notification +** Description send Keypress Notification command to the peer +*******************************************************************************/ +void smp_send_keypress_notification(tSMP_CB *p_cb, tSMP_INT_DATA *p_data) +{ + p_cb->local_keypress_notification = *(UINT8 *) p_data; + smp_send_cmd(SMP_OPCODE_PAIR_KEYPR_NOTIF, p_cb); +} + +/******************************************************************************* +** Function smp_send_enc_info +** Description send encryption information command. +*******************************************************************************/ +void smp_send_enc_info(tSMP_CB *p_cb, tSMP_INT_DATA *p_data) +{ + tBTM_LE_LENC_KEYS le_key; + + SMP_TRACE_DEBUG("%s p_cb->loc_enc_size = %d", __func__, p_cb->loc_enc_size); + smp_update_key_mask (p_cb, SMP_SEC_KEY_TYPE_ENC, FALSE); + + smp_send_cmd(SMP_OPCODE_ENCRYPT_INFO, p_cb); + smp_send_cmd(SMP_OPCODE_MASTER_ID, p_cb); + + /* save the DIV and key size information when acting as slave device */ + memcpy(le_key.ltk, p_cb->ltk, BT_OCTET16_LEN); + le_key.div = p_cb->div; + le_key.key_size = p_cb->loc_enc_size; + le_key.sec_level = p_cb->sec_level; + + if ((p_cb->peer_auth_req & SMP_AUTH_BOND) && (p_cb->loc_auth_req & SMP_AUTH_BOND)) + btm_sec_save_le_key(p_cb->pairing_bda, BTM_LE_KEY_LENC, + (tBTM_LE_KEY_VALUE *)&le_key, TRUE); + + SMP_TRACE_WARNING ("%s", __func__); + + smp_key_distribution(p_cb, NULL); +} + +/******************************************************************************* +** Function smp_send_id_info +** Description send ID information command. +*******************************************************************************/ +void smp_send_id_info(tSMP_CB *p_cb, tSMP_INT_DATA *p_data) +{ + tBTM_LE_KEY_VALUE le_key; + SMP_TRACE_DEBUG("%s", __func__); + smp_update_key_mask (p_cb, SMP_SEC_KEY_TYPE_ID, FALSE); + + smp_send_cmd(SMP_OPCODE_IDENTITY_INFO, p_cb); + smp_send_cmd(SMP_OPCODE_ID_ADDR, p_cb); + + if ((p_cb->peer_auth_req & SMP_AUTH_BOND) && (p_cb->loc_auth_req & SMP_AUTH_BOND)) + btm_sec_save_le_key(p_cb->pairing_bda, BTM_LE_KEY_LID, + &le_key, TRUE); + + SMP_TRACE_WARNING ("%s", __func__); + smp_key_distribution_by_transport(p_cb, NULL); +} + +/******************************************************************************* +** Function smp_send_csrk_info +** Description send CSRK command. +*******************************************************************************/ +void smp_send_csrk_info(tSMP_CB *p_cb, tSMP_INT_DATA *p_data) +{ + tBTM_LE_LCSRK_KEYS key; + SMP_TRACE_DEBUG("%s", __func__); + smp_update_key_mask (p_cb, SMP_SEC_KEY_TYPE_CSRK, FALSE); + + if (smp_send_cmd(SMP_OPCODE_SIGN_INFO, p_cb)) + { + key.div = p_cb->div; + key.sec_level = p_cb->sec_level; + key.counter = 0; /* initialize the local counter */ + memcpy (key.csrk, p_cb->csrk, BT_OCTET16_LEN); + btm_sec_save_le_key(p_cb->pairing_bda, BTM_LE_KEY_LCSRK, (tBTM_LE_KEY_VALUE *)&key, TRUE); + } + + smp_key_distribution_by_transport(p_cb, NULL); +} + +/******************************************************************************* +** Function smp_send_ltk_reply +** Description send LTK reply +*******************************************************************************/ +void smp_send_ltk_reply(tSMP_CB *p_cb, tSMP_INT_DATA *p_data) +{ + SMP_TRACE_DEBUG("%s", __func__); + /* send stk as LTK response */ + btm_ble_ltk_request_reply(p_cb->pairing_bda, TRUE, p_data->key.p_data); +} + +/******************************************************************************* +** Function smp_proc_sec_req +** Description process security request. +*******************************************************************************/ +void smp_proc_sec_req(tSMP_CB *p_cb, tSMP_INT_DATA *p_data) +{ + tBTM_LE_AUTH_REQ auth_req = *(tBTM_LE_AUTH_REQ *)p_data; + tBTM_BLE_SEC_REQ_ACT sec_req_act; + UINT8 reason; + + SMP_TRACE_DEBUG("%s auth_req=0x%x", __func__, auth_req); + + p_cb->cb_evt = 0; + + btm_ble_link_sec_check(p_cb->pairing_bda, auth_req, &sec_req_act); + + SMP_TRACE_DEBUG("%s sec_req_act=0x%x", __func__, sec_req_act); + + switch (sec_req_act) + { + case BTM_BLE_SEC_REQ_ACT_ENCRYPT: + SMP_TRACE_DEBUG("%s BTM_BLE_SEC_REQ_ACT_ENCRYPT", __func__); + smp_sm_event(p_cb, SMP_ENC_REQ_EVT, NULL); + break; + + case BTM_BLE_SEC_REQ_ACT_PAIR: + p_cb->secure_connections_only_mode_required = + (btm_cb.security_mode == BTM_SEC_MODE_SC) ? TRUE : FALSE; + + /* respond to non SC pairing request as failure in SC only mode */ + if (p_cb->secure_connections_only_mode_required && + (auth_req & SMP_SC_SUPPORT_BIT) == 0) + { + reason = SMP_PAIR_AUTH_FAIL; + smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &reason); + } + else + { + /* initialize local i/r key to be default keys */ + p_cb->peer_auth_req = auth_req; + p_cb->local_r_key = p_cb->local_i_key = SMP_SEC_DEFAULT_KEY ; + p_cb->cb_evt = SMP_SEC_REQUEST_EVT; + } + break; + + case BTM_BLE_SEC_REQ_ACT_DISCARD: + p_cb->discard_sec_req = TRUE; + break; + + default: + /* do nothing */ + break; + } +} + +/******************************************************************************* +** Function smp_proc_sec_grant +** Description process security grant. +*******************************************************************************/ +void smp_proc_sec_grant(tSMP_CB *p_cb, tSMP_INT_DATA *p_data) +{ + UINT8 res= *(UINT8 *)p_data; + SMP_TRACE_DEBUG("%s", __func__); + if (res != SMP_SUCCESS) + { + smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, p_data); + } + else /*otherwise, start pairing */ + { + /* send IO request callback */ + p_cb->cb_evt = SMP_IO_CAP_REQ_EVT; + } +} + +/******************************************************************************* +** Function smp_proc_pair_fail +** Description process pairing failure from peer device +*******************************************************************************/ +void smp_proc_pair_fail(tSMP_CB *p_cb, tSMP_INT_DATA *p_data) +{ + SMP_TRACE_DEBUG("%s", __func__); + p_cb->status = *(UINT8 *)p_data; +} + +/******************************************************************************* +** Function smp_proc_pair_cmd +** Description Process the SMP pairing request/response from peer device +*******************************************************************************/ +void smp_proc_pair_cmd(tSMP_CB *p_cb, tSMP_INT_DATA *p_data) +{ + UINT8 *p = (UINT8 *)p_data; + UINT8 reason = SMP_ENC_KEY_SIZE; + tBTM_SEC_DEV_REC *p_dev_rec = btm_find_dev (p_cb->pairing_bda); + + SMP_TRACE_DEBUG("%s", __func__); + /* erase all keys if it is slave proc pairing req*/ + if (p_dev_rec && (p_cb->role == HCI_ROLE_SLAVE)) + btm_sec_clear_ble_keys(p_dev_rec); + + p_cb->flags |= SMP_PAIR_FLAG_ENC_AFTER_PAIR; + + STREAM_TO_UINT8(p_cb->peer_io_caps, p); + STREAM_TO_UINT8(p_cb->peer_oob_flag, p); + STREAM_TO_UINT8(p_cb->peer_auth_req, p); + STREAM_TO_UINT8(p_cb->peer_enc_size, p); + STREAM_TO_UINT8(p_cb->peer_i_key, p); + STREAM_TO_UINT8(p_cb->peer_r_key, p); + + if (smp_command_has_invalid_parameters(p_cb)) + { + reason = SMP_INVALID_PARAMETERS; + smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &reason); + return; + } + + if (p_cb->role == HCI_ROLE_SLAVE) + { + if (!(p_cb->flags & SMP_PAIR_FLAGS_WE_STARTED_DD)) + { + /* peer (master) started pairing sending Pairing Request */ + p_cb->local_i_key = p_cb->peer_i_key; + p_cb->local_r_key = p_cb->peer_r_key; + + p_cb->cb_evt = SMP_SEC_REQUEST_EVT; + } + else /* update local i/r key according to pairing request */ + { + /* pairing started with this side (slave) sending Security Request */ + p_cb->local_i_key &= p_cb->peer_i_key; + p_cb->local_r_key &= p_cb->peer_r_key; + p_cb->selected_association_model = smp_select_association_model(p_cb); + + if (p_cb->secure_connections_only_mode_required && + (!(p_cb->le_secure_connections_mode_is_used) || + (p_cb->selected_association_model == SMP_MODEL_SEC_CONN_JUSTWORKS))) + { + SMP_TRACE_ERROR("%s pairing failed - slave requires secure connection only mode", + __func__); + reason = SMP_PAIR_AUTH_FAIL; + smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &reason); + return; + } + + if (p_cb->selected_association_model == SMP_MODEL_SEC_CONN_OOB) + { + if (smp_request_oob_data(p_cb)) return; + } + else + { + smp_send_pair_rsp(p_cb, NULL); + } + } + } + else /* Master receives pairing response */ + { + p_cb->selected_association_model = smp_select_association_model(p_cb); + + if (p_cb->secure_connections_only_mode_required && + (!(p_cb->le_secure_connections_mode_is_used) || + (p_cb->selected_association_model == SMP_MODEL_SEC_CONN_JUSTWORKS))) + { + SMP_TRACE_ERROR ("Master requires secure connection only mode \ + but it can't be provided -> Master fails pairing"); + reason = SMP_PAIR_AUTH_FAIL; + smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &reason); + return; + } + + if (p_cb->selected_association_model == SMP_MODEL_SEC_CONN_OOB) + { + if (smp_request_oob_data(p_cb)) return; + } + else + { + smp_decide_association_model(p_cb, NULL); + } + } +} + +/******************************************************************************* +** Function smp_proc_confirm +** Description process pairing confirm from peer device +*******************************************************************************/ +void smp_proc_confirm(tSMP_CB *p_cb, tSMP_INT_DATA *p_data) +{ + UINT8 *p = (UINT8 *)p_data; + UINT8 reason = SMP_INVALID_PARAMETERS; + + SMP_TRACE_DEBUG("%s", __func__); + + if (smp_command_has_invalid_parameters(p_cb)) + { + smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &reason); + return; + } + + if (p != NULL) + { + /* save the SConfirm for comparison later */ + STREAM_TO_ARRAY(p_cb->rconfirm, p, BT_OCTET16_LEN); + } + + p_cb->flags |= SMP_PAIR_FLAGS_CMD_CONFIRM; +} + +/******************************************************************************* +** Function smp_proc_init +** Description process pairing initializer from peer device +*******************************************************************************/ +void smp_proc_init(tSMP_CB *p_cb, tSMP_INT_DATA *p_data) +{ + UINT8 *p = (UINT8 *)p_data; + UINT8 reason = SMP_INVALID_PARAMETERS; + + SMP_TRACE_DEBUG("%s", __func__); + + if (smp_command_has_invalid_parameters(p_cb)) + { + smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &reason); + return; + } + + /* save the SRand for comparison */ + STREAM_TO_ARRAY(p_cb->rrand, p, BT_OCTET16_LEN); +} + +/******************************************************************************* +** Function smp_proc_rand +** Description process pairing random (nonce) from peer device +*******************************************************************************/ +void smp_proc_rand(tSMP_CB *p_cb, tSMP_INT_DATA *p_data) +{ + UINT8 *p = (UINT8 *)p_data; + UINT8 reason = SMP_INVALID_PARAMETERS; + + SMP_TRACE_DEBUG("%s", __func__); + + if (smp_command_has_invalid_parameters(p_cb)) + { + smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &reason); + return; + } + + /* save the SRand for comparison */ + STREAM_TO_ARRAY(p_cb->rrand, p, BT_OCTET16_LEN); +} + +/******************************************************************************* +** Function smp_process_pairing_public_key +** Description process pairing public key command from the peer device +** - saves the peer public key; +** - sets the flag indicating that the peer public key is received; +** - calls smp_wait_for_both_public_keys(...). +** +*******************************************************************************/ +void smp_process_pairing_public_key(tSMP_CB *p_cb, tSMP_INT_DATA *p_data) +{ + UINT8 *p = (UINT8 *)p_data; + UINT8 reason = SMP_INVALID_PARAMETERS; + + SMP_TRACE_DEBUG("%s", __func__); + + if (smp_command_has_invalid_parameters(p_cb)) + { + smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &reason); + return; + } + + STREAM_TO_ARRAY(p_cb->peer_publ_key.x, p, BT_OCTET32_LEN); + STREAM_TO_ARRAY(p_cb->peer_publ_key.y, p, BT_OCTET32_LEN); + p_cb->flags |= SMP_PAIR_FLAG_HAVE_PEER_PUBL_KEY; + + smp_wait_for_both_public_keys(p_cb, NULL); +} + +/******************************************************************************* +** Function smp_process_pairing_commitment +** Description process pairing commitment from peer device +*******************************************************************************/ +void smp_process_pairing_commitment(tSMP_CB *p_cb, tSMP_INT_DATA *p_data) +{ + UINT8 *p = (UINT8 *)p_data; + UINT8 reason = SMP_INVALID_PARAMETERS; + + SMP_TRACE_DEBUG("%s", __func__); + + if (smp_command_has_invalid_parameters(p_cb)) + { + smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &reason); + return; + } + + p_cb->flags |= SMP_PAIR_FLAG_HAVE_PEER_COMM; + + if (p != NULL) + { + STREAM_TO_ARRAY(p_cb->remote_commitment, p, BT_OCTET16_LEN); + } +} + +/******************************************************************************* +** Function smp_process_dhkey_check +** Description process DHKey Check from peer device +*******************************************************************************/ +void smp_process_dhkey_check(tSMP_CB *p_cb, tSMP_INT_DATA *p_data) +{ + UINT8 *p = (UINT8 *)p_data; + UINT8 reason = SMP_INVALID_PARAMETERS; + + SMP_TRACE_DEBUG("%s", __func__); + + if (smp_command_has_invalid_parameters(p_cb)) + { + smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &reason); + return; + } + + if (p != NULL) + { + STREAM_TO_ARRAY(p_cb->remote_dhkey_check, p, BT_OCTET16_LEN); + } + + p_cb->flags |= SMP_PAIR_FLAG_HAVE_PEER_DHK_CHK; +} + +/******************************************************************************* +** Function smp_process_keypress_notification +** Description process pairing keypress notification from peer device +*******************************************************************************/ +void smp_process_keypress_notification(tSMP_CB *p_cb, tSMP_INT_DATA *p_data) +{ + UINT8 *p = (UINT8 *)p_data; + UINT8 reason = SMP_INVALID_PARAMETERS; + + SMP_TRACE_DEBUG("%s", __func__); + p_cb->status = *(UINT8 *)p_data; + + if (smp_command_has_invalid_parameters(p_cb)) + { + smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &reason); + return; + } + + if (p != NULL) + { + STREAM_TO_UINT8(p_cb->peer_keypress_notification, p); + } + else + { + p_cb->peer_keypress_notification = BTM_SP_KEY_OUT_OF_RANGE; + } + p_cb->cb_evt = SMP_PEER_KEYPR_NOT_EVT; +} + +/******************************************************************************* +** Function smp_br_process_pairing_command +** Description Process the SMP pairing request/response from peer device via +** BR/EDR transport. +*******************************************************************************/ +void smp_br_process_pairing_command(tSMP_CB *p_cb, tSMP_INT_DATA *p_data) +{ + UINT8 *p = (UINT8 *)p_data; + UINT8 reason = SMP_ENC_KEY_SIZE; + tBTM_SEC_DEV_REC *p_dev_rec = btm_find_dev (p_cb->pairing_bda); + + SMP_TRACE_DEBUG("%s", __func__); + /* rejecting BR pairing request over non-SC BR link */ + if (!p_dev_rec->new_encryption_key_is_p256 && p_cb->role == HCI_ROLE_SLAVE) + { + reason = SMP_XTRANS_DERIVE_NOT_ALLOW; + smp_br_state_machine_event(p_cb, SMP_BR_AUTH_CMPL_EVT, &reason); + return; + } + + /* erase all keys if it is slave proc pairing req*/ + if (p_dev_rec && (p_cb->role == HCI_ROLE_SLAVE)) + btm_sec_clear_ble_keys(p_dev_rec); + + p_cb->flags |= SMP_PAIR_FLAG_ENC_AFTER_PAIR; + + STREAM_TO_UINT8(p_cb->peer_io_caps, p); + STREAM_TO_UINT8(p_cb->peer_oob_flag, p); + STREAM_TO_UINT8(p_cb->peer_auth_req, p); + STREAM_TO_UINT8(p_cb->peer_enc_size, p); + STREAM_TO_UINT8(p_cb->peer_i_key, p); + STREAM_TO_UINT8(p_cb->peer_r_key, p); + + if (smp_command_has_invalid_parameters(p_cb)) + { + reason = SMP_INVALID_PARAMETERS; + smp_br_state_machine_event(p_cb, SMP_BR_AUTH_CMPL_EVT, &reason); + return; + } + + /* peer (master) started pairing sending Pairing Request */ + /* or being master device always use received i/r key as keys to distribute */ + p_cb->local_i_key = p_cb->peer_i_key; + p_cb->local_r_key = p_cb->peer_r_key; + + if (p_cb->role == HCI_ROLE_SLAVE) + { + p_dev_rec->new_encryption_key_is_p256 = FALSE; + /* shortcut to skip Security Grant step */ + p_cb->cb_evt = SMP_BR_KEYS_REQ_EVT; + } + else /* Master receives pairing response */ + { + SMP_TRACE_DEBUG("%s master rcvs valid PAIRING RESPONSE." + " Supposed to move to key distribution phase. ", __func__); + } + + /* auth_req received via BR/EDR SM channel is set to 0, + but everything derived/exchanged has to be saved */ + p_cb->peer_auth_req |= SMP_AUTH_BOND; + p_cb->loc_auth_req |= SMP_AUTH_BOND; +} + +/******************************************************************************* +** Function smp_br_process_security_grant +** Description process security grant in case of pairing over BR/EDR transport. +*******************************************************************************/ +void smp_br_process_security_grant(tSMP_CB *p_cb, tSMP_INT_DATA *p_data) +{ + UINT8 res= *(UINT8 *)p_data; + SMP_TRACE_DEBUG("%s", __func__); + if (res != SMP_SUCCESS) + { + smp_br_state_machine_event(p_cb, SMP_BR_AUTH_CMPL_EVT, p_data); + } + else /*otherwise, start pairing */ + { + /* send IO request callback */ + p_cb->cb_evt = SMP_BR_KEYS_REQ_EVT; + } +} + +/******************************************************************************* +** Function smp_br_check_authorization_request +** Description sets the SMP kes to be derived/distribute over BR/EDR transport +** before starting the distribution/derivation +*******************************************************************************/ +void smp_br_check_authorization_request(tSMP_CB *p_cb, tSMP_INT_DATA *p_data) +{ + UINT8 reason = SMP_SUCCESS; + + SMP_TRACE_DEBUG("%s rcvs i_keys=0x%x r_keys=0x%x " + "(i-initiator r-responder)", __FUNCTION__, p_cb->local_i_key, + p_cb->local_r_key); + + /* In LE SC mode LK field is ignored when BR/EDR transport is used */ + p_cb->local_i_key &= ~SMP_SEC_KEY_TYPE_LK; + p_cb->local_r_key &= ~SMP_SEC_KEY_TYPE_LK; + + /* In LE SC mode only IRK, IAI, CSRK are exchanged with the peer. + ** Set local_r_key on master to expect only these keys. */ + if (p_cb->role == HCI_ROLE_MASTER) + { + p_cb->local_r_key &= (SMP_SEC_KEY_TYPE_ID | SMP_SEC_KEY_TYPE_CSRK); + } + + SMP_TRACE_DEBUG("%s rcvs upgrades: i_keys=0x%x r_keys=0x%x " + "(i-initiator r-responder)", __FUNCTION__, p_cb->local_i_key, + p_cb->local_r_key); + + if (/*((p_cb->peer_auth_req & SMP_AUTH_BOND) || + (p_cb->loc_auth_req & SMP_AUTH_BOND)) &&*/ + (p_cb->local_i_key || p_cb->local_r_key)) + { + smp_br_state_machine_event(p_cb, SMP_BR_BOND_REQ_EVT, NULL); + + /* if no peer key is expected, start master key distribution */ + if (p_cb->role == HCI_ROLE_MASTER && p_cb->local_r_key == 0) + smp_key_distribution_by_transport(p_cb, NULL); + } + else + { + smp_br_state_machine_event(p_cb, SMP_BR_AUTH_CMPL_EVT, &reason); + } +} + +/******************************************************************************* +** Function smp_br_select_next_key +** Description selects the next key to derive/send when BR/EDR transport is +** used. +*******************************************************************************/ +void smp_br_select_next_key(tSMP_CB *p_cb, tSMP_INT_DATA *p_data) +{ + UINT8 reason = SMP_SUCCESS; + SMP_TRACE_DEBUG("%s role=%d (0-master) r_keys=0x%x i_keys=0x%x", + __func__, p_cb->role, p_cb->local_r_key, p_cb->local_i_key); + + if (p_cb->role == HCI_ROLE_SLAVE|| + (!p_cb->local_r_key && p_cb->role == HCI_ROLE_MASTER)) + { + smp_key_pick_key(p_cb, p_data); + } + + if (!p_cb->local_i_key && !p_cb->local_r_key) + { + /* state check to prevent re-entrance */ + if (smp_get_br_state() == SMP_BR_STATE_BOND_PENDING) + { + if (p_cb->total_tx_unacked == 0) + smp_br_state_machine_event(p_cb, SMP_BR_AUTH_CMPL_EVT, &reason); + else + p_cb->wait_for_authorization_complete = TRUE; + } + } +} + +/******************************************************************************* +** Function smp_proc_enc_info +** Description process encryption information from peer device +*******************************************************************************/ +void smp_proc_enc_info(tSMP_CB *p_cb, tSMP_INT_DATA *p_data) +{ + UINT8 *p = (UINT8 *)p_data; + + SMP_TRACE_DEBUG("%s", __func__); + STREAM_TO_ARRAY(p_cb->ltk, p, BT_OCTET16_LEN); + + smp_key_distribution(p_cb, NULL); +} +/******************************************************************************* +** Function smp_proc_master_id +** Description process master ID from slave device +*******************************************************************************/ +void smp_proc_master_id(tSMP_CB *p_cb, tSMP_INT_DATA *p_data) +{ + UINT8 *p = (UINT8 *)p_data; + tBTM_LE_PENC_KEYS le_key; + + SMP_TRACE_DEBUG("%s", __func__); + smp_update_key_mask (p_cb, SMP_SEC_KEY_TYPE_ENC, TRUE); + + STREAM_TO_UINT16(le_key.ediv, p); + STREAM_TO_ARRAY(le_key.rand, p, BT_OCTET8_LEN ); + + /* store the encryption keys from peer device */ + memcpy(le_key.ltk, p_cb->ltk, BT_OCTET16_LEN); + le_key.sec_level = p_cb->sec_level; + le_key.key_size = p_cb->loc_enc_size; + + if ((p_cb->peer_auth_req & SMP_AUTH_BOND) && (p_cb->loc_auth_req & SMP_AUTH_BOND)) + btm_sec_save_le_key(p_cb->pairing_bda, + BTM_LE_KEY_PENC, + (tBTM_LE_KEY_VALUE *)&le_key, TRUE); + + smp_key_distribution(p_cb, NULL); +} + +/******************************************************************************* +** Function smp_proc_enc_info +** Description process identity information from peer device +*******************************************************************************/ +void smp_proc_id_info(tSMP_CB *p_cb, tSMP_INT_DATA *p_data) +{ + UINT8 *p = (UINT8 *)p_data; + + SMP_TRACE_DEBUG("%s", __func__); + STREAM_TO_ARRAY (p_cb->tk, p, BT_OCTET16_LEN); /* reuse TK for IRK */ + smp_key_distribution_by_transport(p_cb, NULL); +} + +/******************************************************************************* +** Function smp_proc_id_addr +** Description process identity address from peer device +*******************************************************************************/ +void smp_proc_id_addr(tSMP_CB *p_cb, tSMP_INT_DATA *p_data) +{ + UINT8 *p = (UINT8 *)p_data; + tBTM_LE_PID_KEYS pid_key; + + SMP_TRACE_DEBUG("%s", __func__); + smp_update_key_mask (p_cb, SMP_SEC_KEY_TYPE_ID, TRUE); + + STREAM_TO_UINT8(pid_key.addr_type, p); + STREAM_TO_BDADDR(pid_key.static_addr, p); + memcpy(pid_key.irk, p_cb->tk, BT_OCTET16_LEN); + + /* to use as BD_ADDR for lk derived from ltk */ + p_cb->id_addr_rcvd = TRUE; + p_cb->id_addr_type = pid_key.addr_type; + memcpy(p_cb->id_addr, pid_key.static_addr, BD_ADDR_LEN); + + /* store the ID key from peer device */ + if ((p_cb->peer_auth_req & SMP_AUTH_BOND) && (p_cb->loc_auth_req & SMP_AUTH_BOND)) + btm_sec_save_le_key(p_cb->pairing_bda, BTM_LE_KEY_PID, + (tBTM_LE_KEY_VALUE *)&pid_key, TRUE); + smp_key_distribution_by_transport(p_cb, NULL); +} + +/******************************************************************************* +** Function smp_proc_srk_info +** Description process security information from peer device +*******************************************************************************/ +void smp_proc_srk_info(tSMP_CB *p_cb, tSMP_INT_DATA *p_data) +{ + tBTM_LE_PCSRK_KEYS le_key; + + SMP_TRACE_DEBUG("%s", __func__); + smp_update_key_mask (p_cb, SMP_SEC_KEY_TYPE_CSRK, TRUE); + + /* save CSRK to security record */ + le_key.sec_level = p_cb->sec_level; + memcpy (le_key.csrk, p_data, BT_OCTET16_LEN); /* get peer CSRK */ + le_key.counter = 0; /* initialize the peer counter */ + + if ((p_cb->peer_auth_req & SMP_AUTH_BOND) && (p_cb->loc_auth_req & SMP_AUTH_BOND)) + btm_sec_save_le_key(p_cb->pairing_bda, + BTM_LE_KEY_PCSRK, + (tBTM_LE_KEY_VALUE *)&le_key, TRUE); + smp_key_distribution_by_transport(p_cb, NULL); +} + +/******************************************************************************* +** Function smp_proc_compare +** Description process compare value +*******************************************************************************/ +void smp_proc_compare(tSMP_CB *p_cb, tSMP_INT_DATA *p_data) +{ + UINT8 reason; + + SMP_TRACE_DEBUG("%s", __func__); + if (!memcmp(p_cb->rconfirm, p_data->key.p_data, BT_OCTET16_LEN)) + { + /* compare the max encryption key size, and save the smaller one for the link */ + if ( p_cb->peer_enc_size < p_cb->loc_enc_size) + p_cb->loc_enc_size = p_cb->peer_enc_size; + + if (p_cb->role == HCI_ROLE_SLAVE) + smp_sm_event(p_cb, SMP_RAND_EVT, NULL); + else + { + /* master device always use received i/r key as keys to distribute */ + p_cb->local_i_key = p_cb->peer_i_key; + p_cb->local_r_key = p_cb->peer_r_key; + + smp_sm_event(p_cb, SMP_ENC_REQ_EVT, NULL); + } + + } + else + { + reason = p_cb->failure = SMP_CONFIRM_VALUE_ERR; + smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &reason); + } +} + +/******************************************************************************* +** Function smp_proc_sl_key +** Description process key ready events. +*******************************************************************************/ +void smp_proc_sl_key(tSMP_CB *p_cb, tSMP_INT_DATA *p_data) +{ + UINT8 key_type = p_data->key.key_type; + + SMP_TRACE_DEBUG("%s", __func__); + if (key_type == SMP_KEY_TYPE_TK) + { + smp_generate_srand_mrand_confirm(p_cb, NULL); + } + else if (key_type == SMP_KEY_TYPE_CFM) + { + smp_set_state(SMP_STATE_WAIT_CONFIRM); + + if (p_cb->flags & SMP_PAIR_FLAGS_CMD_CONFIRM) + smp_sm_event(p_cb, SMP_CONFIRM_EVT, NULL); + } +} + +/******************************************************************************* +** Function smp_start_enc +** Description start encryption +*******************************************************************************/ +void smp_start_enc(tSMP_CB *p_cb, tSMP_INT_DATA *p_data) +{ + tBTM_STATUS cmd; + UINT8 reason = SMP_ENC_FAIL; + + SMP_TRACE_DEBUG("%s", __func__); + if (p_data != NULL) + cmd = btm_ble_start_encrypt(p_cb->pairing_bda, TRUE, p_data->key.p_data); + else + cmd = btm_ble_start_encrypt(p_cb->pairing_bda, FALSE, NULL); + + if (cmd != BTM_CMD_STARTED && cmd != BTM_BUSY) + smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &reason); +} + +/******************************************************************************* +** Function smp_proc_discard +** Description processing for discard security request +*******************************************************************************/ +void smp_proc_discard(tSMP_CB *p_cb, tSMP_INT_DATA *p_data) +{ + SMP_TRACE_DEBUG("%s", __func__); + if (!(p_cb->flags & SMP_PAIR_FLAGS_WE_STARTED_DD)) + smp_reset_control_value(p_cb); +} + +/******************************************************************************* +** Function smp_enc_cmpl +** Description encryption success +*******************************************************************************/ +void smp_enc_cmpl(tSMP_CB *p_cb, tSMP_INT_DATA *p_data) +{ + UINT8 enc_enable = *(UINT8 *)p_data; + UINT8 reason = enc_enable ? SMP_SUCCESS : SMP_ENC_FAIL; + + SMP_TRACE_DEBUG("%s", __func__); + smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &reason); +} + +/******************************************************************************* +** Function smp_check_auth_req +** Description check authentication request +*******************************************************************************/ +void smp_check_auth_req(tSMP_CB *p_cb, tSMP_INT_DATA *p_data) +{ + UINT8 enc_enable = *(UINT8 *)p_data; + UINT8 reason = enc_enable ? SMP_SUCCESS : SMP_ENC_FAIL; + + SMP_TRACE_DEBUG("%s rcvs enc_enable=%d i_keys=0x%x r_keys=0x%x " + "(i-initiator r-responder)", + __func__, enc_enable, p_cb->local_i_key, p_cb->local_r_key); + if (enc_enable == 1) + { + if (p_cb->le_secure_connections_mode_is_used) + { + /* In LE SC mode LTK is used instead of STK and has to be always saved */ + p_cb->local_i_key |= SMP_SEC_KEY_TYPE_ENC; + p_cb->local_r_key |= SMP_SEC_KEY_TYPE_ENC; + + /* In LE SC mode LK is derived from LTK only if both sides request it */ + if (!(p_cb->local_i_key & SMP_SEC_KEY_TYPE_LK) || + !(p_cb->local_r_key & SMP_SEC_KEY_TYPE_LK)) + { + p_cb->local_i_key &= ~SMP_SEC_KEY_TYPE_LK; + p_cb->local_r_key &= ~SMP_SEC_KEY_TYPE_LK; + } + + /* In LE SC mode only IRK, IAI, CSRK are exchanged with the peer. + ** Set local_r_key on master to expect only these keys. + */ + if (p_cb->role == HCI_ROLE_MASTER) + { + p_cb->local_r_key &= (SMP_SEC_KEY_TYPE_ID | SMP_SEC_KEY_TYPE_CSRK); + } + } + else + { + /* in legacy mode derivation of BR/EDR LK is not supported */ + p_cb->local_i_key &= ~SMP_SEC_KEY_TYPE_LK; + p_cb->local_r_key &= ~SMP_SEC_KEY_TYPE_LK; + } + SMP_TRACE_DEBUG("%s rcvs upgrades: i_keys=0x%x r_keys=0x%x " + "(i-initiator r-responder)", + __func__, p_cb->local_i_key, p_cb->local_r_key); + + if (/*((p_cb->peer_auth_req & SMP_AUTH_BOND) || + (p_cb->loc_auth_req & SMP_AUTH_BOND)) &&*/ + (p_cb->local_i_key || p_cb->local_r_key)) + { + smp_sm_event(p_cb, SMP_BOND_REQ_EVT, NULL); + } + else + smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &reason); + } + else if (enc_enable == 0) + { + /* if failed for encryption after pairing, send callback */ + if (p_cb->flags & SMP_PAIR_FLAG_ENC_AFTER_PAIR) + smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &reason); + /* if enc failed for old security information */ + /* if master device, clean up and abck to idle; slave device do nothing */ + else if (p_cb->role == HCI_ROLE_MASTER) + { + smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &reason); + } + } +} + +/******************************************************************************* +** Function smp_key_pick_key +** Description Pick a key distribution function based on the key mask. +*******************************************************************************/ +void smp_key_pick_key(tSMP_CB *p_cb, tSMP_INT_DATA *p_data) +{ + UINT8 key_to_dist = (p_cb->role == HCI_ROLE_SLAVE) ? p_cb->local_r_key : p_cb->local_i_key; + UINT8 i = 0; + + SMP_TRACE_DEBUG("%s key_to_dist=0x%x", __func__, key_to_dist); + while (i < SMP_KEY_DIST_TYPE_MAX) + { + SMP_TRACE_DEBUG("key to send = %02x, i = %d", key_to_dist, i); + + if (key_to_dist & (1 << i)) + { + SMP_TRACE_DEBUG("smp_distribute_act[%d]", i); + (* smp_distribute_act[i])(p_cb, p_data); + break; + } + i ++; + } +} +/******************************************************************************* +** Function smp_key_distribution +** Description start key distribution if required. +*******************************************************************************/ +void smp_key_distribution(tSMP_CB *p_cb, tSMP_INT_DATA *p_data) +{ + UINT8 reason = SMP_SUCCESS; + SMP_TRACE_DEBUG("%s role=%d (0-master) r_keys=0x%x i_keys=0x%x", + __func__, p_cb->role, p_cb->local_r_key, p_cb->local_i_key); + + if (p_cb->role == HCI_ROLE_SLAVE || + (!p_cb->local_r_key && p_cb->role == HCI_ROLE_MASTER)) + { + smp_key_pick_key(p_cb, p_data); + } + + if (!p_cb->local_i_key && !p_cb->local_r_key) + { + /* state check to prevent re-entrant */ + if (smp_get_state() == SMP_STATE_BOND_PENDING) + { + if (p_cb->derive_lk) + { + smp_derive_link_key_from_long_term_key(p_cb, NULL); + p_cb->derive_lk = FALSE; + } + + if (p_cb->total_tx_unacked == 0) + smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &reason); + else + p_cb->wait_for_authorization_complete = TRUE; + } + } +} + +/******************************************************************************* +** Function smp_decide_association_model +** Description This function is called to select assoc model to be used for +** STK generation and to start STK generation process. +** +*******************************************************************************/ +void smp_decide_association_model(tSMP_CB *p_cb, tSMP_INT_DATA *p_data) +{ + UINT8 failure = SMP_UNKNOWN_IO_CAP; + UINT8 int_evt = 0; + tSMP_KEY key; + tSMP_INT_DATA *p = NULL; + + SMP_TRACE_DEBUG("%s Association Model = %d", __func__, p_cb->selected_association_model); + + switch (p_cb->selected_association_model) + { + case SMP_MODEL_ENCRYPTION_ONLY: /* TK = 0, go calculate Confirm */ + if (p_cb->role == HCI_ROLE_MASTER && + ((p_cb->peer_auth_req & SMP_AUTH_YN_BIT) != 0) && + ((p_cb->loc_auth_req & SMP_AUTH_YN_BIT) == 0)) + { + SMP_TRACE_ERROR ("IO capability does not meet authentication requirement"); + failure = SMP_PAIR_AUTH_FAIL; + p = (tSMP_INT_DATA *)&failure; + int_evt = SMP_AUTH_CMPL_EVT; + } + else + { + p_cb->sec_level = SMP_SEC_UNAUTHENTICATE; + SMP_TRACE_EVENT ("p_cb->sec_level =%d (SMP_SEC_UNAUTHENTICATE) ", p_cb->sec_level ); + + key.key_type = SMP_KEY_TYPE_TK; + key.p_data = p_cb->tk; + p = (tSMP_INT_DATA *)&key; + + memset(p_cb->tk, 0, BT_OCTET16_LEN); + /* TK, ready */ + int_evt = SMP_KEY_READY_EVT; + } + break; + + case SMP_MODEL_PASSKEY: + p_cb->sec_level = SMP_SEC_AUTHENTICATED; + SMP_TRACE_EVENT ("p_cb->sec_level =%d (SMP_SEC_AUTHENTICATED) ", p_cb->sec_level ); + + p_cb->cb_evt = SMP_PASSKEY_REQ_EVT; + int_evt = SMP_TK_REQ_EVT; + break; + + case SMP_MODEL_OOB: + SMP_TRACE_ERROR ("Association Model = SMP_MODEL_OOB"); + p_cb->sec_level = SMP_SEC_AUTHENTICATED; + SMP_TRACE_EVENT ("p_cb->sec_level =%d (SMP_SEC_AUTHENTICATED) ", p_cb->sec_level ); + + p_cb->cb_evt = SMP_OOB_REQ_EVT; + int_evt = SMP_TK_REQ_EVT; + break; + + case SMP_MODEL_KEY_NOTIF: + p_cb->sec_level = SMP_SEC_AUTHENTICATED; + SMP_TRACE_DEBUG("Need to generate Passkey"); + + /* generate passkey and notify application */ + smp_generate_passkey(p_cb, NULL); + break; + + case SMP_MODEL_SEC_CONN_JUSTWORKS: + case SMP_MODEL_SEC_CONN_NUM_COMP: + case SMP_MODEL_SEC_CONN_PASSKEY_ENT: + case SMP_MODEL_SEC_CONN_PASSKEY_DISP: + case SMP_MODEL_SEC_CONN_OOB: + int_evt = SMP_PUBL_KEY_EXCH_REQ_EVT; + break; + + case SMP_MODEL_OUT_OF_RANGE: + SMP_TRACE_ERROR("Association Model = SMP_MODEL_OUT_OF_RANGE (failed)"); + p = (tSMP_INT_DATA *)&failure; + int_evt = SMP_AUTH_CMPL_EVT; + break; + + default: + SMP_TRACE_ERROR("Association Model = %d (SOMETHING IS WRONG WITH THE CODE)", + p_cb->selected_association_model); + p = (tSMP_INT_DATA *)&failure; + int_evt = SMP_AUTH_CMPL_EVT; + } + + SMP_TRACE_EVENT ("sec_level=%d ", p_cb->sec_level ); + if (int_evt) + smp_sm_event(p_cb, int_evt, p); +} + +/******************************************************************************* +** Function smp_process_io_response +** Description process IO response for a slave device. +*******************************************************************************/ +void smp_process_io_response(tSMP_CB *p_cb, tSMP_INT_DATA *p_data) +{ + uint8_t reason = SMP_PAIR_AUTH_FAIL; + + SMP_TRACE_DEBUG("%s", __func__); + if (p_cb->flags & SMP_PAIR_FLAGS_WE_STARTED_DD) + { + /* pairing started by local (slave) Security Request */ + smp_set_state(SMP_STATE_SEC_REQ_PENDING); + smp_send_cmd(SMP_OPCODE_SEC_REQ, p_cb); + } + else /* plan to send pairing respond */ + { + /* pairing started by peer (master) Pairing Request */ + p_cb->selected_association_model = smp_select_association_model(p_cb); + + if (p_cb->secure_connections_only_mode_required && + (!(p_cb->le_secure_connections_mode_is_used) || + (p_cb->selected_association_model == SMP_MODEL_SEC_CONN_JUSTWORKS))) + { + SMP_TRACE_ERROR ("Slave requires secure connection only mode \ + but it can't be provided -> Slave fails pairing"); + smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &reason); + return; + } + + if (p_cb->selected_association_model == SMP_MODEL_SEC_CONN_OOB) + { + if (smp_request_oob_data(p_cb)) return; + } + smp_send_pair_rsp(p_cb, NULL); + } +} + +/******************************************************************************* +** Function smp_br_process_slave_keys_response +** Description process application keys response for a slave device +** (BR/EDR transport). +*******************************************************************************/ +void smp_br_process_slave_keys_response(tSMP_CB *p_cb, tSMP_INT_DATA *p_data) +{ + smp_br_send_pair_response(p_cb, NULL); +} + +/******************************************************************************* +** Function smp_br_send_pair_response +** Description actions related to sending pairing response over BR/EDR transport. +*******************************************************************************/ +void smp_br_send_pair_response(tSMP_CB *p_cb, tSMP_INT_DATA *p_data) +{ + SMP_TRACE_DEBUG("%s", __func__); + + p_cb->local_i_key &= p_cb->peer_i_key; + p_cb->local_r_key &= p_cb->peer_r_key; + + smp_send_cmd (SMP_OPCODE_PAIRING_RSP, p_cb); +} + +/******************************************************************************* +** Function smp_pairing_cmpl +** Description This function is called to send the pairing complete callback +** and remove the connection if needed. +*******************************************************************************/ +void smp_pairing_cmpl(tSMP_CB *p_cb, tSMP_INT_DATA *p_data) +{ + if (p_cb->total_tx_unacked == 0) + { + /* update connection parameter to remote preferred */ + L2CA_EnableUpdateBleConnParams(p_cb->pairing_bda, TRUE); + /* process the pairing complete */ + smp_proc_pairing_cmpl(p_cb); + } +} + +/******************************************************************************* +** Function smp_pair_terminate +** Description This function is called to send the pairing complete callback +** and remove the connection if needed. +*******************************************************************************/ +void smp_pair_terminate(tSMP_CB *p_cb, tSMP_INT_DATA *p_data) +{ + SMP_TRACE_DEBUG("%s", __func__); + p_cb->status = SMP_CONN_TOUT; + smp_proc_pairing_cmpl(p_cb); +} + +/******************************************************************************* +** Function smp_idle_terminate +** Description This function calledin idle state to determine to send authentication +** complete or not. +*******************************************************************************/ +void smp_idle_terminate(tSMP_CB *p_cb, tSMP_INT_DATA *p_data) +{ + if (p_cb->flags & SMP_PAIR_FLAGS_WE_STARTED_DD) + { + SMP_TRACE_DEBUG("Pairing terminated at IDLE state."); + p_cb->status = SMP_FAIL; + smp_proc_pairing_cmpl(p_cb); + } +} + +/******************************************************************************* +** Function smp_fast_conn_param +** Description apply default connection parameter for pairing process +*******************************************************************************/ +void smp_fast_conn_param(tSMP_CB *p_cb, tSMP_INT_DATA *p_data) +{ + /* disable connection parameter update */ + L2CA_EnableUpdateBleConnParams(p_cb->pairing_bda, FALSE); +} + +/******************************************************************************* +** Function smp_both_have_public_keys +** Description The function is called when both local and peer public keys are +** saved. +** Actions: +** - invokes DHKey computation; +** - on slave side invokes sending local public key to the peer. +** - invokes SC phase 1 process. +*******************************************************************************/ +void smp_both_have_public_keys(tSMP_CB *p_cb, tSMP_INT_DATA *p_data) +{ + SMP_TRACE_DEBUG("%s",__func__); + + /* invokes DHKey computation */ + smp_compute_dhkey(p_cb); + + /* on slave side invokes sending local public key to the peer */ + if (p_cb->role == HCI_ROLE_SLAVE) + smp_send_pair_public_key(p_cb, NULL); + + smp_sm_event(p_cb, SMP_SC_DHKEY_CMPLT_EVT, NULL); +} + +/******************************************************************************* +** Function smp_start_secure_connection_phase1 +** Description The function starts Secure Connection phase1 i.e. invokes initialization of Secure Connection +** phase 1 parameters and starts building/sending to the peer +** messages appropriate for the role and association model. +*******************************************************************************/ +void smp_start_secure_connection_phase1(tSMP_CB *p_cb, tSMP_INT_DATA *p_data) +{ + SMP_TRACE_DEBUG("%s", __func__); + + if (p_cb->selected_association_model == SMP_MODEL_SEC_CONN_JUSTWORKS) + { + p_cb->sec_level = SMP_SEC_UNAUTHENTICATE; + SMP_TRACE_EVENT ("p_cb->sec_level =%d (SMP_SEC_UNAUTHENTICATE) ", p_cb->sec_level ); + } + else + { + p_cb->sec_level = SMP_SEC_AUTHENTICATED; + SMP_TRACE_EVENT ("p_cb->sec_level =%d (SMP_SEC_AUTHENTICATED) ", p_cb->sec_level ); + } + + switch(p_cb->selected_association_model) + { + case SMP_MODEL_SEC_CONN_JUSTWORKS: + case SMP_MODEL_SEC_CONN_NUM_COMP: + memset(p_cb->local_random, 0, BT_OCTET16_LEN); + smp_start_nonce_generation(p_cb); + break; + case SMP_MODEL_SEC_CONN_PASSKEY_ENT: + /* user has to provide passkey */ + p_cb->cb_evt = SMP_PASSKEY_REQ_EVT; + smp_sm_event(p_cb, SMP_TK_REQ_EVT, NULL); + break; + case SMP_MODEL_SEC_CONN_PASSKEY_DISP: + /* passkey has to be provided to user */ + SMP_TRACE_DEBUG("Need to generate SC Passkey"); + smp_generate_passkey(p_cb, NULL); + break; + case SMP_MODEL_SEC_CONN_OOB: + /* use the available OOB information */ + smp_process_secure_connection_oob_data(p_cb, NULL); + break; + default: + SMP_TRACE_ERROR ("Association Model = %d is not used in LE SC", + p_cb->selected_association_model); + break; + } +} + +/******************************************************************************* +** Function smp_process_local_nonce +** Description The function processes new local nonce. +** +** Note It is supposed to be called in SC phase1. +*******************************************************************************/ +void smp_process_local_nonce(tSMP_CB *p_cb, tSMP_INT_DATA *p_data) +{ + SMP_TRACE_DEBUG("%s", __func__); + + switch(p_cb->selected_association_model) + { + case SMP_MODEL_SEC_CONN_JUSTWORKS: + case SMP_MODEL_SEC_CONN_NUM_COMP: + if (p_cb->role == HCI_ROLE_SLAVE) + { + /* slave calculates and sends local commitment */ + smp_calculate_local_commitment(p_cb); + smp_send_commitment(p_cb, NULL); + /* slave has to wait for peer nonce */ + smp_set_state(SMP_STATE_WAIT_NONCE); + } + else /* i.e. master */ + { + if (p_cb->flags & SMP_PAIR_FLAG_HAVE_PEER_COMM) + { + /* slave commitment is already received, send local nonce, wait for remote nonce*/ + SMP_TRACE_DEBUG("master in assoc mode = %d \ + already rcvd slave commitment - race condition", + p_cb->selected_association_model); + p_cb->flags &= ~SMP_PAIR_FLAG_HAVE_PEER_COMM; + smp_send_rand(p_cb, NULL); + smp_set_state(SMP_STATE_WAIT_NONCE); + } + } + break; + case SMP_MODEL_SEC_CONN_PASSKEY_ENT: + case SMP_MODEL_SEC_CONN_PASSKEY_DISP: + smp_calculate_local_commitment(p_cb); + + if (p_cb->role == HCI_ROLE_MASTER) + { + smp_send_commitment(p_cb, NULL); + } + else /* slave */ + { + if (p_cb->flags & SMP_PAIR_FLAG_HAVE_PEER_COMM) + { + /* master commitment is already received */ + smp_send_commitment(p_cb, NULL); + smp_set_state(SMP_STATE_WAIT_NONCE); + } + } + break; + case SMP_MODEL_SEC_CONN_OOB: + if (p_cb->role == HCI_ROLE_MASTER) + { + smp_send_rand(p_cb, NULL); + } + + smp_set_state(SMP_STATE_WAIT_NONCE); + break; + default: + SMP_TRACE_ERROR ("Association Model = %d is not used in LE SC", + p_cb->selected_association_model); + break; + } +} + +/******************************************************************************* +** Function smp_process_peer_nonce +** Description The function processes newly received and saved in CB peer nonce. +** The actions depend on the selected association model and the role. +** +** Note It is supposed to be called in SC phase1. +*******************************************************************************/ +void smp_process_peer_nonce(tSMP_CB *p_cb, tSMP_INT_DATA *p_data) +{ + UINT8 reason; + + SMP_TRACE_DEBUG("%s start ", __func__); + + switch(p_cb->selected_association_model) + { + case SMP_MODEL_SEC_CONN_JUSTWORKS: + case SMP_MODEL_SEC_CONN_NUM_COMP: + /* in these models only master receives commitment */ + if (p_cb->role == HCI_ROLE_MASTER) + { + if (!smp_check_commitment(p_cb)) + { + reason = p_cb->failure = SMP_CONFIRM_VALUE_ERR; + smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &reason); + break; + } + } + else + { + /* slave sends local nonce */ + smp_send_rand(p_cb, NULL); + } + + if(p_cb->selected_association_model == SMP_MODEL_SEC_CONN_JUSTWORKS) + { + /* go directly to phase 2 */ + smp_sm_event(p_cb, SMP_SC_PHASE1_CMPLT_EVT, NULL); + } + else /* numeric comparison */ + { + smp_set_state(SMP_STATE_WAIT_NONCE); + smp_sm_event(p_cb, SMP_SC_CALC_NC_EVT, NULL); + } + break; + case SMP_MODEL_SEC_CONN_PASSKEY_ENT: + case SMP_MODEL_SEC_CONN_PASSKEY_DISP: + if (!smp_check_commitment(p_cb)) + { + reason = p_cb->failure = SMP_CONFIRM_VALUE_ERR; + smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &reason); + break; + } + + if (p_cb->role == HCI_ROLE_SLAVE) + { + smp_send_rand(p_cb, NULL); + } + + if (++p_cb->round < 20) + { + smp_set_state(SMP_STATE_SEC_CONN_PHS1_START); + p_cb->flags &= ~SMP_PAIR_FLAG_HAVE_PEER_COMM; + smp_start_nonce_generation(p_cb); + break; + } + + smp_sm_event(p_cb, SMP_SC_PHASE1_CMPLT_EVT, NULL); + break; + case SMP_MODEL_SEC_CONN_OOB: + if (p_cb->role == HCI_ROLE_SLAVE) + { + smp_send_rand(p_cb, NULL); + } + + smp_sm_event(p_cb, SMP_SC_PHASE1_CMPLT_EVT, NULL); + break; + default: + SMP_TRACE_ERROR ("Association Model = %d is not used in LE SC", + p_cb->selected_association_model); + break; + } + + SMP_TRACE_DEBUG("%s end ",__FUNCTION__); +} + +/******************************************************************************* +** Function smp_match_dhkey_checks +** Description checks if the calculated peer DHKey Check value is the same as +** received from the peer DHKey check value. +*******************************************************************************/ +void smp_match_dhkey_checks(tSMP_CB *p_cb, tSMP_INT_DATA *p_data) +{ + UINT8 reason = SMP_DHKEY_CHK_FAIL; + + SMP_TRACE_DEBUG("%s", __func__); + + if (memcmp(p_data->key.p_data, p_cb->remote_dhkey_check, BT_OCTET16_LEN)) + { + SMP_TRACE_WARNING ("dhkey chcks do no match"); + p_cb->failure = reason; + smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &reason); + return; + } + + SMP_TRACE_EVENT ("dhkey chcks match"); + + /* compare the max encryption key size, and save the smaller one for the link */ + if (p_cb->peer_enc_size < p_cb->loc_enc_size) + p_cb->loc_enc_size = p_cb->peer_enc_size; + + if (p_cb->role == HCI_ROLE_SLAVE) + { + smp_sm_event(p_cb, SMP_PAIR_DHKEY_CHCK_EVT, NULL); + } + else + { + /* master device always use received i/r key as keys to distribute */ + p_cb->local_i_key = p_cb->peer_i_key; + p_cb->local_r_key = p_cb->peer_r_key; + smp_sm_event(p_cb, SMP_ENC_REQ_EVT, NULL); + } +} + +/******************************************************************************* +** Function smp_move_to_secure_connections_phase2 +** Description Signal State Machine to start SC phase 2 initialization (to +** compute local DHKey Check value). +** +** Note SM is supposed to be in the state SMP_STATE_SEC_CONN_PHS2_START. +*******************************************************************************/ +void smp_move_to_secure_connections_phase2(tSMP_CB *p_cb, tSMP_INT_DATA *p_data) +{ + SMP_TRACE_DEBUG("%s",__func__); + smp_sm_event(p_cb, SMP_SC_PHASE1_CMPLT_EVT, NULL); +} + +/******************************************************************************* +** Function smp_phase_2_dhkey_checks_are_present +** Description generates event if dhkey check from the peer is already received. +** +** Note It is supposed to be used on slave to prevent race condition. +** It is supposed to be called after slave dhkey check is calculated. +*******************************************************************************/ +void smp_phase_2_dhkey_checks_are_present(tSMP_CB *p_cb, tSMP_INT_DATA *p_data) +{ + SMP_TRACE_DEBUG("%s",__func__); + + if (p_cb->flags & SMP_PAIR_FLAG_HAVE_PEER_DHK_CHK) + smp_sm_event(p_cb, SMP_SC_2_DHCK_CHKS_PRES_EVT, NULL); +} + +/******************************************************************************* +** Function smp_wait_for_both_public_keys +** Description generates SMP_BOTH_PUBL_KEYS_RCVD_EVT event when both local and master +** public keys are available. +** +** Note on the slave it is used to prevent race condition. +** +*******************************************************************************/ +void smp_wait_for_both_public_keys(tSMP_CB *p_cb, tSMP_INT_DATA *p_data) +{ + SMP_TRACE_DEBUG("%s",__func__); + + if ((p_cb->flags & SMP_PAIR_FLAG_HAVE_PEER_PUBL_KEY) && + (p_cb->flags & SMP_PAIR_FLAG_HAVE_LOCAL_PUBL_KEY)) + { + if ((p_cb->role == HCI_ROLE_SLAVE) && + ((p_cb->req_oob_type == SMP_OOB_LOCAL) || (p_cb->req_oob_type == SMP_OOB_BOTH))) + { + smp_set_state(SMP_STATE_PUBLIC_KEY_EXCH); + } + smp_sm_event(p_cb, SMP_BOTH_PUBL_KEYS_RCVD_EVT, NULL); + } +} + +/******************************************************************************* +** Function smp_start_passkey_verification +** Description Starts SC passkey entry verification. +*******************************************************************************/ +void smp_start_passkey_verification(tSMP_CB *p_cb, tSMP_INT_DATA *p_data) +{ + UINT8 *p = NULL; + + SMP_TRACE_DEBUG("%s", __func__); + p = p_cb->local_random; + UINT32_TO_STREAM(p, p_data->passkey); + + p = p_cb->peer_random; + UINT32_TO_STREAM(p, p_data->passkey); + + p_cb->round = 0; + smp_start_nonce_generation(p_cb); +} + +/******************************************************************************* +** Function smp_process_secure_connection_oob_data +** Description Processes local/peer SC OOB data received from somewhere. +*******************************************************************************/ +void smp_process_secure_connection_oob_data(tSMP_CB *p_cb, tSMP_INT_DATA *p_data) +{ + SMP_TRACE_DEBUG("%s", __func__); + + tSMP_SC_OOB_DATA *p_sc_oob_data = &p_cb->sc_oob_data; + if (p_sc_oob_data->loc_oob_data.present) + { + memcpy(p_cb->local_random, p_sc_oob_data->loc_oob_data.randomizer, + sizeof(p_cb->local_random)); + } + else + { + SMP_TRACE_EVENT ("local OOB randomizer is absent"); + memset(p_cb->local_random, 0, sizeof (p_cb->local_random)); + } + + if (!p_sc_oob_data->peer_oob_data.present) + { + SMP_TRACE_EVENT ("peer OOB data is absent"); + memset(p_cb->peer_random, 0, sizeof (p_cb->peer_random)); + } + else + { + memcpy(p_cb->peer_random, p_sc_oob_data->peer_oob_data.randomizer, + sizeof(p_cb->peer_random)); + memcpy(p_cb->remote_commitment, p_sc_oob_data->peer_oob_data.commitment, + sizeof(p_cb->remote_commitment)); + + UINT8 reason = SMP_CONFIRM_VALUE_ERR; + /* check commitment */ + if (!smp_check_commitment(p_cb)) + { + p_cb->failure = reason; + smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &reason); + return; + } + + if (p_cb->peer_oob_flag != SMP_OOB_PRESENT) + { + /* the peer doesn't have local randomiser */ + SMP_TRACE_EVENT ("peer didn't receive local OOB data, set local randomizer to 0"); + memset(p_cb->local_random, 0, sizeof (p_cb->local_random)); + } + } + + print128(p_cb->local_random, (const UINT8 *)"local OOB randomizer"); + print128(p_cb->peer_random, (const UINT8 *)"peer OOB randomizer"); + smp_start_nonce_generation(p_cb); +} + +/******************************************************************************* +** Function smp_set_local_oob_keys +** Description Saves calculated private/public keys in sc_oob_data.loc_oob_data, +** starts nonce generation +** (to be saved in sc_oob_data.loc_oob_data.randomizer). +*******************************************************************************/ +void smp_set_local_oob_keys(tSMP_CB *p_cb, tSMP_INT_DATA *p_data) +{ + SMP_TRACE_DEBUG("%s", __func__); + + memcpy(p_cb->sc_oob_data.loc_oob_data.private_key_used, p_cb->private_key, + BT_OCTET32_LEN); + p_cb->sc_oob_data.loc_oob_data.publ_key_used = p_cb->loc_publ_key; + smp_start_nonce_generation(p_cb); +} + +/******************************************************************************* +** Function smp_set_local_oob_random_commitment +** Description Saves calculated randomizer and commitment in sc_oob_data.loc_oob_data, +** passes sc_oob_data.loc_oob_data up for safekeeping. +*******************************************************************************/ +void smp_set_local_oob_random_commitment(tSMP_CB *p_cb, tSMP_INT_DATA *p_data) +{ + SMP_TRACE_DEBUG("%s", __func__); + memcpy(p_cb->sc_oob_data.loc_oob_data.randomizer, p_cb->rand, + BT_OCTET16_LEN); + + smp_calculate_f4(p_cb->sc_oob_data.loc_oob_data.publ_key_used.x, + p_cb->sc_oob_data.loc_oob_data.publ_key_used.x, + p_cb->sc_oob_data.loc_oob_data.randomizer, 0, + p_cb->sc_oob_data.loc_oob_data.commitment); + +#if SMP_DEBUG == TRUE + UINT8 *p_print = NULL; + SMP_TRACE_DEBUG("local SC OOB data set:"); + p_print = (UINT8*) &p_cb->sc_oob_data.loc_oob_data.addr_sent_to; + smp_debug_print_nbyte_little_endian (p_print, (const UINT8 *)"addr_sent_to", + sizeof(tBLE_BD_ADDR)); + p_print = (UINT8*) &p_cb->sc_oob_data.loc_oob_data.private_key_used; + smp_debug_print_nbyte_little_endian (p_print, (const UINT8 *)"private_key_used", + BT_OCTET32_LEN); + p_print = (UINT8*) &p_cb->sc_oob_data.loc_oob_data.publ_key_used.x; + smp_debug_print_nbyte_little_endian (p_print, (const UINT8 *)"publ_key_used.x", + BT_OCTET32_LEN); + p_print = (UINT8*) &p_cb->sc_oob_data.loc_oob_data.publ_key_used.y; + smp_debug_print_nbyte_little_endian (p_print, (const UINT8 *)"publ_key_used.y", + BT_OCTET32_LEN); + p_print = (UINT8*) &p_cb->sc_oob_data.loc_oob_data.randomizer; + smp_debug_print_nbyte_little_endian (p_print, (const UINT8 *)"randomizer", + BT_OCTET16_LEN); + p_print = (UINT8*) &p_cb->sc_oob_data.loc_oob_data.commitment; + smp_debug_print_nbyte_little_endian (p_print,(const UINT8 *) "commitment", + BT_OCTET16_LEN); + SMP_TRACE_DEBUG(""); +#endif + + /* pass created OOB data up */ + p_cb->cb_evt = SMP_SC_LOC_OOB_DATA_UP_EVT; + smp_send_app_cback(p_cb, NULL); + + smp_cb_cleanup(p_cb); +} + +/******************************************************************************* +** +** Function smp_link_encrypted +** +** Description This function is called when link is encrypted and notified to +** slave device. Proceed to to send LTK, DIV and ER to master if +** bonding the devices. +** +** +** Returns void +** +*******************************************************************************/ +void smp_link_encrypted(BD_ADDR bda, UINT8 encr_enable) +{ + tSMP_CB *p_cb = &smp_cb; + + SMP_TRACE_DEBUG("%s encr_enable=%d", __func__, encr_enable); + + if (memcmp(&smp_cb.pairing_bda[0], bda, BD_ADDR_LEN) == 0) + { + /* encryption completed with STK, remmeber the key size now, could be overwite + * when key exchange happens */ + if (p_cb->loc_enc_size != 0 && encr_enable) + { + /* update the link encryption key size if a SMP pairing just performed */ + btm_ble_update_sec_key_size(bda, p_cb->loc_enc_size); + } + + smp_sm_event(&smp_cb, SMP_ENCRYPTED_EVT, &encr_enable); + } +} + +/******************************************************************************* +** +** Function smp_proc_ltk_request +** +** Description This function is called when LTK request is received from +** controller. +** +** Returns void +** +*******************************************************************************/ +BOOLEAN smp_proc_ltk_request(BD_ADDR bda) +{ + SMP_TRACE_DEBUG("%s state = %d", __func__, smp_cb.state); + BOOLEAN match = FALSE; + + if (!memcmp(bda, smp_cb.pairing_bda, BD_ADDR_LEN)) + { + match = TRUE; + } else { + BD_ADDR dummy_bda = {0}; + tBTM_SEC_DEV_REC *p_dev_rec = btm_find_dev(bda); + if (p_dev_rec != NULL && + 0 == memcmp(p_dev_rec->ble.pseudo_addr, smp_cb.pairing_bda, BD_ADDR_LEN) && + 0 != memcmp(p_dev_rec->ble.pseudo_addr, dummy_bda, BD_ADDR_LEN)) + { + match = TRUE; + } + } + + if (match && smp_cb.state == SMP_STATE_ENCRYPTION_PENDING) + { + smp_sm_event(&smp_cb, SMP_ENC_REQ_EVT, NULL); + return TRUE; + } + + return FALSE; +} + +/******************************************************************************* +** +** Function smp_process_secure_connection_long_term_key +** +** Description This function is called to process SC LTK. +** SC LTK is calculated and used instead of STK. +** Here SC LTK is saved in BLE DB. +** +** Returns void +** +*******************************************************************************/ +void smp_process_secure_connection_long_term_key(void) +{ + tSMP_CB *p_cb = &smp_cb; + + SMP_TRACE_DEBUG("%s", __func__); + smp_save_secure_connections_long_term_key(p_cb); + + smp_update_key_mask (p_cb, SMP_SEC_KEY_TYPE_ENC, FALSE); + smp_key_distribution(p_cb, NULL); +} + +/******************************************************************************* +** +** Function smp_set_derive_link_key +** +** Description This function is called to set flag that indicates that +** BR/EDR LK has to be derived from LTK after all keys are +** distributed. +** +** Returns void +** +*******************************************************************************/ +void smp_set_derive_link_key(tSMP_CB *p_cb, tSMP_INT_DATA *p_data) +{ + SMP_TRACE_DEBUG ("%s", __func__); + p_cb->derive_lk = TRUE; + smp_update_key_mask (p_cb, SMP_SEC_KEY_TYPE_LK, FALSE); + smp_key_distribution(p_cb, NULL); +} + +/******************************************************************************* +** +** Function smp_derive_link_key_from_long_term_key +** +** Description This function is called to derive BR/EDR LK from LTK. +** +** Returns void +** +*******************************************************************************/ +void smp_derive_link_key_from_long_term_key(tSMP_CB *p_cb, tSMP_INT_DATA *p_data) +{ + tSMP_STATUS status = SMP_PAIR_FAIL_UNKNOWN; + + SMP_TRACE_DEBUG("%s", __func__); + if (!smp_calculate_link_key_from_long_term_key(p_cb)) + { + SMP_TRACE_ERROR("%s failed", __FUNCTION__); + smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &status); + return; + } +} + +/******************************************************************************* +** +** Function smp_br_process_link_key +** +** Description This function is called to process BR/EDR LK: +** - to derive SMP LTK from BR/EDR LK; +*8 - to save SMP LTK. +** +** Returns void +** +*******************************************************************************/ +void smp_br_process_link_key(tSMP_CB *p_cb, tSMP_INT_DATA *p_data) +{ + tSMP_STATUS status = SMP_PAIR_FAIL_UNKNOWN; + + SMP_TRACE_DEBUG("%s", __func__); + if (!smp_calculate_long_term_key_from_link_key(p_cb)) + { + SMP_TRACE_ERROR ("%s failed",__FUNCTION__); + smp_sm_event(p_cb, SMP_BR_AUTH_CMPL_EVT, &status); + return; + } + + SMP_TRACE_DEBUG("%s: LTK derivation from LK successfully completed", __FUNCTION__); + smp_save_secure_connections_long_term_key(p_cb); + smp_update_key_mask (p_cb, SMP_SEC_KEY_TYPE_ENC, FALSE); + smp_br_select_next_key(p_cb, NULL); +} + +/******************************************************************************* +** Function smp_key_distribution_by_transport +** Description depending on the transport used at the moment calls either +** smp_key_distribution(...) or smp_br_key_distribution(...). +*******************************************************************************/ +void smp_key_distribution_by_transport(tSMP_CB *p_cb, tSMP_INT_DATA *p_data) +{ + SMP_TRACE_DEBUG("%s", __func__); + if (p_cb->smp_over_br) + { + smp_br_select_next_key(p_cb, NULL); + } + else + { + smp_key_distribution(p_cb, NULL); + } +} + +/******************************************************************************* +** Function smp_br_pairing_complete +** Description This function is called to send the pairing complete callback +** and remove the connection if needed. +*******************************************************************************/ +void smp_br_pairing_complete(tSMP_CB *p_cb, tSMP_INT_DATA *p_data) +{ + SMP_TRACE_DEBUG("%s", __func__); + + if (p_cb->total_tx_unacked == 0) + { + /* process the pairing complete */ + smp_proc_pairing_cmpl(p_cb); + } +} + +#endif diff --git a/components/bt/bluedroid/stack/smp/smp_api.c b/components/bt/bluedroid/stack/smp/smp_api.c new file mode 100755 index 0000000000..a96e653df3 --- /dev/null +++ b/components/bt/bluedroid/stack/smp/smp_api.c @@ -0,0 +1,607 @@ +/****************************************************************************** + * + * Copyright (C) 2008-2012 Broadcom Corporation + * + * 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 implementation of the SMP interface used by + * applications that can run over an SMP. + * + ******************************************************************************/ +#include + +#include "bt_target.h" +//#include "bt_utils.h" +#if SMP_INCLUDED == TRUE + #include "smp_int.h" + #include "smp_api.h" + #include "l2cdefs.h" + #include "l2c_int.h" + #include "btm_int.h" + #include "hcimsgs.h" + + #include "btu.h" + #include "p_256_ecc_pp.h" + +/******************************************************************************* +** +** Function SMP_Init +** +** Description This function initializes the SMP unit. +** +** Returns void +** +*******************************************************************************/ +void SMP_Init(void) +{ + memset(&smp_cb, 0, sizeof(tSMP_CB)); + +#if defined(SMP_INITIAL_TRACE_LEVEL) + smp_cb.trace_level = SMP_INITIAL_TRACE_LEVEL; +#else + smp_cb.trace_level = BT_TRACE_LEVEL_NONE; /* No traces */ +#endif + SMP_TRACE_EVENT ("%s", __FUNCTION__); + + smp_l2cap_if_init(); + /* initialization of P-256 parameters */ + p_256_init_curve(KEY_LENGTH_DWORDS_P256); +} + + +/******************************************************************************* +** +** Function SMP_SetTraceLevel +** +** Description This function sets the trace level for SMP. If called with +** a value of 0xFF, it simply returns the current trace level. +** +** Input Parameters: +** level: The level to set the GATT tracing to: +** 0xff-returns the current setting. +** 0-turns off tracing. +** >= 1-Errors. +** >= 2-Warnings. +** >= 3-APIs. +** >= 4-Events. +** >= 5-Debug. +** +** Returns The new or current trace level +** +*******************************************************************************/ +extern UINT8 SMP_SetTraceLevel (UINT8 new_level) +{ + if (new_level != 0xFF) + smp_cb.trace_level = new_level; + + return(smp_cb.trace_level); +} + + +/******************************************************************************* +** +** Function SMP_Register +** +** Description This function register for the SMP services callback. +** +** Returns void +** +*******************************************************************************/ +BOOLEAN SMP_Register (tSMP_CALLBACK *p_cback) +{ + SMP_TRACE_EVENT ("SMP_Register state=%d", smp_cb.state); + + if (smp_cb.p_callback != NULL) + { + SMP_TRACE_ERROR ("SMP_Register: duplicate registration, overwrite it"); + } + smp_cb.p_callback = p_cback; + + return(TRUE); + +} + +/******************************************************************************* +** +** Function SMP_Pair +** +** Description This function call to perform a SMP pairing with peer device. +** Device support one SMP pairing at one time. +** +** Parameters bd_addr - peer device bd address. +** +** Returns None +** +*******************************************************************************/ +tSMP_STATUS SMP_Pair (BD_ADDR bd_addr) +{ + tSMP_CB *p_cb = &smp_cb; + UINT8 status = SMP_PAIR_INTERNAL_ERR; + + SMP_TRACE_EVENT ("%s state=%d br_state=%d flag=0x%x ", + __FUNCTION__, p_cb->state, p_cb->br_state, p_cb->flags); + if (p_cb->state != SMP_STATE_IDLE || p_cb->flags & SMP_PAIR_FLAGS_WE_STARTED_DD || + p_cb->smp_over_br) + { + /* pending security on going, reject this one */ + return SMP_BUSY; + } + else + { + p_cb->flags = SMP_PAIR_FLAGS_WE_STARTED_DD; + + memcpy (p_cb->pairing_bda, bd_addr, BD_ADDR_LEN); + + if (!L2CA_ConnectFixedChnl (L2CAP_SMP_CID, bd_addr)) + { + SMP_TRACE_ERROR("%s: L2C connect fixed channel failed.", __FUNCTION__); + smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &status); + return status; + } + + return SMP_STARTED; + } +} + +/******************************************************************************* +** +** Function SMP_BR_PairWith +** +** Description This function is called to start a SMP pairing over BR/EDR. +** Device support one SMP pairing at one time. +** +** Parameters bd_addr - peer device bd address. +** +** Returns SMP_STARTED if pairing started, otherwise reason for failure. +** +*******************************************************************************/ +tSMP_STATUS SMP_BR_PairWith (BD_ADDR bd_addr) +{ + tSMP_CB *p_cb = &smp_cb; + UINT8 status = SMP_PAIR_INTERNAL_ERR; + + SMP_TRACE_EVENT ("%s state=%d br_state=%d flag=0x%x ", + __func__, p_cb->state, p_cb->br_state, p_cb->flags); + + if (p_cb->state != SMP_STATE_IDLE || + p_cb->smp_over_br || + p_cb->flags & SMP_PAIR_FLAGS_WE_STARTED_DD) + { + /* pending security on going, reject this one */ + return SMP_BUSY; + } + + p_cb->role = HCI_ROLE_MASTER; + p_cb->flags = SMP_PAIR_FLAGS_WE_STARTED_DD; + p_cb->smp_over_br = TRUE; + + memcpy (p_cb->pairing_bda, bd_addr, BD_ADDR_LEN); + + if (!L2CA_ConnectFixedChnl (L2CAP_SMP_BR_CID, bd_addr)) + { + SMP_TRACE_ERROR("%s: L2C connect fixed channel failed.",__FUNCTION__); + smp_br_state_machine_event(p_cb, SMP_BR_AUTH_CMPL_EVT, &status); + return status; + } + + return SMP_STARTED; +} + +/******************************************************************************* +** +** Function SMP_PairCancel +** +** Description This function call to cancel a SMP pairing with peer device. +** +** Parameters bd_addr - peer device bd address. +** +** Returns TRUE - Pairining is cancelled +** +*******************************************************************************/ +BOOLEAN SMP_PairCancel (BD_ADDR bd_addr) +{ + tSMP_CB *p_cb = &smp_cb; + UINT8 err_code = SMP_PAIR_FAIL_UNKNOWN; + BOOLEAN status = FALSE; + + BTM_TRACE_EVENT ("SMP_CancelPair state=%d flag=0x%x ", p_cb->state, p_cb->flags); + if ( (p_cb->state != SMP_STATE_IDLE) && + (!memcmp (p_cb->pairing_bda, bd_addr, BD_ADDR_LEN)) ) + { + p_cb->is_pair_cancel = TRUE; + SMP_TRACE_DEBUG("Cancel Pairing: set fail reason Unknown"); + smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &err_code); + status = TRUE; + } + + return status; +} +/******************************************************************************* +** +** Function SMP_SecurityGrant +** +** Description This function is called to grant security process. +** +** Parameters bd_addr - peer device bd address. +** res - result of the operation SMP_SUCCESS if success. +** Otherwise, SMP_REPEATED_ATTEMPTS is too many attempts. +** +** Returns None +** +*******************************************************************************/ +void SMP_SecurityGrant(BD_ADDR bd_addr, UINT8 res) +{ + SMP_TRACE_EVENT ("SMP_SecurityGrant "); + + if (smp_cb.smp_over_br) + { + if (smp_cb.br_state != SMP_BR_STATE_WAIT_APP_RSP || + smp_cb.cb_evt != SMP_SEC_REQUEST_EVT || + memcmp (smp_cb.pairing_bda, bd_addr, BD_ADDR_LEN)) + { + return; + } + + /* clear the SMP_SEC_REQUEST_EVT event after get grant */ + /* avoid generating duplicate pair request */ + smp_cb.cb_evt = 0; + smp_br_state_machine_event(&smp_cb, SMP_BR_API_SEC_GRANT_EVT, &res); + return; + } + + if (smp_cb.state != SMP_STATE_WAIT_APP_RSP || + smp_cb.cb_evt != SMP_SEC_REQUEST_EVT || + memcmp (smp_cb.pairing_bda, bd_addr, BD_ADDR_LEN)) + return; + /* clear the SMP_SEC_REQUEST_EVT event after get grant */ + /* avoid generate duplicate pair request */ + smp_cb.cb_evt = 0; + smp_sm_event(&smp_cb, SMP_API_SEC_GRANT_EVT, &res); +} + +/******************************************************************************* +** +** Function SMP_PasskeyReply +** +** Description This function is called after Security Manager submitted +** passkey request to the application. +** +** Parameters: bd_addr - Address of the device for which passkey was requested +** res - result of the operation SMP_SUCCESS if success +** passkey - numeric value in the range of +** BTM_MIN_PASSKEY_VAL(0) - BTM_MAX_PASSKEY_VAL(999999(0xF423F)). +** +*******************************************************************************/ +void SMP_PasskeyReply (BD_ADDR bd_addr, UINT8 res, UINT32 passkey) +{ + tSMP_CB *p_cb = & smp_cb; + UINT8 failure = SMP_PASSKEY_ENTRY_FAIL; + + SMP_TRACE_EVENT ("SMP_PasskeyReply: Key: %d Result:%d", + passkey, res); + + /* If timeout already expired or has been canceled, ignore the reply */ + if (p_cb->cb_evt != SMP_PASSKEY_REQ_EVT) + { + SMP_TRACE_WARNING ("SMP_PasskeyReply() - Wrong State: %d", p_cb->state); + return; + } + + if (memcmp (bd_addr, p_cb->pairing_bda, BD_ADDR_LEN) != 0) + { + SMP_TRACE_ERROR ("SMP_PasskeyReply() - Wrong BD Addr"); + return; + } + + if (btm_find_dev (bd_addr) == NULL) + { + SMP_TRACE_ERROR ("SMP_PasskeyReply() - no dev CB"); + return; + } + + if (passkey > BTM_MAX_PASSKEY_VAL || res != SMP_SUCCESS) + { + SMP_TRACE_WARNING ("SMP_PasskeyReply() - Wrong key len: %d or passkey entry fail", passkey); + /* send pairing failure */ + smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &failure); + + } + else if (p_cb->selected_association_model == SMP_MODEL_SEC_CONN_PASSKEY_ENT) + { + smp_sm_event(&smp_cb, SMP_SC_KEY_READY_EVT, &passkey); + } + else + { + smp_convert_string_to_tk(p_cb->tk, passkey); + } + + return; +} + +/******************************************************************************* +** +** Function SMP_ConfirmReply +** +** Description This function is called after Security Manager submitted +** numeric comparison request to the application. +** +** Parameters: bd_addr - Address of the device with which numeric +** comparison was requested +** res - comparison result SMP_SUCCESS if success +** +*******************************************************************************/ +void SMP_ConfirmReply (BD_ADDR bd_addr, UINT8 res) +{ + tSMP_CB *p_cb = & smp_cb; + UINT8 failure = SMP_NUMERIC_COMPAR_FAIL; + + SMP_TRACE_EVENT ("%s: Result:%d", __FUNCTION__, res); + + /* If timeout already expired or has been canceled, ignore the reply */ + if (p_cb->cb_evt != SMP_NC_REQ_EVT) + { + SMP_TRACE_WARNING ("%s() - Wrong State: %d", __FUNCTION__,p_cb->state); + return; + } + + if (memcmp (bd_addr, p_cb->pairing_bda, BD_ADDR_LEN) != 0) + { + SMP_TRACE_ERROR ("%s() - Wrong BD Addr",__FUNCTION__); + return; + } + + if (btm_find_dev (bd_addr) == NULL) + { + SMP_TRACE_ERROR ("%s() - no dev CB",__FUNCTION__); + return; + } + + if (res != SMP_SUCCESS) + { + SMP_TRACE_WARNING ("%s() - Numeric Comparison fails",__FUNCTION__); + /* send pairing failure */ + smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &failure); + } + else + { + smp_sm_event(p_cb, SMP_SC_NC_OK_EVT, NULL); + } +} + +/******************************************************************************* +** +** Function SMP_OobDataReply +** +** Description This function is called to provide the OOB data for +** SMP in response to SMP_OOB_REQ_EVT +** +** Parameters: bd_addr - Address of the peer device +** res - result of the operation SMP_SUCCESS if success +** p_data - simple pairing Randomizer C. +** +*******************************************************************************/ +void SMP_OobDataReply(BD_ADDR bd_addr, tSMP_STATUS res, UINT8 len, UINT8 *p_data) +{ + tSMP_CB *p_cb = & smp_cb; + UINT8 failure = SMP_OOB_FAIL; + tSMP_KEY key; + + SMP_TRACE_EVENT ("%s State: %d res:%d", __FUNCTION__, smp_cb.state, res); + + /* If timeout already expired or has been canceled, ignore the reply */ + if (p_cb->state != SMP_STATE_WAIT_APP_RSP || p_cb->cb_evt != SMP_OOB_REQ_EVT) + return; + + if (res != SMP_SUCCESS || len == 0 || !p_data) + { + smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &failure); + } + else + { + if (len > BT_OCTET16_LEN) + len = BT_OCTET16_LEN; + + memcpy(p_cb->tk, p_data, len); + + key.key_type = SMP_KEY_TYPE_TK; + key.p_data = p_cb->tk; + + smp_sm_event(&smp_cb, SMP_KEY_READY_EVT, &key); + } +} + +/******************************************************************************* +** +** Function SMP_SecureConnectionOobDataReply +** +** Description This function is called to provide the SC OOB data for +** SMP in response to SMP_SC_OOB_REQ_EVT +** +** Parameters: p_data - pointer to the data +** +*******************************************************************************/ +void SMP_SecureConnectionOobDataReply(UINT8 *p_data) +{ + tSMP_CB *p_cb = &smp_cb; + + UINT8 failure = SMP_OOB_FAIL; + tSMP_SC_OOB_DATA *p_oob = (tSMP_SC_OOB_DATA *) p_data; + if (!p_oob) + { + SMP_TRACE_ERROR("%s received no data",__FUNCTION__); + smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &failure); + return; + } + + SMP_TRACE_EVENT ("%s req_oob_type: %d, loc_oob_data.present: %d, " + "peer_oob_data.present: %d", + __FUNCTION__, p_cb->req_oob_type, p_oob->loc_oob_data.present, + p_oob->peer_oob_data.present); + + if (p_cb->state != SMP_STATE_WAIT_APP_RSP || p_cb->cb_evt != SMP_SC_OOB_REQ_EVT) + return; + + BOOLEAN data_missing = FALSE; + switch (p_cb->req_oob_type) + { + case SMP_OOB_PEER: + if (!p_oob->peer_oob_data.present) + data_missing = TRUE; + break; + case SMP_OOB_LOCAL: + if (!p_oob->loc_oob_data.present) + data_missing = TRUE; + break; + case SMP_OOB_BOTH: + if (!p_oob->loc_oob_data.present || !p_oob->peer_oob_data.present) + data_missing = TRUE; + break; + default: + SMP_TRACE_EVENT ("Unexpected OOB data type requested. Fail OOB"); + data_missing = TRUE; + break; + } + + if (data_missing) + { + smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &failure); + return; + } + + p_cb->sc_oob_data = *p_oob; + + smp_sm_event(&smp_cb, SMP_SC_OOB_DATA_EVT, p_data); +} + +/******************************************************************************* +** +** Function SMP_Encrypt +** +** Description This function is called to encrypt the data with the specified +** key +** +** Parameters: key - Pointer to key key[0] conatins the MSB +** key_len - key length +** plain_text - Pointer to data to be encrypted +** plain_text[0] conatins the MSB +** pt_len - plain text length +** p_out - output of the encrypted texts +** +** Returns Boolean - request is successful +*******************************************************************************/ +BOOLEAN SMP_Encrypt (UINT8 *key, UINT8 key_len, + UINT8 *plain_text, UINT8 pt_len, + tSMP_ENC *p_out) + +{ + BOOLEAN status=FALSE; + status = smp_encrypt_data(key, key_len, plain_text, pt_len, p_out); + return status; +} + +/******************************************************************************* +** +** Function SMP_KeypressNotification +** +** Description This function is called to notify Security Manager about Keypress Notification. +** +** Parameters: bd_addr Address of the device to send keypress notification to +** value Keypress notification parameter value +** +*******************************************************************************/ +void SMP_KeypressNotification (BD_ADDR bd_addr, UINT8 value) +{ + tSMP_CB *p_cb = &smp_cb; + + SMP_TRACE_EVENT ("%s: Value: %d", __FUNCTION__,value); + + if (memcmp (bd_addr, p_cb->pairing_bda, BD_ADDR_LEN) != 0) + { + SMP_TRACE_ERROR ("%s() - Wrong BD Addr",__FUNCTION__); + return; + } + + if (btm_find_dev (bd_addr) == NULL) + { + SMP_TRACE_ERROR ("%s() - no dev CB",__FUNCTION__); + return; + } + + /* Keypress Notification is used by a device with KeyboardOnly IO capabilities */ + /* during the passkey entry protocol */ + if (p_cb->local_io_capability != SMP_IO_CAP_IN) + { + SMP_TRACE_ERROR ("%s() - wrong local IO capabilities %d", + __FUNCTION__, p_cb->local_io_capability); + return; + } + + if (p_cb->selected_association_model != SMP_MODEL_SEC_CONN_PASSKEY_ENT) + { + SMP_TRACE_ERROR ("%s() - wrong protocol %d", __FUNCTION__, + p_cb->selected_association_model); + return; + } + + smp_sm_event(p_cb, SMP_KEYPRESS_NOTIFICATION_EVENT, &value); +} + +/******************************************************************************* +** +** Function SMP_CreateLocalSecureConnectionsOobData +** +** Description This function is called to start creation of local SC OOB +** data set (tSMP_LOC_OOB_DATA). +** +** Parameters: bd_addr - Address of the device to send OOB data block to +** +** Returns Boolean - TRUE: creation of local SC OOB data set started. +*******************************************************************************/ +BOOLEAN SMP_CreateLocalSecureConnectionsOobData (tBLE_BD_ADDR *addr_to_send_to) +{ + tSMP_CB *p_cb = &smp_cb; + UINT8 *bd_addr; + + if (addr_to_send_to == NULL) + { + SMP_TRACE_ERROR ("%s addr_to_send_to is not provided",__FUNCTION__); + return FALSE; + } + + bd_addr = addr_to_send_to->bda; + + SMP_TRACE_EVENT ("%s addr type: %u, BDA: %08x%04x, state: %u, br_state: %u", + __FUNCTION__, addr_to_send_to->type, + (bd_addr[0]<<24)+(bd_addr[1]<<16)+(bd_addr[2]<<8) + bd_addr[3], + (bd_addr[4]<<8)+bd_addr[5], + p_cb->state, + p_cb->br_state); + + if ((p_cb->state != SMP_STATE_IDLE) || (p_cb->smp_over_br)) + { + SMP_TRACE_WARNING ("%s creation of local OOB data set "\ + "starts only in IDLE state",__FUNCTION__); + return FALSE; + } + + p_cb->sc_oob_data.loc_oob_data.addr_sent_to = *addr_to_send_to; + smp_sm_event(p_cb, SMP_CR_LOC_SC_OOB_DATA_EVT, NULL); + + return TRUE; +} + +#endif /* SMP_INCLUDED */ diff --git a/components/bt/bluedroid/stack/smp/smp_br_main.c b/components/bt/bluedroid/stack/smp/smp_br_main.c new file mode 100755 index 0000000000..11039ec206 --- /dev/null +++ b/components/bt/bluedroid/stack/smp/smp_br_main.c @@ -0,0 +1,399 @@ +/****************************************************************************** + * + * Copyright (C) 2014-2015 Broadcom Corporation + * + * 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. + * + ******************************************************************************/ + +#include "bt_target.h" + +#include +#include "smp_int.h" + +#if BLE_INCLUDED == TRUE + +const char *const smp_br_state_name [SMP_BR_STATE_MAX+1] = +{ + "SMP_BR_STATE_IDLE", + "SMP_BR_STATE_WAIT_APP_RSP", + "SMP_BR_STATE_PAIR_REQ_RSP", + "SMP_BR_STATE_BOND_PENDING", + "SMP_BR_STATE_OUT_OF_RANGE" +}; + +const char *const smp_br_event_name [SMP_BR_MAX_EVT] = +{ + "BR_PAIRING_REQ_EVT", + "BR_PAIRING_RSP_EVT", + "BR_CONFIRM_EVT", + "BR_RAND_EVT", + "BR_PAIRING_FAILED_EVT", + "BR_ENCRPTION_INFO_EVT", + "BR_MASTER_ID_EVT", + "BR_ID_INFO_EVT", + "BR_ID_ADDR_EVT", + "BR_SIGN_INFO_EVT", + "BR_SECURITY_REQ_EVT", + "BR_PAIR_PUBLIC_KEY_EVT", + "BR_PAIR_DHKEY_CHCK_EVT", + "BR_PAIR_KEYPR_NOTIF_EVT", + "BR_KEY_READY_EVT", + "BR_ENCRYPTED_EVT", + "BR_L2CAP_CONN_EVT", + "BR_L2CAP_DISCONN_EVT", + "BR_KEYS_RSP_EVT", + "BR_API_SEC_GRANT_EVT", + "BR_TK_REQ_EVT", + "BR_AUTH_CMPL_EVT", + "BR_ENC_REQ_EVT", + "BR_BOND_REQ_EVT", + "BR_DISCARD_SEC_REQ_EVT", + "BR_OUT_OF_RANGE_EVT" +}; + +const char *smp_get_br_event_name(tSMP_BR_EVENT event); +const char *smp_get_br_state_name(tSMP_BR_STATE state); + +#define SMP_BR_SM_IGNORE 0 +#define SMP_BR_NUM_ACTIONS 2 +#define SMP_BR_SME_NEXT_STATE 2 +#define SMP_BR_SM_NUM_COLS 3 +typedef const UINT8 (*tSMP_BR_SM_TBL)[SMP_BR_SM_NUM_COLS]; + +enum +{ + SMP_SEND_PAIR_REQ, + SMP_BR_SEND_PAIR_RSP, + SMP_SEND_PAIR_FAIL, + SMP_SEND_ID_INFO, + SMP_BR_PROC_PAIR_CMD, + SMP_PROC_PAIR_FAIL, + SMP_PROC_ID_INFO, + SMP_PROC_ID_ADDR, + SMP_PROC_SRK_INFO, + SMP_BR_PROC_SEC_GRANT, + SMP_BR_PROC_SL_KEYS_RSP, + SMP_BR_KEY_DISTRIBUTION, + SMP_BR_PAIRING_COMPLETE, + SMP_SEND_APP_CBACK, + SMP_BR_CHECK_AUTH_REQ, + SMP_PAIR_TERMINATE, + SMP_IDLE_TERMINATE, + SMP_BR_SM_NO_ACTION +}; + +static const tSMP_ACT smp_br_sm_action[] = +{ + smp_send_pair_req, + smp_br_send_pair_response, + smp_send_pair_fail, + smp_send_id_info, + smp_br_process_pairing_command, + smp_proc_pair_fail, + smp_proc_id_info, + smp_proc_id_addr, + smp_proc_srk_info, + smp_br_process_security_grant, + smp_br_process_slave_keys_response, + smp_br_select_next_key, + smp_br_pairing_complete, + smp_send_app_cback, + smp_br_check_authorization_request, + smp_pair_terminate, + smp_idle_terminate +}; + +static const UINT8 smp_br_all_table[][SMP_BR_SM_NUM_COLS] = +{ +/* Event Action Next State */ +/* BR_PAIRING_FAILED */ {SMP_PROC_PAIR_FAIL, SMP_BR_PAIRING_COMPLETE, SMP_BR_STATE_IDLE}, +/* BR_AUTH_CMPL */ {SMP_SEND_PAIR_FAIL, SMP_BR_PAIRING_COMPLETE, SMP_BR_STATE_IDLE}, +/* BR_L2CAP_DISCONN */ {SMP_PAIR_TERMINATE, SMP_BR_SM_NO_ACTION, SMP_BR_STATE_IDLE} +}; + +/************ SMP Master FSM State/Event Indirection Table **************/ +static const UINT8 smp_br_master_entry_map[][SMP_BR_STATE_MAX] = +{ +/* br_state name: Idle WaitApp Pair Bond + Rsp ReqRsp Pend */ +/* BR_PAIRING_REQ */ { 0, 0, 0, 0 }, +/* BR_PAIRING_RSP */ { 0, 0, 1, 0 }, +/* BR_CONFIRM */ { 0, 0, 0, 0 }, +/* BR_RAND */ { 0, 0, 0, 0 }, +/* BR_PAIRING_FAILED */ { 0, 0x81, 0x81, 0 }, +/* BR_ENCRPTION_INFO */ { 0, 0, 0, 0 }, +/* BR_MASTER_ID */ { 0, 0, 0, 0 }, +/* BR_ID_INFO */ { 0, 0, 0, 1 }, +/* BR_ID_ADDR */ { 0, 0, 0, 2 }, +/* BR_SIGN_INFO */ { 0, 0, 0, 3 }, +/* BR_SECURITY_REQ */ { 0, 0, 0, 0 }, +/* BR_PAIR_PUBLIC_KEY_EVT */ { 0, 0, 0, 0 }, +/* BR_PAIR_DHKEY_CHCK_EVT */ { 0, 0, 0, 0 }, +/* BR_PAIR_KEYPR_NOTIF_EVT */ { 0, 0, 0, 0 }, +/* BR_KEY_READY */ { 0, 0, 0, 0 }, +/* BR_ENCRYPTED */ { 0, 0, 0, 0 }, +/* BR_L2CAP_CONN */ { 1, 0, 0, 0 }, +/* BR_L2CAP_DISCONN */ { 2, 0x83, 0x83, 0x83 }, +/* BR_KEYS_RSP */ { 0, 1, 0, 0 }, +/* BR_API_SEC_GRANT */ { 0, 0, 0, 0 }, +/* BR_TK_REQ */ { 0, 0, 0, 0 }, +/* BR_AUTH_CMPL */ { 0, 0x82, 0x82, 0x82 }, +/* BR_ENC_REQ */ { 0, 0, 0, 0 }, +/* BR_BOND_REQ */ { 0, 0, 2, 0 }, +/* BR_DISCARD_SEC_REQ */ { 0, 0, 0, 0 } +}; + +static const UINT8 smp_br_master_idle_table[][SMP_BR_SM_NUM_COLS] = +{ +/* Event Action Next State */ +/* BR_L2CAP_CONN */ {SMP_SEND_APP_CBACK, SMP_BR_SM_NO_ACTION, SMP_BR_STATE_WAIT_APP_RSP}, +/* BR_L2CAP_DISCONN */ {SMP_IDLE_TERMINATE, SMP_BR_SM_NO_ACTION, SMP_BR_STATE_IDLE} +}; + +static const UINT8 smp_br_master_wait_appln_response_table[][SMP_BR_SM_NUM_COLS] = +{ +/* Event Action Next State */ +/* BR_KEYS_RSP */{SMP_SEND_PAIR_REQ, SMP_BR_SM_NO_ACTION, SMP_BR_STATE_PAIR_REQ_RSP} +}; + +static const UINT8 smp_br_master_pair_request_response_table [][SMP_BR_SM_NUM_COLS] = +{ +/* Event Action Next State */ +/* BR_PAIRING_RSP */ {SMP_BR_PROC_PAIR_CMD, SMP_BR_CHECK_AUTH_REQ, SMP_BR_STATE_PAIR_REQ_RSP}, +/* BR_BOND_REQ */ {SMP_BR_SM_NO_ACTION, SMP_BR_SM_NO_ACTION, SMP_BR_STATE_BOND_PENDING} +}; + +static const UINT8 smp_br_master_bond_pending_table[][SMP_BR_SM_NUM_COLS] = +{ +/* Event Action Next State */ +/* BR_ID_INFO */{SMP_PROC_ID_INFO, SMP_BR_SM_NO_ACTION, SMP_BR_STATE_BOND_PENDING}, +/* BR_ID_ADDR */{SMP_PROC_ID_ADDR, SMP_BR_SM_NO_ACTION, SMP_BR_STATE_BOND_PENDING}, +/* BR_SIGN_INFO */{SMP_PROC_SRK_INFO, SMP_BR_SM_NO_ACTION, SMP_BR_STATE_BOND_PENDING} +}; + +static const UINT8 smp_br_slave_entry_map[][SMP_BR_STATE_MAX] = +{ +/* br_state name: Idle WaitApp Pair Bond + Rsp ReqRsp Pend */ +/* BR_PAIRING_REQ */ { 1, 0, 0, 0 }, +/* BR_PAIRING_RSP */ { 0, 0, 0, 0 }, +/* BR_CONFIRM */ { 0, 0, 0, 0 }, +/* BR_RAND */ { 0, 0, 0, 0 }, +/* BR_PAIRING_FAILED */ { 0, 0x81, 0x81, 0x81 }, +/* BR_ENCRPTION_INFO */ { 0, 0, 0, 0 }, +/* BR_MASTER_ID */ { 0, 0, 0, 0 }, +/* BR_ID_INFO */ { 0, 0, 0, 1 }, +/* BR_ID_ADDR */ { 0, 0, 0, 2 }, +/* BR_SIGN_INFO */ { 0, 0, 0, 3 }, +/* BR_SECURITY_REQ */ { 0, 0, 0, 0 }, +/* BR_PAIR_PUBLIC_KEY_EVT */ { 0, 0, 0, 0 }, +/* BR_PAIR_DHKEY_CHCK_EVT */ { 0, 0, 0, 0 }, +/* BR_PAIR_KEYPR_NOTIF_EVT */ { 0, 0, 0, 0 }, +/* BR_KEY_READY */ { 0, 0, 0, 0 }, +/* BR_ENCRYPTED */ { 0, 0, 0, 0 }, +/* BR_L2CAP_CONN */ { 0, 0, 0, 0 }, +/* BR_L2CAP_DISCONN */ { 0, 0x83, 0x83, 0x83 }, +/* BR_KEYS_RSP */ { 0, 2, 0, 0 }, +/* BR_API_SEC_GRANT */ { 0, 1, 0, 0 }, +/* BR_TK_REQ */ { 0, 0, 0, 0 }, +/* BR_AUTH_CMPL */ { 0, 0x82, 0x82, 0x82 }, +/* BR_ENC_REQ */ { 0, 0, 0, 0 }, +/* BR_BOND_REQ */ { 0, 3, 0, 0 }, +/* BR_DISCARD_SEC_REQ */ { 0, 0, 0, 0 } +}; + +static const UINT8 smp_br_slave_idle_table[][SMP_BR_SM_NUM_COLS] = +{ +/* Event Action Next State */ +/* BR_PAIRING_REQ */ {SMP_BR_PROC_PAIR_CMD, SMP_SEND_APP_CBACK, SMP_BR_STATE_WAIT_APP_RSP} +}; + +static const UINT8 smp_br_slave_wait_appln_response_table [][SMP_BR_SM_NUM_COLS] = +{ +/* Event Action Next State */ +/* BR_API_SEC_GRANT */ {SMP_BR_PROC_SEC_GRANT, SMP_SEND_APP_CBACK, SMP_BR_STATE_WAIT_APP_RSP}, +/* BR_KEYS_RSP */{SMP_BR_PROC_SL_KEYS_RSP, SMP_BR_CHECK_AUTH_REQ,SMP_BR_STATE_WAIT_APP_RSP}, +/* BR_BOND_REQ */ {SMP_BR_KEY_DISTRIBUTION, SMP_BR_SM_NO_ACTION, SMP_BR_STATE_BOND_PENDING} +}; + +static const UINT8 smp_br_slave_bond_pending_table[][SMP_BR_SM_NUM_COLS] = +{ +/* Event Action Next State */ +/* BR_ID_INFO */ {SMP_PROC_ID_INFO, SMP_BR_SM_NO_ACTION, SMP_BR_STATE_BOND_PENDING}, +/* BR_ID_ADDR */ {SMP_PROC_ID_ADDR, SMP_BR_SM_NO_ACTION, SMP_BR_STATE_BOND_PENDING}, +/* BR_SIGN_INFO */ {SMP_PROC_SRK_INFO, SMP_BR_SM_NO_ACTION, SMP_BR_STATE_BOND_PENDING} +}; + +static const tSMP_BR_SM_TBL smp_br_state_table[][2] = +{ + /* SMP_BR_STATE_IDLE */ + {smp_br_master_idle_table, smp_br_slave_idle_table}, + + /* SMP_BR_STATE_WAIT_APP_RSP */ + {smp_br_master_wait_appln_response_table, smp_br_slave_wait_appln_response_table}, + + /* SMP_BR_STATE_PAIR_REQ_RSP */ + {smp_br_master_pair_request_response_table, NULL}, + + /* SMP_BR_STATE_BOND_PENDING */ + {smp_br_master_bond_pending_table, smp_br_slave_bond_pending_table}, +}; + +typedef const UINT8 (*tSMP_BR_ENTRY_TBL)[SMP_BR_STATE_MAX]; + +static const tSMP_BR_ENTRY_TBL smp_br_entry_table[] = +{ + smp_br_master_entry_map, + smp_br_slave_entry_map +}; + +#define SMP_BR_ALL_TABLE_MASK 0x80 + +/******************************************************************************* +** Function smp_set_br_state +** Returns None +*******************************************************************************/ +void smp_set_br_state(tSMP_BR_STATE br_state) +{ + if (br_state < SMP_BR_STATE_MAX) + { + SMP_TRACE_DEBUG( "BR_State change: %s(%d) ==> %s(%d)", + smp_get_br_state_name(smp_cb.br_state), smp_cb.br_state, + smp_get_br_state_name(br_state), br_state ); + smp_cb.br_state = br_state; + } + else + { + SMP_TRACE_DEBUG("%s invalid br_state =%d", __FUNCTION__,br_state ); + } +} + +/******************************************************************************* +** Function smp_get_br_state +** Returns The smp_br state +*******************************************************************************/ +tSMP_BR_STATE smp_get_br_state(void) +{ + return smp_cb.br_state; +} + +/******************************************************************************* +** Function smp_get_br_state_name +** Returns The smp_br state name. +*******************************************************************************/ +const char *smp_get_br_state_name(tSMP_BR_STATE br_state) +{ + const char *p_str = smp_br_state_name[SMP_BR_STATE_MAX]; + + if (br_state < SMP_BR_STATE_MAX) + p_str = smp_br_state_name[br_state]; + + return p_str; +} +/******************************************************************************* +** Function smp_get_br_event_name +** Returns The smp_br event name. +*******************************************************************************/ +const char * smp_get_br_event_name(tSMP_BR_EVENT event) +{ + const char * p_str = smp_br_event_name[SMP_BR_MAX_EVT - 1]; + + if (event < SMP_BR_MAX_EVT) + { + p_str = smp_br_event_name[event- 1]; + } + return p_str; +} + +/******************************************************************************* +** +** Function smp_br_state_machine_event +** +** Description Handle events to the state machine. It looks up the entry +** in the smp_br_entry_table array. +** If it is a valid entry, it gets the state table.Set the next state, +** if not NULL state. Execute the action function according to the +** state table. If the state returned by action function is not NULL +** state, adjust the new state to the returned state. +** +** Returns void. +** +*******************************************************************************/ +void smp_br_state_machine_event(tSMP_CB *p_cb, tSMP_BR_EVENT event, void *p_data) +{ + tSMP_BR_STATE curr_state = p_cb->br_state; + tSMP_BR_SM_TBL state_table; + UINT8 action, entry; + tSMP_BR_ENTRY_TBL entry_table = smp_br_entry_table[p_cb->role]; + + SMP_TRACE_EVENT("main %s", __func__); + if (curr_state >= SMP_BR_STATE_MAX) + { + SMP_TRACE_DEBUG( "Invalid br_state: %d", curr_state) ; + return; + } + + SMP_TRACE_DEBUG( "SMP Role: %s State: [%s (%d)], Event: [%s (%d)]", + (p_cb->role == HCI_ROLE_SLAVE) ? "Slave" : "Master", + smp_get_br_state_name( p_cb->br_state), + p_cb->br_state, smp_get_br_event_name(event), event) ; + + /* look up the state table for the current state */ + /* lookup entry / w event & curr_state */ + /* If entry is ignore, return. + * Otherwise, get state table (according to curr_state or all_state) */ + if ((event <= SMP_BR_MAX_EVT) && ( (entry = entry_table[event - 1][curr_state]) + != SMP_BR_SM_IGNORE )) + { + if (entry & SMP_BR_ALL_TABLE_MASK) + { + entry &= ~SMP_BR_ALL_TABLE_MASK; + state_table = smp_br_all_table; + } + else + { + state_table = smp_br_state_table[curr_state][p_cb->role]; + } + } + else + { + SMP_TRACE_DEBUG( "Ignore event [%s (%d)] in state [%s (%d)]", + smp_get_br_event_name(event), event, + smp_get_br_state_name(curr_state), curr_state); + return; + } + + /* Get possible next state from state table. */ + + smp_set_br_state(state_table[entry - 1][SMP_BR_SME_NEXT_STATE]); + + /* If action is not ignore, clear param, exec action and get next state. + * The action function may set the Param for cback. + * Depending on param, call cback or free buffer. */ + /* execute action functions */ + for (UINT8 i = 0; i < SMP_BR_NUM_ACTIONS; i++) + { + if ((action = state_table[entry - 1][i]) != SMP_BR_SM_NO_ACTION) + { + (*smp_br_sm_action[action])(p_cb, (tSMP_INT_DATA *)p_data); + } + else + { + break; + } + } + SMP_TRACE_DEBUG( "result state = %s", smp_get_br_state_name( p_cb->br_state ) ) ; +} + +#endif diff --git a/components/bt/bluedroid/stack/smp/smp_cmac.c b/components/bt/bluedroid/stack/smp/smp_cmac.c new file mode 100755 index 0000000000..eb7571afde --- /dev/null +++ b/components/bt/bluedroid/stack/smp/smp_cmac.c @@ -0,0 +1,388 @@ +/****************************************************************************** + * + * Copyright (C) 2008-2012 Broadcom Corporation + * + * 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 implementation of the AES128 CMAC algorithm. + * + ******************************************************************************/ + +#include "bt_target.h" + +#if SMP_INCLUDED == TRUE +// #include + #include + + #include "btm_ble_api.h" + #include "smp_int.h" + #include "hcimsgs.h" + +typedef struct +{ + UINT8 *text; + UINT16 len; + UINT16 round; +}tCMAC_CB; + +tCMAC_CB cmac_cb; + +/* Rb for AES-128 as block cipher, LSB as [0] */ +BT_OCTET16 const_Rb = { + 0x87, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; + +void print128(BT_OCTET16 x, const UINT8 *key_name) +{ +#if SMP_DEBUG == TRUE && SMP_DEBUG_VERBOSE == TRUE + UINT8 *p = (UINT8 *)x; + UINT8 i; + + SMP_TRACE_WARNING("%s(MSB ~ LSB) = ", key_name); + + for (i = 0; i < 4; i ++) + { + SMP_TRACE_WARNING("%02x %02x %02x %02x", + p[BT_OCTET16_LEN - i*4 -1], p[BT_OCTET16_LEN - i*4 -2], + p[BT_OCTET16_LEN - i*4 -3], p[BT_OCTET16_LEN - i*4 -4]); + } +#endif +} + +/******************************************************************************* +** +** Function padding +** +** Description utility function to padding the given text to be a 128 bits +** data. The parameter dest is input and output parameter, it +** must point to a BT_OCTET16_LEN memory space; where include +** length bytes valid data. +** +** Returns void +** +*******************************************************************************/ +static void padding ( BT_OCTET16 dest, UINT8 length ) +{ + UINT8 i, *p = dest; + /* original last block */ + for ( i = length ; i < BT_OCTET16_LEN; i++ ) + p[BT_OCTET16_LEN - i - 1] = ( i == length ) ? 0x80 : 0; +} +/******************************************************************************* +** +** Function leftshift_onebit +** +** Description utility function to left shift one bit for a 128 bits value. +** +** Returns void +** +*******************************************************************************/ +static void leftshift_onebit(UINT8 *input, UINT8 *output) +{ + UINT8 i, overflow = 0 , next_overflow = 0; + SMP_TRACE_EVENT ("leftshift_onebit "); + /* input[0] is LSB */ + for ( i = 0; i < BT_OCTET16_LEN ; i ++ ) + { + next_overflow = (input[i] & 0x80) ? 1:0; + output[i] = (input[i] << 1) | overflow; + overflow = next_overflow; + } + return; +} +/******************************************************************************* +** +** Function cmac_aes_cleanup +** +** Description clean up function for AES_CMAC algorithm. +** +** Returns void +** +*******************************************************************************/ +static void cmac_aes_cleanup(void) +{ + if (cmac_cb.text != NULL) + { + GKI_freebuf(cmac_cb.text); + } + memset(&cmac_cb, 0, sizeof(tCMAC_CB)); +} + +/******************************************************************************* +** +** Function cmac_aes_k_calculate +** +** Description This function is the calculation of block cipher using AES-128. +** +** Returns void +** +*******************************************************************************/ +static BOOLEAN cmac_aes_k_calculate(BT_OCTET16 key, UINT8 *p_signature, UINT16 tlen) +{ + tSMP_ENC output; + UINT8 i = 1, err = 0; + UINT8 x[16] = {0}; + UINT8 *p_mac; + + SMP_TRACE_EVENT ("cmac_aes_k_calculate "); + + while (i <= cmac_cb.round) + { + smp_xor_128(&cmac_cb.text[(cmac_cb.round - i)*BT_OCTET16_LEN], x); /* Mi' := Mi (+) X */ + + if (!SMP_Encrypt(key, BT_OCTET16_LEN, &cmac_cb.text[(cmac_cb.round - i)*BT_OCTET16_LEN], BT_OCTET16_LEN, &output)) + { + err = 1; + break; + } + + memcpy(x, output.param_buf, BT_OCTET16_LEN); + i ++; + } + + if (!err) + { + p_mac = output.param_buf + (BT_OCTET16_LEN - tlen); + memcpy(p_signature, p_mac, tlen); + + SMP_TRACE_DEBUG("tlen = %d p_mac = %d", tlen, p_mac); + SMP_TRACE_DEBUG("p_mac[0] = 0x%02x p_mac[1] = 0x%02x p_mac[2] = 0x%02x p_mac[3] = 0x%02x", + *p_mac, *(p_mac + 1), *(p_mac + 2), *(p_mac + 3)); + SMP_TRACE_DEBUG("p_mac[4] = 0x%02x p_mac[5] = 0x%02x p_mac[6] = 0x%02x p_mac[7] = 0x%02x", + *(p_mac + 4), *(p_mac + 5), *(p_mac + 6), *(p_mac + 7)); + + return TRUE; + + } + else + return FALSE; +} +/******************************************************************************* +** +** Function cmac_prepare_last_block +** +** Description This function proceeed to prepare the last block of message +** Mn depending on the size of the message. +** +** Returns void +** +*******************************************************************************/ +static void cmac_prepare_last_block (BT_OCTET16 k1, BT_OCTET16 k2) +{ +// UINT8 x[16] = {0}; + BOOLEAN flag; + + SMP_TRACE_EVENT ("cmac_prepare_last_block "); + /* last block is a complete block set flag to 1 */ + flag = ((cmac_cb.len % BT_OCTET16_LEN) == 0 && cmac_cb.len != 0) ? TRUE : FALSE; + + SMP_TRACE_WARNING("flag = %d round = %d", flag, cmac_cb.round); + + if ( flag ) + { /* last block is complete block */ + smp_xor_128(&cmac_cb.text[0], k1); + } + else /* padding then xor with k2 */ + { + padding(&cmac_cb.text[0], (UINT8)(cmac_cb.len % 16)); + + smp_xor_128(&cmac_cb.text[0], k2); + } +} +/******************************************************************************* +** +** Function cmac_subkey_cont +** +** Description This is the callback function when CIPHk(0[128]) is completed. +** +** Returns void +** +*******************************************************************************/ +static void cmac_subkey_cont(tSMP_ENC *p) +{ + UINT8 k1[BT_OCTET16_LEN], k2[BT_OCTET16_LEN]; + UINT8 *pp = p->param_buf; + SMP_TRACE_EVENT ("cmac_subkey_cont "); + print128(pp, (const UINT8 *)"K1 before shift"); + + /* If MSB(L) = 0, then K1 = L << 1 */ + if ( (pp[BT_OCTET16_LEN - 1] & 0x80) != 0 ) + { + /* Else K1 = ( L << 1 ) (+) Rb */ + leftshift_onebit(pp, k1); + smp_xor_128(k1, const_Rb); + } + else + { + leftshift_onebit(pp, k1); + } + + if ( (k1[BT_OCTET16_LEN - 1] & 0x80) != 0 ) + { + /* K2 = (K1 << 1) (+) Rb */ + leftshift_onebit(k1, k2); + smp_xor_128(k2, const_Rb); + } + else + { + /* If MSB(K1) = 0, then K2 = K1 << 1 */ + leftshift_onebit(k1, k2); + } + + print128(k1, (const UINT8 *)"K1"); + print128(k2, (const UINT8 *)"K2"); + + cmac_prepare_last_block (k1, k2); +} +/******************************************************************************* +** +** Function cmac_generate_subkey +** +** Description This is the function to generate the two subkeys. +** +** Parameters key - CMAC key, expect SRK when used by SMP. +** +** Returns void +** +*******************************************************************************/ +static BOOLEAN cmac_generate_subkey(BT_OCTET16 key) +{ + BT_OCTET16 z = {0}; + BOOLEAN ret = TRUE; + tSMP_ENC output; + SMP_TRACE_EVENT (" cmac_generate_subkey"); + + if (SMP_Encrypt(key, BT_OCTET16_LEN, z, BT_OCTET16_LEN, &output)) + { + cmac_subkey_cont(&output);; + } + else + ret = FALSE; + + return ret; +} +/******************************************************************************* +** +** Function aes_cipher_msg_auth_code +** +** Description This is the AES-CMAC Generation Function with tlen implemented. +** +** Parameters key - CMAC key in little endian order, expect SRK when used by SMP. +** input - text to be signed in little endian byte order. +** length - length of the input in byte. +** tlen - lenth of mac desired +** p_signature - data pointer to where signed data to be stored, tlen long. +** +** Returns FALSE if out of resources, TRUE in other cases. +** +*******************************************************************************/ +BOOLEAN aes_cipher_msg_auth_code(BT_OCTET16 key, UINT8 *input, UINT16 length, + UINT16 tlen, UINT8 *p_signature) +{ + UINT16 len, diff; + UINT16 n = (length + BT_OCTET16_LEN - 1) / BT_OCTET16_LEN; /* n is number of rounds */ + BOOLEAN ret = FALSE; + + SMP_TRACE_EVENT ("%s", __func__); + + if (n == 0) n = 1; + len = n * BT_OCTET16_LEN; + + SMP_TRACE_WARNING("AES128_CMAC started, allocate buffer size = %d", len); + /* allocate a memory space of multiple of 16 bytes to hold text */ + if ((cmac_cb.text = (UINT8 *)GKI_getbuf(len)) != NULL) + { + cmac_cb.round = n; + + memset(cmac_cb.text, 0, len); + diff = len - length; + + if (input != NULL && length > 0) + { + memcpy(&cmac_cb.text[diff] , input, (int)length); + cmac_cb.len = length; + } + else + cmac_cb.len = 0; + + /* prepare calculation for subkey s and last block of data */ + if (cmac_generate_subkey(key)) + { + /* start calculation */ + ret = cmac_aes_k_calculate(key, p_signature, tlen); + } + /* clean up */ + cmac_aes_cleanup(); + } + else + { + ret = FALSE; + SMP_TRACE_ERROR("No resources"); + } + + return ret; +} + + #if 0 /* testing code, sample data from spec */ +void test_cmac_cback(UINT8 *p_mac, UINT16 tlen) +{ + SMP_TRACE_EVENT ("test_cmac_cback "); + SMP_TRACE_ERROR("test_cmac_cback"); +} + +void test_cmac(void) +{ + SMP_TRACE_EVENT ("test_cmac "); + UINT8 M[64] = { + 0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96, + 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a, + 0xae, 0x2d, 0x8a, 0x57, 0x1e, 0x03, 0xac, 0x9c, + 0x9e, 0xb7, 0x6f, 0xac, 0x45, 0xaf, 0x8e, 0x51, + 0x30, 0xc8, 0x1c, 0x46, 0xa3, 0x5c, 0xe4, 0x11, + 0xe5, 0xfb, 0xc1, 0x19, 0x1a, 0x0a, 0x52, 0xef, + 0xf6, 0x9f, 0x24, 0x45, 0xdf, 0x4f, 0x9b, 0x17, + 0xad, 0x2b, 0x41, 0x7b, 0xe6, 0x6c, 0x37, 0x10 + }; + + UINT8 key[16] = { + 0x3c, 0x4f, 0xcf, 0x09, 0x88, 0x15, 0xf7, 0xab, + 0xa6, 0xd2, 0xae, 0x28, 0x16, 0x15, 0x7e, 0x2b + }; + UINT8 i =0, tmp; + UINT16 len; + + len = 64; + + for (i = 0; i < len/2; i ++) + { + tmp = M[i]; + M[i] = M[len -1 - i]; + M[len -1 - i] = tmp; + } + + + memset(&cmac_cb, 0, sizeof(tCMAC_CB)); + + SMP_TRACE_WARNING("\n Example 1: len = %d\n", len); + + aes_cipher_msg_auth_code(key, M, len, 128, test_cmac_cback, 0); + +} + #endif +#endif + diff --git a/components/bt/bluedroid/stack/smp/smp_keys.c b/components/bt/bluedroid/stack/smp/smp_keys.c new file mode 100755 index 0000000000..4a73392de5 --- /dev/null +++ b/components/bt/bluedroid/stack/smp/smp_keys.c @@ -0,0 +1,2291 @@ +/****************************************************************************** + * + * Copyright (C) 1999-2012 Broadcom Corporation + * + * 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 security manager protocol utility functions + * + ******************************************************************************/ +#include "bt_target.h" + +#if SMP_INCLUDED == TRUE +#if SMP_DEBUG == TRUE + #include +#endif +#include +//#include "bt_utils.h" +#include "btm_ble_api.h" +#include "smp_int.h" +#include "btm_int.h" +#include "btm_ble_int.h" +#include "hcimsgs.h" +#include "aes.h" +#include "p_256_ecc_pp.h" +#include "controller.h" + +#ifndef SMP_MAX_ENC_REPEAT + #define SMP_MAX_ENC_REPEAT 3 +#endif + +static void smp_rand_back(tBTM_RAND_ENC *p); +static void smp_generate_confirm(tSMP_CB *p_cb, tSMP_INT_DATA *p_data); +static void smp_generate_ltk_cont(tSMP_CB *p_cb, tSMP_INT_DATA *p_data); +static void smp_generate_y(tSMP_CB *p_cb, tSMP_INT_DATA *p); +static void smp_generate_rand_vector (tSMP_CB *p_cb, tSMP_INT_DATA *p); +static void smp_process_stk(tSMP_CB *p_cb, tSMP_ENC *p); +static void smp_calculate_comfirm_cont(tSMP_CB *p_cb, tSMP_ENC *p); +static void smp_process_confirm(tSMP_CB *p_cb, tSMP_ENC *p); +static void smp_process_compare(tSMP_CB *p_cb, tSMP_ENC *p); +static void smp_process_ediv(tSMP_CB *p_cb, tSMP_ENC *p); +static BOOLEAN smp_calculate_legacy_short_term_key(tSMP_CB *p_cb, tSMP_ENC *output); +static void smp_continue_private_key_creation(tSMP_CB *p_cb, tBTM_RAND_ENC *p); +static void smp_process_private_key(tSMP_CB *p_cb); +static void smp_finish_nonce_generation(tSMP_CB *p_cb); +static void smp_process_new_nonce(tSMP_CB *p_cb); + +static const tSMP_ACT smp_encrypt_action[] = +{ + smp_generate_compare, /* SMP_GEN_COMPARE */ + smp_generate_confirm, /* SMP_GEN_CONFIRM*/ + smp_generate_stk, /* SMP_GEN_STK*/ + smp_generate_ltk_cont, /* SMP_GEN_LTK */ + smp_generate_ltk, /* SMP_GEN_DIV_LTK */ + smp_generate_rand_vector, /* SMP_GEN_RAND_V */ + smp_generate_y, /* SMP_GEN_EDIV */ + smp_generate_passkey, /* SMP_GEN_TK */ + smp_generate_srand_mrand_confirm, /* SMP_GEN_SRAND_MRAND */ + smp_generate_rand_cont /* SMP_GEN_SRAND_MRAND_CONT */ +}; + +#define SMP_PASSKEY_MASK 0xfff00000 + +void smp_debug_print_nbyte_little_endian(UINT8 *p, const UINT8 *key_name, UINT8 len) +{ +#if SMP_DEBUG == TRUE + int ind, x; + int col_count = 32; + int row_count; + UINT8 p_buf[512]; + + SMP_TRACE_WARNING("%s(LSB ~ MSB):", key_name); + memset(p_buf, 0, sizeof(p_buf)); + row_count = len % col_count ? len / col_count + 1: len / col_count; + + ind = 0; + for (int row = 0; row < row_count; row++) + { + for (int column = 0, x = 0; (ind < len) && (column < col_count); column++, ind++) + { + x += sprintf((char *)&p_buf[x], "%02x ", p[ind]); + } + SMP_TRACE_WARNING(" [%03d]: %s", row * col_count, p_buf); + } +#endif +} + +void smp_debug_print_nbyte_big_endian (UINT8 *p, const UINT8 *key_name, UINT8 len) +{ +#if SMP_DEBUG == TRUE + UINT8 p_buf[512]; + + SMP_TRACE_WARNING("%s(MSB ~ LSB):", key_name); + memset(p_buf, 0, sizeof(p_buf)); + nrows = len % ncols ? len / ncols + 1: len / ncols; + + int ind = 0; + int ncols = 32; /* num entries in one line */ + int nrows; /* num lines */ + int x; + + for (int row = 0; row < nrows; row++) + { + for (int col = 0, x = 0; (ind < len) && (col < ncols); col++, ind++) + { + x += sprintf ((char *)&p_buf[len-x-1], "%02x ", p[ind]); + } + SMP_TRACE_WARNING("[%03d]: %s", row * ncols, p_buf); + } +#endif +} + +/******************************************************************************* +** +** Function smp_encrypt_data +** +** Description This function is called to encrypt data. +** It uses AES-128 encryption algorithm. +** Plain_text is encrypted using key, the result is at p_out. +** +** Returns void +** +*******************************************************************************/ +BOOLEAN smp_encrypt_data (UINT8 *key, UINT8 key_len, + UINT8 *plain_text, UINT8 pt_len, + tSMP_ENC *p_out) +{ + aes_context ctx; + UINT8 *p_start = NULL; + UINT8 *p = NULL; + UINT8 *p_rev_data = NULL; /* input data in big endilan format */ + UINT8 *p_rev_key = NULL; /* input key in big endilan format */ + UINT8 *p_rev_output = NULL; /* encrypted output in big endilan format */ + + SMP_TRACE_DEBUG ("%s", __func__); + if ( (p_out == NULL ) || (key_len != SMP_ENCRYT_KEY_SIZE) ) + { + SMP_TRACE_ERROR ("%s failed", __func__); + return FALSE; + } + + if ((p_start = (UINT8 *)GKI_getbuf((SMP_ENCRYT_DATA_SIZE*4))) == NULL) + { + SMP_TRACE_ERROR ("%s failed unable to allocate buffer", __func__); + return FALSE; + } + + if (pt_len > SMP_ENCRYT_DATA_SIZE) + pt_len = SMP_ENCRYT_DATA_SIZE; + + memset(p_start, 0, SMP_ENCRYT_DATA_SIZE * 4); + p = p_start; + ARRAY_TO_STREAM (p, plain_text, pt_len); /* byte 0 to byte 15 */ + p_rev_data = p = p_start + SMP_ENCRYT_DATA_SIZE; /* start at byte 16 */ + REVERSE_ARRAY_TO_STREAM (p, p_start, SMP_ENCRYT_DATA_SIZE); /* byte 16 to byte 31 */ + p_rev_key = p; /* start at byte 32 */ + REVERSE_ARRAY_TO_STREAM (p, key, SMP_ENCRYT_KEY_SIZE); /* byte 32 to byte 47 */ + +#if SMP_DEBUG == TRUE && SMP_DEBUG_VERBOSE == TRUE + smp_debug_print_nbyte_little_endian(key, (const UINT8 *)"Key", SMP_ENCRYT_KEY_SIZE); + smp_debug_print_nbyte_little_endian(p_start, (const UINT8 *)"Plain text", SMP_ENCRYT_DATA_SIZE); +#endif + p_rev_output = p; + aes_set_key(p_rev_key, SMP_ENCRYT_KEY_SIZE, &ctx); + bluedroid_aes_encrypt(p_rev_data, p, &ctx); /* outputs in byte 48 to byte 63 */ + + p = p_out->param_buf; + REVERSE_ARRAY_TO_STREAM (p, p_rev_output, SMP_ENCRYT_DATA_SIZE); +#if SMP_DEBUG == TRUE && SMP_DEBUG_VERBOSE == TRUE + smp_debug_print_nbyte_little_endian(p_out->param_buf, (const UINT8 *)"Encrypted text", SMP_ENCRYT_KEY_SIZE); +#endif + + p_out->param_len = SMP_ENCRYT_KEY_SIZE; + p_out->status = HCI_SUCCESS; + p_out->opcode = HCI_BLE_ENCRYPT; + + GKI_freebuf(p_start); + + return TRUE; +} + +/******************************************************************************* +** +** Function smp_generate_passkey +** +** Description This function is called to generate passkey. +** +** Returns void +** +*******************************************************************************/ +void smp_generate_passkey(tSMP_CB *p_cb, tSMP_INT_DATA *p_data) +{ + UNUSED(p_data); + + SMP_TRACE_DEBUG ("%s", __func__); + p_cb->rand_enc_proc_state = SMP_GEN_TK; + + /* generate MRand or SRand */ + if (!btsnd_hcic_ble_rand((void *)smp_rand_back)) + smp_rand_back(NULL); +} + +/******************************************************************************* +** +** Function smp_proc_passkey +** +** Description This function is called to process a passkey. +** +** Returns void +** +*******************************************************************************/ +void smp_proc_passkey(tSMP_CB *p_cb , tBTM_RAND_ENC *p) +{ + UINT8 *tt = p_cb->tk; + tSMP_KEY key; + UINT32 passkey; /* 19655 test number; */ + UINT8 *pp = p->param_buf; + + SMP_TRACE_DEBUG ("%s", __func__); + STREAM_TO_UINT32(passkey, pp); + passkey &= ~SMP_PASSKEY_MASK; + + /* truncate by maximum value */ + while (passkey > BTM_MAX_PASSKEY_VAL) + passkey >>= 1; + + /* save the TK */ + memset(p_cb->tk, 0, BT_OCTET16_LEN); + UINT32_TO_STREAM(tt, passkey); + + key.key_type = SMP_KEY_TYPE_TK; + key.p_data = p_cb->tk; + + if (p_cb->p_callback) + { + (*p_cb->p_callback)(SMP_PASSKEY_NOTIF_EVT, p_cb->pairing_bda, (tSMP_EVT_DATA *)&passkey); + } + + if (p_cb->selected_association_model == SMP_MODEL_SEC_CONN_PASSKEY_DISP) + { + smp_sm_event(&smp_cb, SMP_KEY_READY_EVT, &passkey); + } + else + { + smp_sm_event(p_cb, SMP_KEY_READY_EVT, (tSMP_INT_DATA *)&key); + } +} + +/******************************************************************************* +** +** Function smp_generate_stk +** +** Description This function is called to generate STK calculated by running +** AES with the TK value as key and a concatenation of the random +** values. +** +** Returns void +** +*******************************************************************************/ +void smp_generate_stk(tSMP_CB *p_cb, tSMP_INT_DATA *p_data) +{ + UNUSED(p_data); + + tSMP_ENC output; + tSMP_STATUS status = SMP_PAIR_FAIL_UNKNOWN; + + SMP_TRACE_DEBUG ("%s", __func__); + + if (p_cb->le_secure_connections_mode_is_used) + { + SMP_TRACE_WARNING ("FOR LE SC LTK IS USED INSTEAD OF STK"); + output.param_len = SMP_ENCRYT_KEY_SIZE; + output.status = HCI_SUCCESS; + output.opcode = HCI_BLE_ENCRYPT; + memcpy(output.param_buf, p_cb->ltk, SMP_ENCRYT_DATA_SIZE); + } + else if (!smp_calculate_legacy_short_term_key(p_cb, &output)) + { + SMP_TRACE_ERROR("%s failed", __func__); + smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &status); + return; + } + + smp_process_stk(p_cb, &output); +} + +/******************************************************************************* +** +** Function smp_generate_srand_mrand_confirm +** +** Description This function is called to start the second pairing phase by +** start generating random number. +** +** +** Returns void +** +*******************************************************************************/ +void smp_generate_srand_mrand_confirm(tSMP_CB *p_cb, tSMP_INT_DATA *p_data) +{ + UNUSED(p_data); + + SMP_TRACE_DEBUG ("%s", __func__); + p_cb->rand_enc_proc_state = SMP_GEN_SRAND_MRAND; + /* generate MRand or SRand */ + if (!btsnd_hcic_ble_rand((void *)smp_rand_back)) + smp_rand_back(NULL); +} + +/******************************************************************************* +** +** Function smp_generate_rand_cont +** +** Description This function is called to generate another 64 bits random for +** MRand or Srand. +** +** Returns void +** +*******************************************************************************/ +void smp_generate_rand_cont(tSMP_CB *p_cb, tSMP_INT_DATA *p_data) +{ + UNUSED(p_data); + + SMP_TRACE_DEBUG ("%s", __func__); + p_cb->rand_enc_proc_state = SMP_GEN_SRAND_MRAND_CONT; + /* generate 64 MSB of MRand or SRand */ + if (!btsnd_hcic_ble_rand((void *)smp_rand_back)) + smp_rand_back(NULL); +} + +/******************************************************************************* +** +** Function smp_generate_ltk +** +** Description This function is called: +** - in legacy pairing - to calculate LTK, starting with DIV +** generation; +** - in LE Secure Connections pairing over LE transport - to process LTK +** already generated to encrypt LE link; +** - in LE Secure Connections pairing over BR/EDR transport - to start +** BR/EDR Link Key processing. +** +** Returns void +** +*******************************************************************************/ +void smp_generate_ltk(tSMP_CB *p_cb, tSMP_INT_DATA *p_data) +{ + UNUSED(p_data); + + BOOLEAN div_status; + SMP_TRACE_DEBUG ("%s", __FUNCTION__); + if (smp_get_br_state() == SMP_BR_STATE_BOND_PENDING) + { + smp_br_process_link_key(p_cb, NULL); + return; + } + else if (p_cb->le_secure_connections_mode_is_used) + { + smp_process_secure_connection_long_term_key(); + return; + } + + div_status = btm_get_local_div(p_cb->pairing_bda, &p_cb->div); + + if (div_status) + { + smp_generate_ltk_cont(p_cb, NULL); + } + else + { + SMP_TRACE_DEBUG ("Generate DIV for LTK"); + p_cb->rand_enc_proc_state = SMP_GEN_DIV_LTK; + /* generate MRand or SRand */ + if (!btsnd_hcic_ble_rand((void *)smp_rand_back)) + smp_rand_back(NULL); + } +} + +/******************************************************************************* +** +** Function smp_compute_csrk +** +** Description This function is called to calculate CSRK +** +** +** Returns void +** +*******************************************************************************/ +void smp_compute_csrk(tSMP_CB *p_cb, tSMP_INT_DATA *p_data) +{ + UNUSED(p_data); + + BT_OCTET16 er; + UINT8 buffer[4]; /* for (r || DIV) r=1*/ + UINT16 r=1; + UINT8 *p=buffer; + tSMP_ENC output; + tSMP_STATUS status = SMP_PAIR_FAIL_UNKNOWN; + + SMP_TRACE_DEBUG ("smp_compute_csrk div=%x", p_cb->div); + BTM_GetDeviceEncRoot(er); + /* CSRK = d1(ER, DIV, 1) */ + UINT16_TO_STREAM(p, p_cb->div); + UINT16_TO_STREAM(p, r); + + if (!SMP_Encrypt(er, BT_OCTET16_LEN, buffer, 4, &output)) + { + SMP_TRACE_ERROR("smp_generate_csrk failed"); + if (p_cb->smp_over_br) + { + smp_br_state_machine_event(p_cb, SMP_BR_AUTH_CMPL_EVT, &status); + } + else + { + smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &status); + } + } + else + { + memcpy((void *)p_cb->csrk, output.param_buf, BT_OCTET16_LEN); + smp_send_csrk_info(p_cb, NULL); + } +} + +/******************************************************************************* +** +** Function smp_generate_csrk +** +** Description This function is called to calculate CSRK, starting with DIV +** generation. +** +** +** Returns void +** +*******************************************************************************/ +void smp_generate_csrk(tSMP_CB *p_cb, tSMP_INT_DATA *p_data) +{ + UNUSED(p_data); + + BOOLEAN div_status; + + SMP_TRACE_DEBUG ("smp_generate_csrk"); + + div_status = btm_get_local_div(p_cb->pairing_bda, &p_cb->div); + if (div_status) + { + smp_compute_csrk(p_cb, NULL); + } + else + { + SMP_TRACE_DEBUG ("Generate DIV for CSRK"); + p_cb->rand_enc_proc_state = SMP_GEN_DIV_CSRK; + if (!btsnd_hcic_ble_rand((void *)smp_rand_back)) + smp_rand_back(NULL); + } +} + +/******************************************************************************* +** Function smp_concatenate_peer +** add pairing command sent from local device into p1. +*******************************************************************************/ +void smp_concatenate_local( tSMP_CB *p_cb, UINT8 **p_data, UINT8 op_code) +{ + UINT8 *p = *p_data; + + SMP_TRACE_DEBUG ("%s", __func__); + UINT8_TO_STREAM(p, op_code); + UINT8_TO_STREAM(p, p_cb->local_io_capability); + UINT8_TO_STREAM(p, p_cb->loc_oob_flag); + UINT8_TO_STREAM(p, p_cb->loc_auth_req); + UINT8_TO_STREAM(p, p_cb->loc_enc_size); + UINT8_TO_STREAM(p, p_cb->local_i_key); + UINT8_TO_STREAM(p, p_cb->local_r_key); + + *p_data = p; +} + +/******************************************************************************* +** Function smp_concatenate_peer +** add pairing command received from peer device into p1. +*******************************************************************************/ +void smp_concatenate_peer( tSMP_CB *p_cb, UINT8 **p_data, UINT8 op_code) +{ + UINT8 *p = *p_data; + + SMP_TRACE_DEBUG ("smp_concatenate_peer "); + UINT8_TO_STREAM(p, op_code); + UINT8_TO_STREAM(p, p_cb->peer_io_caps); + UINT8_TO_STREAM(p, p_cb->peer_oob_flag); + UINT8_TO_STREAM(p, p_cb->peer_auth_req); + UINT8_TO_STREAM(p, p_cb->peer_enc_size); + UINT8_TO_STREAM(p, p_cb->peer_i_key); + UINT8_TO_STREAM(p, p_cb->peer_r_key); + + *p_data = p; +} + +/******************************************************************************* +** +** Function smp_gen_p1_4_confirm +** +** Description Generate Confirm/Compare Step1: +** p1 = pres || preq || rat' || iat' +** +** Returns void +** +*******************************************************************************/ +void smp_gen_p1_4_confirm( tSMP_CB *p_cb, BT_OCTET16 p1) +{ + UINT8 *p = (UINT8 *)p1; + tBLE_ADDR_TYPE addr_type = 0; + BD_ADDR remote_bda; + + SMP_TRACE_DEBUG ("smp_gen_p1_4_confirm"); + + if (!BTM_ReadRemoteConnectionAddr(p_cb->pairing_bda, remote_bda, &addr_type)) + { + SMP_TRACE_ERROR("can not generate confirm for unknown device"); + return; + } + + BTM_ReadConnectionAddr( p_cb->pairing_bda, p_cb->local_bda, &p_cb->addr_type); + + if (p_cb->role == HCI_ROLE_MASTER) + { + /* LSB : rat': initiator's(local) address type */ + UINT8_TO_STREAM(p, p_cb->addr_type); + /* LSB : iat': responder's address type */ + UINT8_TO_STREAM(p, addr_type); + /* concatinate preq */ + smp_concatenate_local(p_cb, &p, SMP_OPCODE_PAIRING_REQ); + /* concatinate pres */ + smp_concatenate_peer(p_cb, &p, SMP_OPCODE_PAIRING_RSP); + } + else + { + /* LSB : iat': initiator's address type */ + UINT8_TO_STREAM(p, addr_type); + /* LSB : rat': responder's(local) address type */ + UINT8_TO_STREAM(p, p_cb->addr_type); + /* concatinate preq */ + smp_concatenate_peer(p_cb, &p, SMP_OPCODE_PAIRING_REQ); + /* concatinate pres */ + smp_concatenate_local(p_cb, &p, SMP_OPCODE_PAIRING_RSP); + } +#if SMP_DEBUG == TRUE + SMP_TRACE_DEBUG("p1 = pres || preq || rat' || iat'"); + smp_debug_print_nbyte_little_endian ((UINT8 *)p1, (const UINT8 *)"P1", 16); +#endif +} + +/******************************************************************************* +** +** Function smp_gen_p2_4_confirm +** +** Description Generate Confirm/Compare Step2: +** p2 = padding || ia || ra +** +** Returns void +** +*******************************************************************************/ +void smp_gen_p2_4_confirm( tSMP_CB *p_cb, BT_OCTET16 p2) +{ + UINT8 *p = (UINT8 *)p2; + BD_ADDR remote_bda; + tBLE_ADDR_TYPE addr_type = 0; + + if (!BTM_ReadRemoteConnectionAddr(p_cb->pairing_bda, remote_bda, &addr_type)) + { + SMP_TRACE_ERROR("can not generate confirm p2 for unknown device"); + return; + } + + SMP_TRACE_DEBUG ("smp_gen_p2_4_confirm"); + + memset(p, 0, sizeof(BT_OCTET16)); + + if (p_cb->role == HCI_ROLE_MASTER) + { + /* LSB ra */ + BDADDR_TO_STREAM(p, remote_bda); + /* ia */ + BDADDR_TO_STREAM(p, p_cb->local_bda); + } + else + { + /* LSB ra */ + BDADDR_TO_STREAM(p, p_cb->local_bda); + /* ia */ + BDADDR_TO_STREAM(p, remote_bda); + } +#if SMP_DEBUG == TRUE + SMP_TRACE_DEBUG("p2 = padding || ia || ra"); + smp_debug_print_nbyte_little_endian(p2, (const UINT8 *)"p2", 16); +#endif +} + +/******************************************************************************* +** +** Function smp_calculate_comfirm +** +** Description This function is called to calculate Confirm value. +** +** Returns void +** +*******************************************************************************/ +void smp_calculate_comfirm (tSMP_CB *p_cb, BT_OCTET16 rand, BD_ADDR bda) +{ + UNUSED(bda); + + BT_OCTET16 p1; + tSMP_ENC output; + tSMP_STATUS status = SMP_PAIR_FAIL_UNKNOWN; + + SMP_TRACE_DEBUG ("smp_calculate_comfirm "); + /* generate p1 = pres || preq || rat' || iat' */ + smp_gen_p1_4_confirm(p_cb, p1); + + /* p1 = rand XOR p1 */ + smp_xor_128(p1, rand); + + smp_debug_print_nbyte_little_endian ((UINT8 *)p1, (const UINT8 *)"P1' = r XOR p1", 16); + + /* calculate e(k, r XOR p1), where k = TK */ + if (!SMP_Encrypt(p_cb->tk, BT_OCTET16_LEN, p1, BT_OCTET16_LEN, &output)) + { + SMP_TRACE_ERROR("smp_generate_csrk failed"); + smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &status); + } + else + { + smp_calculate_comfirm_cont(p_cb, &output); + } +} + +/******************************************************************************* +** +** Function smp_calculate_comfirm_cont +** +** Description This function is called when SConfirm/MConfirm is generated +** proceed to send the Confirm request/response to peer device. +** +** Returns void +** +*******************************************************************************/ +static void smp_calculate_comfirm_cont(tSMP_CB *p_cb, tSMP_ENC *p) +{ + BT_OCTET16 p2; + tSMP_ENC output; + tSMP_STATUS status = SMP_PAIR_FAIL_UNKNOWN; + + SMP_TRACE_DEBUG ("smp_calculate_comfirm_cont "); +#if SMP_DEBUG == TRUE + SMP_TRACE_DEBUG("Confirm step 1 p1' = e(k, r XOR p1) Generated"); + smp_debug_print_nbyte_little_endian (p->param_buf, (const UINT8 *)"C1", 16); +#endif + + smp_gen_p2_4_confirm(p_cb, p2); + + /* calculate p2 = (p1' XOR p2) */ + smp_xor_128(p2, p->param_buf); + smp_debug_print_nbyte_little_endian ((UINT8 *)p2, (const UINT8 *)"p2' = C1 xor p2", 16); + + /* calculate: Confirm = E(k, p1' XOR p2) */ + if (!SMP_Encrypt(p_cb->tk, BT_OCTET16_LEN, p2, BT_OCTET16_LEN, &output)) + { + SMP_TRACE_ERROR("smp_calculate_comfirm_cont failed"); + smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &status); + } + else + { + switch (p_cb->rand_enc_proc_state) + { + case SMP_GEN_CONFIRM: + smp_process_confirm(p_cb, &output); + break; + + case SMP_GEN_COMPARE: + smp_process_compare(p_cb, &output); + break; + } + } +} + +/******************************************************************************* +** +** Function smp_generate_confirm +** +** Description This function is called when a 48 bits random number is generated +** as SRand or MRand, continue to calculate Sconfirm or MConfirm. +** +** Returns void +** +*******************************************************************************/ +static void smp_generate_confirm(tSMP_CB *p_cb, tSMP_INT_DATA *p_data) +{ + UNUSED(p_data); + + SMP_TRACE_DEBUG ("%s", __func__); + p_cb->rand_enc_proc_state = SMP_GEN_CONFIRM; + smp_debug_print_nbyte_little_endian ((UINT8 *)p_cb->rand, (const UINT8 *)"local rand", 16); + smp_calculate_comfirm(p_cb, p_cb->rand, p_cb->pairing_bda); +} + +/******************************************************************************* +** +** Function smp_generate_compare +** +** Description This function is called to generate SConfirm for Slave device, +** or MSlave for Master device. This function can be also used for +** generating Compare number for confirm value check. +** +** Returns void +** +*******************************************************************************/ +void smp_generate_compare (tSMP_CB *p_cb, tSMP_INT_DATA *p_data) +{ + UNUSED(p_data); + + SMP_TRACE_DEBUG ("smp_generate_compare "); + p_cb->rand_enc_proc_state = SMP_GEN_COMPARE; + smp_debug_print_nbyte_little_endian ((UINT8 *)p_cb->rrand, (const UINT8 *)"peer rand", 16); + smp_calculate_comfirm(p_cb, p_cb->rrand, p_cb->local_bda); +} + +/******************************************************************************* +** +** Function smp_process_confirm +** +** Description This function is called when SConfirm/MConfirm is generated +** proceed to send the Confirm request/response to peer device. +** +** Returns void +** +*******************************************************************************/ +static void smp_process_confirm(tSMP_CB *p_cb, tSMP_ENC *p) +{ + tSMP_KEY key; + + SMP_TRACE_DEBUG ("%s", __FUNCTION__); + memcpy(p_cb->confirm, p->param_buf, BT_OCTET16_LEN); + +#if (SMP_DEBUG == TRUE) + SMP_TRACE_DEBUG("Confirm Generated"); + smp_debug_print_nbyte_little_endian ((UINT8 *)p_cb->confirm, (const UINT8 *)"Confirm", 16); +#endif + + key.key_type = SMP_KEY_TYPE_CFM; + key.p_data = p->param_buf; + smp_sm_event(p_cb, SMP_KEY_READY_EVT, &key); +} + +/******************************************************************************* +** +** Function smp_process_compare +** +** Description This function is called when Compare is generated using the +** RRand and local BDA, TK information. +** +** Returns void +** +*******************************************************************************/ +static void smp_process_compare(tSMP_CB *p_cb, tSMP_ENC *p) +{ + tSMP_KEY key; + + SMP_TRACE_DEBUG ("smp_process_compare "); +#if (SMP_DEBUG == TRUE) + SMP_TRACE_DEBUG("Compare Generated"); + smp_debug_print_nbyte_little_endian (p->param_buf, (const UINT8 *)"Compare", 16); +#endif + key.key_type = SMP_KEY_TYPE_CMP; + key.p_data = p->param_buf; + + smp_sm_event(p_cb, SMP_KEY_READY_EVT, &key); +} + +/******************************************************************************* +** +** Function smp_process_stk +** +** Description This function is called when STK is generated +** proceed to send the encrypt the link using STK. +** +** Returns void +** +*******************************************************************************/ +static void smp_process_stk(tSMP_CB *p_cb, tSMP_ENC *p) +{ + tSMP_KEY key; + + SMP_TRACE_DEBUG ("smp_process_stk "); +#if (SMP_DEBUG == TRUE) + SMP_TRACE_ERROR("STK Generated"); +#endif + smp_mask_enc_key(p_cb->loc_enc_size, p->param_buf); + + key.key_type = SMP_KEY_TYPE_STK; + key.p_data = p->param_buf; + + smp_sm_event(p_cb, SMP_KEY_READY_EVT, &key); +} + +/******************************************************************************* +** +** Function smp_generate_ltk_cont +** +** Description This function is to calculate LTK = d1(ER, DIV, 0)= e(ER, DIV) +** +** Returns void +** +*******************************************************************************/ +static void smp_generate_ltk_cont(tSMP_CB *p_cb, tSMP_INT_DATA *p_data) +{ + UNUSED(p_data); + + BT_OCTET16 er; + tSMP_ENC output; + tSMP_STATUS status = SMP_PAIR_FAIL_UNKNOWN; + + SMP_TRACE_DEBUG ("%s", __func__); + BTM_GetDeviceEncRoot(er); + + /* LTK = d1(ER, DIV, 0)= e(ER, DIV)*/ + if (!SMP_Encrypt(er, BT_OCTET16_LEN, (UINT8 *)&p_cb->div, + sizeof(UINT16), &output)) + { + SMP_TRACE_ERROR("%s failed", __func__); + smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &status); + } + else + { + /* mask the LTK */ + smp_mask_enc_key(p_cb->loc_enc_size, output.param_buf); + memcpy((void *)p_cb->ltk, output.param_buf, BT_OCTET16_LEN); + smp_generate_rand_vector(p_cb, NULL); + } +} + +/******************************************************************************* +** +** Function smp_generate_y +** +** Description This function is to proceed generate Y = E(DHK, Rand) +** +** Returns void +** +*******************************************************************************/ +static void smp_generate_y(tSMP_CB *p_cb, tSMP_INT_DATA *p) +{ + UNUSED(p); + + BT_OCTET16 dhk; + tSMP_ENC output; + tSMP_STATUS status = SMP_PAIR_FAIL_UNKNOWN; + + + SMP_TRACE_DEBUG ("smp_generate_y "); + BTM_GetDeviceDHK(dhk); + + if (!SMP_Encrypt(dhk, BT_OCTET16_LEN, p_cb->enc_rand, + BT_OCTET8_LEN, &output)) + { + SMP_TRACE_ERROR("smp_generate_y failed"); + smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &status); + } + else + { + smp_process_ediv(p_cb, &output); + } +} + +/******************************************************************************* +** +** Function smp_generate_rand_vector +** +** Description This function is called when LTK is generated, send state machine +** event to SMP. +** +** Returns void +** +*******************************************************************************/ +static void smp_generate_rand_vector (tSMP_CB *p_cb, tSMP_INT_DATA *p) +{ + UNUSED(p); + + /* generate EDIV and rand now */ + /* generate random vector */ + SMP_TRACE_DEBUG ("smp_generate_rand_vector "); + p_cb->rand_enc_proc_state = SMP_GEN_RAND_V; + if (!btsnd_hcic_ble_rand((void *)smp_rand_back)) + smp_rand_back(NULL); +} + +/******************************************************************************* +** +** Function smp_process_ediv +** +** Description This function is to calculate EDIV = Y xor DIV +** +** Returns void +** +*******************************************************************************/ +static void smp_process_ediv(tSMP_CB *p_cb, tSMP_ENC *p) +{ + tSMP_KEY key; + UINT8 *pp= p->param_buf; + UINT16 y; + + SMP_TRACE_DEBUG ("smp_process_ediv "); + STREAM_TO_UINT16(y, pp); + + /* EDIV = Y xor DIV */ + p_cb->ediv = p_cb->div ^ y; + /* send LTK ready */ + SMP_TRACE_ERROR("LTK ready"); + key.key_type = SMP_KEY_TYPE_LTK; + key.p_data = p->param_buf; + + smp_sm_event(p_cb, SMP_KEY_READY_EVT, &key); +} + +/******************************************************************************* +** +** Function smp_calculate_legacy_short_term_key +** +** Description The function calculates legacy STK. +** +** Returns FALSE if out of resources, TRUE in other cases. +** +*******************************************************************************/ +BOOLEAN smp_calculate_legacy_short_term_key(tSMP_CB *p_cb, tSMP_ENC *output) +{ + BT_OCTET16 ptext; + UINT8 *p = ptext; + + SMP_TRACE_DEBUG ("%s", __func__); + memset(p, 0, BT_OCTET16_LEN); + if (p_cb->role == HCI_ROLE_MASTER) + { + memcpy(p, p_cb->rand, BT_OCTET8_LEN); + memcpy(&p[BT_OCTET8_LEN], p_cb->rrand, BT_OCTET8_LEN); + } + else + { + memcpy(p, p_cb->rrand, BT_OCTET8_LEN); + memcpy(&p[BT_OCTET8_LEN], p_cb->rand, BT_OCTET8_LEN); + } + + BOOLEAN encrypted; + /* generate STK = Etk(rand|rrand)*/ + encrypted = SMP_Encrypt( p_cb->tk, BT_OCTET16_LEN, ptext, BT_OCTET16_LEN, output); + if (!encrypted) + { + SMP_TRACE_ERROR("%s failed", __func__); + } + return encrypted; +} + +/******************************************************************************* +** +** Function smp_create_private_key +** +** Description This function is called to create private key used to +** calculate public key and DHKey. +** The function starts private key creation requesting controller +** to generate [0-7] octets of private key. +** +** Returns void +** +*******************************************************************************/ +void smp_create_private_key(tSMP_CB *p_cb, tSMP_INT_DATA *p_data) +{ + SMP_TRACE_DEBUG ("%s",__FUNCTION__); + p_cb->rand_enc_proc_state = SMP_GENERATE_PRIVATE_KEY_0_7; + if (!btsnd_hcic_ble_rand((void *)smp_rand_back)) + smp_rand_back(NULL); +} + +/******************************************************************************* +** +** Function smp_use_oob_private_key +** +** Description This function is called +** - to save the secret key used to calculate the public key used +** in calculations of commitment sent OOB to a peer +** - to use this secret key to recalculate the public key and +** start the process of sending this public key to the peer +** if secret/public keys have to be reused. +** If the keys aren't supposed to be reused, continue from the +** point from which request for OOB data was issued. +** +** Returns void +** +*******************************************************************************/ +void smp_use_oob_private_key(tSMP_CB *p_cb, tSMP_INT_DATA *p_data) +{ + SMP_TRACE_DEBUG ("%s req_oob_type: %d, role: %d", + __func__, p_cb->req_oob_type, p_cb->role); + + switch (p_cb->req_oob_type) + { + case SMP_OOB_BOTH: + case SMP_OOB_LOCAL: + SMP_TRACE_DEBUG("%s restore secret key", __func__) + memcpy(p_cb->private_key, p_cb->sc_oob_data.loc_oob_data.private_key_used, BT_OCTET32_LEN); + smp_process_private_key(p_cb); + break; + default: + SMP_TRACE_DEBUG("%s create secret key anew", __func__); + smp_set_state(SMP_STATE_PAIR_REQ_RSP); + smp_decide_association_model(p_cb, NULL); + break; + } +} + +/******************************************************************************* +** +** Function smp_continue_private_key_creation +** +** Description This function is used to continue private key creation. +** +** Returns void +** +*******************************************************************************/ +void smp_continue_private_key_creation (tSMP_CB *p_cb, tBTM_RAND_ENC *p) +{ + UINT8 state = p_cb->rand_enc_proc_state & ~0x80; + SMP_TRACE_DEBUG ("%s state=0x%x", __func__, state); + + switch (state) + { + case SMP_GENERATE_PRIVATE_KEY_0_7: + memcpy((void *)p_cb->private_key, p->param_buf, p->param_len); + p_cb->rand_enc_proc_state = SMP_GENERATE_PRIVATE_KEY_8_15; + if (!btsnd_hcic_ble_rand((void *)smp_rand_back)) + smp_rand_back(NULL); + break; + + case SMP_GENERATE_PRIVATE_KEY_8_15: + memcpy((void *)&p_cb->private_key[8], p->param_buf, p->param_len); + p_cb->rand_enc_proc_state = SMP_GENERATE_PRIVATE_KEY_16_23; + if (!btsnd_hcic_ble_rand((void *)smp_rand_back)) + smp_rand_back(NULL); + break; + + case SMP_GENERATE_PRIVATE_KEY_16_23: + memcpy((void *)&p_cb->private_key[16], p->param_buf, p->param_len); + p_cb->rand_enc_proc_state = SMP_GENERATE_PRIVATE_KEY_24_31; + if (!btsnd_hcic_ble_rand((void *)smp_rand_back)) + smp_rand_back(NULL); + break; + + case SMP_GENERATE_PRIVATE_KEY_24_31: + memcpy((void *)&p_cb->private_key[24], p->param_buf, p->param_len); + smp_process_private_key (p_cb); + break; + + default: + break; + } + + return; +} + +/******************************************************************************* +** +** Function smp_process_private_key +** +** Description This function processes private key. +** It calculates public key and notifies SM that private key / +** public key pair is created. +** +** Returns void +** +*******************************************************************************/ +void smp_process_private_key(tSMP_CB *p_cb) +{ + Point public_key; + BT_OCTET32 private_key; + + SMP_TRACE_DEBUG ("%s", __FUNCTION__); + + memcpy(private_key, p_cb->private_key, BT_OCTET32_LEN); + ECC_PointMult(&public_key, &(curve_p256.G), (DWORD*) private_key, KEY_LENGTH_DWORDS_P256); + memcpy(p_cb->loc_publ_key.x, public_key.x, BT_OCTET32_LEN); + memcpy(p_cb->loc_publ_key.y, public_key.y, BT_OCTET32_LEN); + + smp_debug_print_nbyte_little_endian (p_cb->private_key, (const UINT8 *)"private", + BT_OCTET32_LEN); + smp_debug_print_nbyte_little_endian (p_cb->loc_publ_key.x, (const UINT8 *)"local public(x)", + BT_OCTET32_LEN); + smp_debug_print_nbyte_little_endian (p_cb->loc_publ_key.y, (const UINT8 *)"local public(y)", + BT_OCTET32_LEN); + p_cb->flags |= SMP_PAIR_FLAG_HAVE_LOCAL_PUBL_KEY; + smp_sm_event(p_cb, SMP_LOC_PUBL_KEY_CRTD_EVT, NULL); +} + +/******************************************************************************* +** +** Function smp_compute_dhkey +** +** Description The function: +** - calculates a new public key using as input local private +** key and peer public key; +** - saves the new public key x-coordinate as DHKey. +** +** Returns void +** +*******************************************************************************/ +void smp_compute_dhkey (tSMP_CB *p_cb) +{ + Point peer_publ_key, new_publ_key; + BT_OCTET32 private_key; + + SMP_TRACE_DEBUG ("%s", __FUNCTION__); + + memcpy(private_key, p_cb->private_key, BT_OCTET32_LEN); + memcpy(peer_publ_key.x, p_cb->peer_publ_key.x, BT_OCTET32_LEN); + memcpy(peer_publ_key.y, p_cb->peer_publ_key.y, BT_OCTET32_LEN); + + ECC_PointMult(&new_publ_key, &peer_publ_key, (DWORD*) private_key, KEY_LENGTH_DWORDS_P256); + + memcpy(p_cb->dhkey, new_publ_key.x, BT_OCTET32_LEN); + + smp_debug_print_nbyte_little_endian (p_cb->dhkey, (const UINT8 *)"Old DHKey", + BT_OCTET32_LEN); + + smp_debug_print_nbyte_little_endian (p_cb->private_key, (const UINT8 *)"private", + BT_OCTET32_LEN); + smp_debug_print_nbyte_little_endian (p_cb->peer_publ_key.x, (const UINT8 *)"rem public(x)", + BT_OCTET32_LEN); + smp_debug_print_nbyte_little_endian (p_cb->peer_publ_key.y, (const UINT8 *)"rem public(y)", + BT_OCTET32_LEN); + smp_debug_print_nbyte_little_endian (p_cb->dhkey, (const UINT8 *)"Reverted DHKey", + BT_OCTET32_LEN); +} + +/******************************************************************************* +** +** Function smp_calculate_local_commitment +** +** Description The function calculates and saves local commmitment in CB. +** +** Returns void +** +*******************************************************************************/ +void smp_calculate_local_commitment(tSMP_CB *p_cb) +{ + UINT8 random_input; + + SMP_TRACE_DEBUG("%s", __FUNCTION__); + + switch (p_cb->selected_association_model) + { + case SMP_MODEL_SEC_CONN_JUSTWORKS: + case SMP_MODEL_SEC_CONN_NUM_COMP: + if (p_cb->role == HCI_ROLE_MASTER) + SMP_TRACE_WARNING ("local commitment calc on master is not expected \ + for Just Works/Numeric Comparison models"); + smp_calculate_f4(p_cb->loc_publ_key.x, p_cb->peer_publ_key.x, p_cb->rand, 0, + p_cb->commitment); + break; + case SMP_MODEL_SEC_CONN_PASSKEY_ENT: + case SMP_MODEL_SEC_CONN_PASSKEY_DISP: + random_input = smp_calculate_random_input(p_cb->local_random, p_cb->round); + smp_calculate_f4(p_cb->loc_publ_key.x, p_cb->peer_publ_key.x, p_cb->rand, + random_input, p_cb->commitment); + break; + case SMP_MODEL_SEC_CONN_OOB: + SMP_TRACE_WARNING ("local commitment calc is expected for OOB model BEFORE pairing"); + smp_calculate_f4(p_cb->loc_publ_key.x, p_cb->loc_publ_key.x, p_cb->local_random, 0, + p_cb->commitment); + break; + default: + SMP_TRACE_ERROR("Association Model = %d is not used in LE SC", + p_cb->selected_association_model); + return; + } + + SMP_TRACE_EVENT ("local commitment calculation is completed"); +} + +/******************************************************************************* +** +** Function smp_calculate_peer_commitment +** +** Description The function calculates and saves peer commmitment at the +** provided output buffer. +** +** Returns void +** +*******************************************************************************/ +void smp_calculate_peer_commitment(tSMP_CB *p_cb, BT_OCTET16 output_buf) +{ + UINT8 ri; + + SMP_TRACE_DEBUG ("%s", __FUNCTION__); + + switch (p_cb->selected_association_model) + { + case SMP_MODEL_SEC_CONN_JUSTWORKS: + case SMP_MODEL_SEC_CONN_NUM_COMP: + if (p_cb->role == HCI_ROLE_SLAVE) + SMP_TRACE_WARNING ("peer commitment calc on slave is not expected \ + for Just Works/Numeric Comparison models"); + smp_calculate_f4(p_cb->peer_publ_key.x, p_cb->loc_publ_key.x, p_cb->rrand, 0, + output_buf); + break; + case SMP_MODEL_SEC_CONN_PASSKEY_ENT: + case SMP_MODEL_SEC_CONN_PASSKEY_DISP: + ri = smp_calculate_random_input(p_cb->peer_random, p_cb->round); + smp_calculate_f4(p_cb->peer_publ_key.x, p_cb->loc_publ_key.x, p_cb->rrand, ri, + output_buf); + break; + case SMP_MODEL_SEC_CONN_OOB: + smp_calculate_f4(p_cb->peer_publ_key.x, p_cb->peer_publ_key.x, p_cb->peer_random, 0, + output_buf); + break; + default: + SMP_TRACE_ERROR("Association Model = %d is not used in LE SC", + p_cb->selected_association_model); + return; + } + + SMP_TRACE_EVENT ("peer commitment calculation is completed"); +} + +/******************************************************************************* +** +** Function smp_calculate_f4 +** +** Description The function calculates +** C = f4(U, V, X, Z) = AES-CMAC (U||V||Z) +** X +** where +** input: U is 256 bit, +** V is 256 bit, +** X is 128 bit, +** Z is 8 bit, +** output: C is 128 bit. +** +** Returns void +** +** Note The LSB is the first octet, the MSB is the last octet of +** the AES-CMAC input/output stream. +** +*******************************************************************************/ +void smp_calculate_f4(UINT8 *u, UINT8 *v, UINT8 *x, UINT8 z, UINT8 *c) +{ + UINT8 msg_len = BT_OCTET32_LEN /* U size */ + BT_OCTET32_LEN /* V size */ + 1 /* Z size */; + UINT8 msg[BT_OCTET32_LEN + BT_OCTET32_LEN + 1]; + UINT8 key[BT_OCTET16_LEN]; + UINT8 cmac[BT_OCTET16_LEN]; + UINT8 *p = NULL; +#if SMP_DEBUG == TRUE + UINT8 *p_prnt = NULL; +#endif + + SMP_TRACE_DEBUG ("%s", __FUNCTION__); + +#if SMP_DEBUG == TRUE + p_prnt = u; + smp_debug_print_nbyte_little_endian (p_prnt, (const UINT8 *)"U", BT_OCTET32_LEN); + p_prnt = v; + smp_debug_print_nbyte_little_endian (p_prnt, (const UINT8 *)"V", BT_OCTET32_LEN); + p_prnt = x; + smp_debug_print_nbyte_little_endian (p_prnt, (const UINT8 *)"X", BT_OCTET16_LEN); + p_prnt = &z; + smp_debug_print_nbyte_little_endian (p_prnt, (const UINT8 *)"Z", 1); +#endif + + p = msg; + UINT8_TO_STREAM(p, z); + ARRAY_TO_STREAM(p, v, BT_OCTET32_LEN); + ARRAY_TO_STREAM(p, u, BT_OCTET32_LEN); +#if SMP_DEBUG == TRUE + p_prnt = msg; + smp_debug_print_nbyte_little_endian (p_prnt, (const UINT8 *)"M", msg_len); +#endif + + p = key; + ARRAY_TO_STREAM(p, x, BT_OCTET16_LEN); +#if SMP_DEBUG == TRUE + p_prnt = key; + smp_debug_print_nbyte_little_endian (p_prnt, (const UINT8 *)"K", BT_OCTET16_LEN); +#endif + + aes_cipher_msg_auth_code(key, msg, msg_len, BT_OCTET16_LEN, cmac); +#if SMP_DEBUG == TRUE + p_prnt = cmac; + smp_debug_print_nbyte_little_endian (p_prnt, (const UINT8 *)"AES_CMAC", BT_OCTET16_LEN); +#endif + + p = c; + ARRAY_TO_STREAM(p, cmac, BT_OCTET16_LEN); +} + +/******************************************************************************* +** +** Function smp_calculate_numeric_comparison_display_number +** +** Description The function calculates and saves number to display in numeric +** comparison association mode. +** +** Returns void +** +*******************************************************************************/ +void smp_calculate_numeric_comparison_display_number(tSMP_CB *p_cb, + tSMP_INT_DATA *p_data) +{ + SMP_TRACE_DEBUG ("%s", __func__); + + if (p_cb->role == HCI_ROLE_MASTER) + { + p_cb->number_to_display = + smp_calculate_g2(p_cb->loc_publ_key.x, p_cb->peer_publ_key.x, p_cb->rand, + p_cb->rrand); + } + else + { + p_cb->number_to_display = + smp_calculate_g2(p_cb->peer_publ_key.x, p_cb->loc_publ_key.x, p_cb->rrand, + p_cb->rand); + } + + if (p_cb->number_to_display >= (BTM_MAX_PASSKEY_VAL + 1)) + { + UINT8 reason; + reason = p_cb->failure = SMP_PAIR_FAIL_UNKNOWN; + smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &reason); + return; + } + + SMP_TRACE_EVENT("Number to display in numeric comparison = %d", p_cb->number_to_display); + p_cb->cb_evt = SMP_NC_REQ_EVT; + smp_sm_event(p_cb, SMP_SC_DSPL_NC_EVT, &p_cb->number_to_display); + return; +} + +/******************************************************************************* +** +** Function smp_calculate_g2 +** +** Description The function calculates +** g2(U, V, X, Y) = AES-CMAC (U||V||Y) mod 2**32 mod 10**6 +** X +** and +** Vres = g2(U, V, X, Y) mod 10**6 +** where +** input: U is 256 bit, +** V is 256 bit, +** X is 128 bit, +** Y is 128 bit, +** +** Returns Vres. +** Expected value has to be in the range [0 - 999999] i.e. [0 - 0xF423F]. +** Vres = 1000000 means that the calculation fails. +** +** Note The LSB is the first octet, the MSB is the last octet of +** the AES-CMAC input/output stream. +** +*******************************************************************************/ +UINT32 smp_calculate_g2(UINT8 *u, UINT8 *v, UINT8 *x, UINT8 *y) +{ + UINT8 msg_len = BT_OCTET32_LEN /* U size */ + BT_OCTET32_LEN /* V size */ + + BT_OCTET16_LEN /* Y size */; + UINT8 msg[BT_OCTET32_LEN + BT_OCTET32_LEN + BT_OCTET16_LEN]; + UINT8 key[BT_OCTET16_LEN]; + UINT8 cmac[BT_OCTET16_LEN]; + UINT8 *p = NULL; + UINT32 vres; +#if SMP_DEBUG == TRUE + UINT8 *p_prnt = NULL; +#endif + + SMP_TRACE_DEBUG ("%s", __FUNCTION__); + + p = msg; + ARRAY_TO_STREAM(p, y, BT_OCTET16_LEN); + ARRAY_TO_STREAM(p, v, BT_OCTET32_LEN); + ARRAY_TO_STREAM(p, u, BT_OCTET32_LEN); +#if SMP_DEBUG == TRUE + p_prnt = u; + smp_debug_print_nbyte_little_endian (p_prnt, (const UINT8 *)"U", BT_OCTET32_LEN); + p_prnt = v; + smp_debug_print_nbyte_little_endian (p_prnt, (const UINT8 *)"V", BT_OCTET32_LEN); + p_prnt = x; + smp_debug_print_nbyte_little_endian (p_prnt, (const UINT8 *)"X", BT_OCTET16_LEN); + p_prnt = y; + smp_debug_print_nbyte_little_endian (p_prnt, (const UINT8 *)"Y", BT_OCTET16_LEN); +#endif + + p = key; + ARRAY_TO_STREAM(p, x, BT_OCTET16_LEN); +#if SMP_DEBUG == TRUE + p_prnt = key; + smp_debug_print_nbyte_little_endian (p_prnt, (const UINT8 *)"K", BT_OCTET16_LEN); +#endif + + if(!aes_cipher_msg_auth_code(key, msg, msg_len, BT_OCTET16_LEN, cmac)) + { + SMP_TRACE_ERROR("%s failed",__FUNCTION__); + return (BTM_MAX_PASSKEY_VAL + 1); + } + +#if SMP_DEBUG == TRUE + p_prnt = cmac; + smp_debug_print_nbyte_little_endian (p_prnt, (const UINT8 *)"AES-CMAC", BT_OCTET16_LEN); +#endif + + /* vres = cmac mod 2**32 mod 10**6 */ + p = &cmac[0]; + STREAM_TO_UINT32(vres, p); +#if SMP_DEBUG == TRUE + p_prnt = (UINT8 *) &vres; + smp_debug_print_nbyte_little_endian (p_prnt, (const UINT8 *)"cmac mod 2**32", 4); +#endif + + while (vres > BTM_MAX_PASSKEY_VAL) + vres -= (BTM_MAX_PASSKEY_VAL + 1); +#if SMP_DEBUG == TRUE + p_prnt = (UINT8 *) &vres; + smp_debug_print_nbyte_little_endian (p_prnt, (const UINT8 *)"cmac mod 2**32 mod 10**6", 4); +#endif + + SMP_TRACE_ERROR("Value for numeric comparison = %d", vres); + return vres; +} + +/******************************************************************************* +** +** Function smp_calculate_f5 +** +** Description The function provides two AES-CMAC that are supposed to be used as +** - MacKey (MacKey is used in pairing DHKey check calculation); +** - LTK (LTK is used to ecrypt the link after completion of Phase 2 +** and on reconnection, to derive BR/EDR LK). +** The function inputs are W, N1, N2, A1, A2. +** F5 rules: +** - the value used as key in MacKey/LTK (T) is calculated +** (function smp_calculate_f5_key(...)); +** The formula is: +** T = AES-CMAC (W) +** salt +** where salt is internal parameter of smp_calculate_f5_key(...). +** - MacKey and LTK are calculated as AES-MAC values received with the +** key T calculated in the previous step and the plaintext message +** built from the external parameters N1, N2, A1, A2 and the internal +** parameters counter, keyID, length. +** The function smp_calculate_f5_mackey_or_long_term_key(...) is used in the +** calculations. +** The same formula is used in calculation of MacKey and LTK and the +** same parameter values except the value of the internal parameter +** counter: +** - in MacKey calculations the value is 0; +** - in LTK calculations the value is 1. +** MacKey = AES-CMAC (Counter=0||keyID||N1||N2||A1||A2||Length=256) +** T +** LTK = AES-CMAC (Counter=1||keyID||N1||N2||A1||A2||Length=256) +** T +** The parameters are +** input: +** W is 256 bits, +** N1 is 128 bits, +** N2 is 128 bits, +** A1 is 56 bit, +** A2 is 56 bit. +** internal: +** Counter is 8 bits, its value is 0 for MacKey, +** 1 for LTK; +** KeyId is 32 bits, its value is +** 0x62746c65 (MSB~LSB); +** Length is 16 bits, its value is 0x0100 +** (MSB~LSB). +** output: +** MacKey is 128 bits; +** LTK is 128 bits +** +** Returns FALSE if out of resources, TRUE in other cases. +** +** Note The LSB is the first octet, the MSB is the last octet of +** the AES-CMAC input/output stream. +** +*******************************************************************************/ +BOOLEAN smp_calculate_f5(UINT8 *w, UINT8 *n1, UINT8 *n2, UINT8 *a1, UINT8 *a2, + UINT8 *mac_key, UINT8 *ltk) +{ + BT_OCTET16 t; /* AES-CMAC output in smp_calculate_f5_key(...), key in */ + /* smp_calculate_f5_mackey_or_long_term_key(...) */ +#if SMP_DEBUG == TRUE + UINT8 *p_prnt = NULL; +#endif + /* internal parameters: */ + + /* + counter is 0 for MacKey, + is 1 for LTK + */ + UINT8 counter_mac_key[1] = {0}; + UINT8 counter_ltk[1] = {1}; + /* + keyID 62746c65 + */ + UINT8 key_id[4] = {0x65, 0x6c, 0x74, 0x62}; + /* + length 0100 + */ + UINT8 length[2] = {0x00, 0x01}; + + SMP_TRACE_DEBUG ("%s", __FUNCTION__); +#if SMP_DEBUG == TRUE + p_prnt = w; + smp_debug_print_nbyte_little_endian (p_prnt, (const UINT8 *)"W", BT_OCTET32_LEN); + p_prnt = n1; + smp_debug_print_nbyte_little_endian (p_prnt, (const UINT8 *)"N1", BT_OCTET16_LEN); + p_prnt = n2; + smp_debug_print_nbyte_little_endian (p_prnt, (const UINT8 *)"N2", BT_OCTET16_LEN); + p_prnt = a1; + smp_debug_print_nbyte_little_endian (p_prnt, (const UINT8 *)"A1", 7); + p_prnt = a2; + smp_debug_print_nbyte_little_endian (p_prnt,(const UINT8 *) "A2", 7); +#endif + + if (!smp_calculate_f5_key(w, t)) + { + SMP_TRACE_ERROR("%s failed to calc T",__FUNCTION__); + return FALSE; + } +#if SMP_DEBUG == TRUE + p_prnt = t; + smp_debug_print_nbyte_little_endian (p_prnt, (const UINT8 *)"T", BT_OCTET16_LEN); +#endif + + if (!smp_calculate_f5_mackey_or_long_term_key(t, counter_mac_key, key_id, n1, n2, a1, a2, + length, mac_key)) + { + SMP_TRACE_ERROR("%s failed to calc MacKey", __FUNCTION__); + return FALSE; + } +#if SMP_DEBUG == TRUE + p_prnt = mac_key; + smp_debug_print_nbyte_little_endian (p_prnt, (const UINT8 *)"MacKey", BT_OCTET16_LEN); +#endif + + if (!smp_calculate_f5_mackey_or_long_term_key(t, counter_ltk, key_id, n1, n2, a1, a2, + length, ltk)) + { + SMP_TRACE_ERROR("%s failed to calc LTK",__FUNCTION__); + return FALSE; + } +#if SMP_DEBUG == TRUE + p_prnt = ltk; + smp_debug_print_nbyte_little_endian (p_prnt, (const UINT8 *)"LTK", BT_OCTET16_LEN); +#endif + + return TRUE; +} + +/******************************************************************************* +** +** Function smp_calculate_f5_mackey_or_long_term_key +** +** Description The function calculates the value of MacKey or LTK by the rules +** defined for f5 function. +** At the moment exactly the same formula is used to calculate +** LTK and MacKey. +** The difference is the value of input parameter Counter: +** - in MacKey calculations the value is 0; +** - in LTK calculations the value is 1. +** The formula: +** mac = AES-CMAC (Counter||keyID||N1||N2||A1||A2||Length) +** T +** where +** input: T is 256 bits; +** Counter is 8 bits, its value is 0 for MacKey, +** 1 for LTK; +** keyID is 32 bits, its value is 0x62746c65; +** N1 is 128 bits; +** N2 is 128 bits; +** A1 is 56 bits; +** A2 is 56 bits; +** Length is 16 bits, its value is 0x0100 +** output: LTK is 128 bit. +** +** Returns FALSE if out of resources, TRUE in other cases. +** +** Note The LSB is the first octet, the MSB is the last octet of +** the AES-CMAC input/output stream. +** +*******************************************************************************/ +BOOLEAN smp_calculate_f5_mackey_or_long_term_key(UINT8 *t, UINT8 *counter, + UINT8 *key_id, UINT8 *n1, UINT8 *n2, UINT8 *a1, UINT8 *a2, + UINT8 *length, UINT8 *mac) +{ + UINT8 *p = NULL; + UINT8 cmac[BT_OCTET16_LEN]; + UINT8 key[BT_OCTET16_LEN]; + UINT8 msg_len = 1 /* Counter size */ + 4 /* keyID size */ + + BT_OCTET16_LEN /* N1 size */ + BT_OCTET16_LEN /* N2 size */ + + 7 /* A1 size*/ + 7 /* A2 size*/ + 2 /* Length size */; + UINT8 msg[1 + 4 + BT_OCTET16_LEN + BT_OCTET16_LEN + 7 + 7 + 2]; + BOOLEAN ret = TRUE; +#if SMP_DEBUG == TRUE + UINT8 *p_prnt = NULL; +#endif + + SMP_TRACE_DEBUG ("%s", __FUNCTION__); +#if SMP_DEBUG == TRUE + p_prnt = t; + smp_debug_print_nbyte_little_endian (p_prnt, (const UINT8 *)"T", BT_OCTET16_LEN); + p_prnt = counter; + smp_debug_print_nbyte_little_endian (p_prnt, (const UINT8 *)"Counter", 1); + p_prnt = key_id; + smp_debug_print_nbyte_little_endian (p_prnt, (const UINT8 *)"KeyID", 4); + p_prnt = n1; + smp_debug_print_nbyte_little_endian (p_prnt, (const UINT8 *)"N1", BT_OCTET16_LEN); + p_prnt = n2; + smp_debug_print_nbyte_little_endian (p_prnt, (const UINT8 *)"N2", BT_OCTET16_LEN); + p_prnt = a1; + smp_debug_print_nbyte_little_endian (p_prnt, (const UINT8 *)"A1", 7); + p_prnt = a2; + smp_debug_print_nbyte_little_endian (p_prnt, (const UINT8 *)"A2", 7); + p_prnt = length; + smp_debug_print_nbyte_little_endian (p_prnt, (const UINT8 *)"Length", 2); +#endif + + p = key; + ARRAY_TO_STREAM(p, t, BT_OCTET16_LEN); +#if SMP_DEBUG == TRUE + p_prnt = key; + smp_debug_print_nbyte_little_endian (p_prnt, (const UINT8 *)"K", BT_OCTET16_LEN); +#endif + p = msg; + ARRAY_TO_STREAM(p, length, 2); + ARRAY_TO_STREAM(p, a2, 7); + ARRAY_TO_STREAM(p, a1, 7); + ARRAY_TO_STREAM(p, n2, BT_OCTET16_LEN); + ARRAY_TO_STREAM(p, n1, BT_OCTET16_LEN); + ARRAY_TO_STREAM(p, key_id, 4); + ARRAY_TO_STREAM(p, counter, 1); +#if SMP_DEBUG == TRUE + p_prnt = msg; + smp_debug_print_nbyte_little_endian (p_prnt, (const UINT8 *)"M", msg_len); +#endif + + if (!aes_cipher_msg_auth_code(key, msg, msg_len, BT_OCTET16_LEN, cmac)) + { + SMP_TRACE_ERROR("%s failed", __FUNCTION__); + ret = FALSE; + } + +#if SMP_DEBUG == TRUE + p_prnt = cmac; + smp_debug_print_nbyte_little_endian (p_prnt, (const UINT8 *)"AES-CMAC", BT_OCTET16_LEN); +#endif + + p = mac; + ARRAY_TO_STREAM(p, cmac, BT_OCTET16_LEN); + return ret; +} + +/******************************************************************************* +** +** Function smp_calculate_f5_key +** +** Description The function calculates key T used in calculation of +** MacKey and LTK (f5 output is defined as MacKey || LTK). +** T = AES-CMAC (W) +** salt +** where +** Internal: salt is 128 bit. +** input: W is 256 bit. +** Output: T is 128 bit. +** +** Returns FALSE if out of resources, TRUE in other cases. +** +** Note The LSB is the first octet, the MSB is the last octet of +** the AES-CMAC input/output stream. +** +*******************************************************************************/ +BOOLEAN smp_calculate_f5_key(UINT8 *w, UINT8 *t) +{ + UINT8 *p = NULL; + /* Please see 2.2.7 LE Secure Connections Key Generation Function f5 */ + /* + salt: 6C88 8391 AAF5 A538 6037 0BDB 5A60 83BE + */ + BT_OCTET16 salt = { + 0xBE, 0x83, 0x60, 0x5A, 0xDB, 0x0B, 0x37, 0x60, + 0x38, 0xA5, 0xF5, 0xAA, 0x91, 0x83, 0x88, 0x6C + }; +#if SMP_DEBUG == TRUE + UINT8 *p_prnt = NULL; +#endif + + SMP_TRACE_DEBUG ("%s", __FUNCTION__); +#if SMP_DEBUG == TRUE + p_prnt = salt; + smp_debug_print_nbyte_little_endian (p_prnt, (const UINT8 *)"salt", BT_OCTET16_LEN); + p_prnt = w; + smp_debug_print_nbyte_little_endian (p_prnt, (const UINT8 *)"W", BT_OCTET32_LEN); +#endif + + BT_OCTET16 key; + BT_OCTET32 msg; + + p = key; + ARRAY_TO_STREAM(p, salt, BT_OCTET16_LEN); + p = msg; + ARRAY_TO_STREAM(p, w, BT_OCTET32_LEN); +#if SMP_DEBUG == TRUE + p_prnt = key; + smp_debug_print_nbyte_little_endian (p_prnt, (const UINT8 *)"K", BT_OCTET16_LEN); + p_prnt = msg; + smp_debug_print_nbyte_little_endian (p_prnt, (const UINT8 *)"M", BT_OCTET32_LEN); +#endif + + BT_OCTET16 cmac; + BOOLEAN ret = TRUE; + if (!aes_cipher_msg_auth_code(key, msg, BT_OCTET32_LEN, BT_OCTET16_LEN, cmac)) + { + SMP_TRACE_ERROR("%s failed", __FUNCTION__); + ret = FALSE; + } + +#if SMP_DEBUG == TRUE + p_prnt = cmac; + smp_debug_print_nbyte_little_endian (p_prnt, (const UINT8 *)"AES-CMAC", BT_OCTET16_LEN); +#endif + + p = t; + ARRAY_TO_STREAM(p, cmac, BT_OCTET16_LEN); + return ret; +} + +/******************************************************************************* +** +** Function smp_calculate_local_dhkey_check +** +** Description The function calculates and saves local device DHKey check +** value in CB. +** Before doing this it calls smp_calculate_f5_mackey_and_long_term_key(...). +** to calculate MacKey and LTK. +** MacKey is used in dhkey calculation. +** +** Returns void +** +*******************************************************************************/ +void smp_calculate_local_dhkey_check(tSMP_CB *p_cb, tSMP_INT_DATA *p_data) +{ + UINT8 iocap[3], a[7], b[7]; + + SMP_TRACE_DEBUG ("%s", __FUNCTION__); + + smp_calculate_f5_mackey_and_long_term_key(p_cb); + + smp_collect_local_io_capabilities(iocap, p_cb); + + smp_collect_local_ble_address(a, p_cb); + smp_collect_peer_ble_address(b, p_cb); + smp_calculate_f6(p_cb->mac_key, p_cb->rand, p_cb->rrand, p_cb->peer_random, iocap, a, b, + p_cb->dhkey_check); + + SMP_TRACE_EVENT ("local DHKey check calculation is completed"); +} + +/******************************************************************************* +** +** Function smp_calculate_peer_dhkey_check +** +** Description The function calculates peer device DHKey check value. +** +** Returns void +** +*******************************************************************************/ +void smp_calculate_peer_dhkey_check(tSMP_CB *p_cb, tSMP_INT_DATA *p_data) +{ + UINT8 iocap[3], a[7], b[7]; + BT_OCTET16 param_buf; + BOOLEAN ret; + tSMP_KEY key; + tSMP_STATUS status = SMP_PAIR_FAIL_UNKNOWN; + + SMP_TRACE_DEBUG ("%s", __FUNCTION__); + + smp_collect_peer_io_capabilities(iocap, p_cb); + + smp_collect_local_ble_address(a, p_cb); + smp_collect_peer_ble_address(b, p_cb); + ret = smp_calculate_f6(p_cb->mac_key, p_cb->rrand, p_cb->rand, p_cb->local_random, iocap, + b, a, param_buf); + + if (ret) + { + SMP_TRACE_EVENT ("peer DHKey check calculation is completed"); +#if (SMP_DEBUG == TRUE) + smp_debug_print_nbyte_little_endian (param_buf, (const UINT8 *)"peer DHKey check", + BT_OCTET16_LEN); +#endif + key.key_type = SMP_KEY_TYPE_PEER_DHK_CHCK; + key.p_data = param_buf; + smp_sm_event(p_cb, SMP_SC_KEY_READY_EVT, &key); + } + else + { + SMP_TRACE_EVENT ("peer DHKey check calculation failed"); + smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &status); + } +} + +/******************************************************************************* +** +** Function smp_calculate_f6 +** +** Description The function calculates +** C = f6(W, N1, N2, R, IOcap, A1, A2) = AES-CMAC (N1||N2||R||IOcap||A1||A2) +** W +** where +** input: W is 128 bit, +** N1 is 128 bit, +** N2 is 128 bit, +** R is 128 bit, +** IOcap is 24 bit, +** A1 is 56 bit, +** A2 is 56 bit, +** output: C is 128 bit. +** +** Returns FALSE if out of resources, TRUE in other cases. +** +** Note The LSB is the first octet, the MSB is the last octet of +** the AES-CMAC input/output stream. +** +*******************************************************************************/ +BOOLEAN smp_calculate_f6(UINT8 *w, UINT8 *n1, UINT8 *n2, UINT8 *r, UINT8 *iocap, UINT8 *a1, + UINT8 *a2, UINT8 *c) +{ + UINT8 *p = NULL; + UINT8 msg_len = BT_OCTET16_LEN /* N1 size */ + BT_OCTET16_LEN /* N2 size */ + + BT_OCTET16_LEN /* R size */ + 3 /* IOcap size */ + 7 /* A1 size*/ + + 7 /* A2 size*/; + UINT8 msg[BT_OCTET16_LEN + BT_OCTET16_LEN + BT_OCTET16_LEN + 3 + 7 + 7]; +#if SMP_DEBUG == TRUE + UINT8 *p_print = NULL; +#endif + + SMP_TRACE_DEBUG ("%s", __FUNCTION__); +#if SMP_DEBUG == TRUE + p_print = w; + smp_debug_print_nbyte_little_endian (p_print, (const UINT8 *)"W", BT_OCTET16_LEN); + p_print = n1; + smp_debug_print_nbyte_little_endian (p_print, (const UINT8 *)"N1", BT_OCTET16_LEN); + p_print = n2; + smp_debug_print_nbyte_little_endian (p_print, (const UINT8 *)"N2", BT_OCTET16_LEN); + p_print = r; + smp_debug_print_nbyte_little_endian (p_print, (const UINT8 *)"R", BT_OCTET16_LEN); + p_print = iocap; + smp_debug_print_nbyte_little_endian (p_print, (const UINT8 *)"IOcap", 3); + p_print = a1; + smp_debug_print_nbyte_little_endian (p_print, (const UINT8 *)"A1", 7); + p_print = a2; + smp_debug_print_nbyte_little_endian (p_print, (const UINT8 *)"A2", 7); +#endif + + UINT8 cmac[BT_OCTET16_LEN]; + UINT8 key[BT_OCTET16_LEN]; + + p = key; + ARRAY_TO_STREAM(p, w, BT_OCTET16_LEN); +#if SMP_DEBUG == TRUE + p_print = key; + smp_debug_print_nbyte_little_endian (p_print, (const UINT8 *)"K", BT_OCTET16_LEN); +#endif + + p = msg; + ARRAY_TO_STREAM(p, a2, 7); + ARRAY_TO_STREAM(p, a1, 7); + ARRAY_TO_STREAM(p, iocap, 3); + ARRAY_TO_STREAM(p, r, BT_OCTET16_LEN); + ARRAY_TO_STREAM(p, n2, BT_OCTET16_LEN); + ARRAY_TO_STREAM(p, n1, BT_OCTET16_LEN); +#if SMP_DEBUG == TRUE + p_print = msg; + smp_debug_print_nbyte_little_endian (p_print, (const UINT8 *)"M", msg_len); +#endif + + BOOLEAN ret = TRUE; + if(!aes_cipher_msg_auth_code(key, msg, msg_len, BT_OCTET16_LEN, cmac)) + { + SMP_TRACE_ERROR("%s failed", __FUNCTION__); + ret = FALSE; + } + +#if SMP_DEBUG == TRUE + p_print = cmac; + smp_debug_print_nbyte_little_endian (p_print, (const UINT8 *)"AES-CMAC", BT_OCTET16_LEN); +#endif + + p = c; + ARRAY_TO_STREAM(p, cmac, BT_OCTET16_LEN); + return ret; +} + +/******************************************************************************* +** +** Function smp_calculate_link_key_from_long_term_key +** +** Description The function calculates and saves BR/EDR link key derived from +** LE SC LTK. +** +** Returns FALSE if out of resources, TRUE in other cases. +** +*******************************************************************************/ +BOOLEAN smp_calculate_link_key_from_long_term_key(tSMP_CB *p_cb) +{ + tBTM_SEC_DEV_REC *p_dev_rec; + BD_ADDR bda_for_lk; + tBLE_ADDR_TYPE conn_addr_type; + + SMP_TRACE_DEBUG ("%s", __func__); + + if (p_cb->id_addr_rcvd && p_cb->id_addr_type == BLE_ADDR_PUBLIC) + { + SMP_TRACE_DEBUG ("Use rcvd identity address as BD_ADDR of LK rcvd identity address"); + memcpy(bda_for_lk, p_cb->id_addr, BD_ADDR_LEN); + } + else if ((BTM_ReadRemoteConnectionAddr(p_cb->pairing_bda, bda_for_lk, &conn_addr_type)) && + conn_addr_type == BLE_ADDR_PUBLIC) + { + SMP_TRACE_DEBUG ("Use rcvd connection address as BD_ADDR of LK"); + } + else + { + SMP_TRACE_WARNING ("Don't have peer public address to associate with LK"); + return FALSE; + } + + if ((p_dev_rec = btm_find_dev (p_cb->pairing_bda)) == NULL) + { + SMP_TRACE_ERROR("%s failed to find Security Record", __func__); + return FALSE; + } + + BT_OCTET16 intermediate_link_key; + BOOLEAN ret = TRUE; + + ret = smp_calculate_h6(p_cb->ltk, (UINT8 *)"1pmt" /* reversed "tmp1" */,intermediate_link_key); + if (!ret) + { + SMP_TRACE_ERROR("%s failed to derive intermediate_link_key", __func__); + return ret; + } + + BT_OCTET16 link_key; + ret = smp_calculate_h6(intermediate_link_key, (UINT8 *) "rbel" /* reversed "lebr" */, link_key); + if (!ret) + { + SMP_TRACE_ERROR("%s failed", __func__); + } + else + { + UINT8 link_key_type; + if (btm_cb.security_mode == BTM_SEC_MODE_SC) + { + /* Secure Connections Only Mode */ + link_key_type = BTM_LKEY_TYPE_AUTH_COMB_P_256; + } + else if (controller_get_interface()->supports_secure_connections()) + { + /* both transports are SC capable */ + if (p_cb->sec_level == SMP_SEC_AUTHENTICATED) + link_key_type = BTM_LKEY_TYPE_AUTH_COMB_P_256; + else + link_key_type = BTM_LKEY_TYPE_UNAUTH_COMB_P_256; + } + else if (btm_cb.security_mode == BTM_SEC_MODE_SP) + { + /* BR/EDR transport is SSP capable */ + if (p_cb->sec_level == SMP_SEC_AUTHENTICATED) + link_key_type = BTM_LKEY_TYPE_AUTH_COMB; + else + link_key_type = BTM_LKEY_TYPE_UNAUTH_COMB; + } + else + { + SMP_TRACE_ERROR ("%s failed to update link_key. Sec Mode = %d, sm4 = 0x%02x", + __func__, btm_cb.security_mode, p_dev_rec->sm4); + return FALSE; + } + + link_key_type += BTM_LTK_DERIVED_LKEY_OFFSET; + + UINT8 *p; + BT_OCTET16 notif_link_key; + p = notif_link_key; + ARRAY16_TO_STREAM(p, link_key); + + btm_sec_link_key_notification (bda_for_lk, notif_link_key, link_key_type); + + SMP_TRACE_EVENT ("%s is completed", __func__); + } + + return ret; +} + +/******************************************************************************* +** +** Function smp_calculate_long_term_key_from_link_key +** +** Description The function calculates and saves SC LTK derived from BR/EDR +** link key. +** +** Returns FALSE if out of resources, TRUE in other cases. +** +*******************************************************************************/ +BOOLEAN smp_calculate_long_term_key_from_link_key(tSMP_CB *p_cb) +{ + BOOLEAN ret = TRUE; + tBTM_SEC_DEV_REC *p_dev_rec; + UINT8 rev_link_key[16]; + + SMP_TRACE_DEBUG ("%s", __FUNCTION__); + + if ((p_dev_rec = btm_find_dev (p_cb->pairing_bda)) == NULL) + { + SMP_TRACE_ERROR("%s failed to find Security Record",__FUNCTION__); + return FALSE; + } + + UINT8 br_link_key_type; + if ((br_link_key_type = BTM_SecGetDeviceLinkKeyType (p_cb->pairing_bda)) + == BTM_LKEY_TYPE_IGNORE) + { + SMP_TRACE_ERROR("%s failed to retrieve BR link type",__FUNCTION__); + return FALSE; + } + + if ((br_link_key_type != BTM_LKEY_TYPE_AUTH_COMB_P_256) && + (br_link_key_type != BTM_LKEY_TYPE_UNAUTH_COMB_P_256)) + { + SMP_TRACE_ERROR("%s LE SC LTK can't be derived from LK %d", + __FUNCTION__, br_link_key_type); + return FALSE; + } + + UINT8 *p1; + UINT8 *p2; + p1 = rev_link_key; + p2 = p_dev_rec->link_key; + REVERSE_ARRAY_TO_STREAM(p1, p2, 16); + + BT_OCTET16 intermediate_long_term_key; + /* "tmp2" obtained from the spec */ + ret = smp_calculate_h6(rev_link_key, (UINT8 *) "2pmt" /* reversed "tmp2" */, + intermediate_long_term_key); + + if (!ret) + { + SMP_TRACE_ERROR("%s failed to derive intermediate_long_term_key",__FUNCTION__); + return ret; + } + + /* "brle" obtained from the spec */ + ret = smp_calculate_h6(intermediate_long_term_key, (UINT8 *) "elrb" /* reversed "brle" */, + p_cb->ltk); + + if (!ret) + { + SMP_TRACE_ERROR("%s failed",__FUNCTION__); + } + else + { + p_cb->sec_level = (br_link_key_type == BTM_LKEY_TYPE_AUTH_COMB_P_256) + ? SMP_SEC_AUTHENTICATED : SMP_SEC_UNAUTHENTICATE; + SMP_TRACE_EVENT ("%s is completed",__FUNCTION__); + } + + return ret; +} + +/******************************************************************************* +** +** Function smp_calculate_h6 +** +** Description The function calculates +** C = h6(W, KeyID) = AES-CMAC (KeyID) +** W +** where +** input: W is 128 bit, +** KeyId is 32 bit, +** output: C is 128 bit. +** +** Returns FALSE if out of resources, TRUE in other cases. +** +** Note The LSB is the first octet, the MSB is the last octet of +** the AES-CMAC input/output stream. +** +*******************************************************************************/ +BOOLEAN smp_calculate_h6(UINT8 *w, UINT8 *keyid, UINT8 *c) +{ +#if SMP_DEBUG == TRUE + UINT8 *p_print = NULL; +#endif + + SMP_TRACE_DEBUG ("%s",__FUNCTION__); +#if SMP_DEBUG == TRUE + p_print = w; + smp_debug_print_nbyte_little_endian (p_print, (const UINT8 *)"W", BT_OCTET16_LEN); + p_print = keyid; + smp_debug_print_nbyte_little_endian (p_print, (const UINT8 *)"keyID", 4); +#endif + + UINT8 *p = NULL; + UINT8 key[BT_OCTET16_LEN]; + + p = key; + ARRAY_TO_STREAM(p, w, BT_OCTET16_LEN); + +#if SMP_DEBUG == TRUE + p_print = key; + smp_debug_print_nbyte_little_endian (p_print, (const UINT8 *)"K", BT_OCTET16_LEN); +#endif + + UINT8 msg_len = 4 /* KeyID size */; + UINT8 msg[4]; + + p = msg; + ARRAY_TO_STREAM(p, keyid, 4); + +#if SMP_DEBUG == TRUE + p_print = msg; + smp_debug_print_nbyte_little_endian (p_print,(const UINT8 *) "M", msg_len); +#endif + + BOOLEAN ret = TRUE; + UINT8 cmac[BT_OCTET16_LEN]; + if (!aes_cipher_msg_auth_code(key, msg, msg_len, BT_OCTET16_LEN, cmac)) + { + SMP_TRACE_ERROR("%s failed",__FUNCTION__); + ret = FALSE; + } + +#if SMP_DEBUG == TRUE + p_print = cmac; + smp_debug_print_nbyte_little_endian (p_print, (const UINT8 *)"AES-CMAC", BT_OCTET16_LEN); +#endif + + p = c; + ARRAY_TO_STREAM(p, cmac, BT_OCTET16_LEN); + return ret; +} + +/******************************************************************************* +** +** Function smp_start_nonce_generation +** +** Description This function starts nonce generation. +** +** Returns void +** +*******************************************************************************/ +void smp_start_nonce_generation(tSMP_CB *p_cb) +{ + SMP_TRACE_DEBUG("%s", __FUNCTION__); + p_cb->rand_enc_proc_state = SMP_GEN_NONCE_0_7; + if (!btsnd_hcic_ble_rand((void *)smp_rand_back)) + smp_rand_back(NULL); +} + +/******************************************************************************* +** +** Function smp_finish_nonce_generation +** +** Description This function finishes nonce generation. +** +** Returns void +** +*******************************************************************************/ +void smp_finish_nonce_generation(tSMP_CB *p_cb) +{ + SMP_TRACE_DEBUG("%s", __FUNCTION__); + p_cb->rand_enc_proc_state = SMP_GEN_NONCE_8_15; + if (!btsnd_hcic_ble_rand((void *)smp_rand_back)) + smp_rand_back(NULL); +} + +/******************************************************************************* +** +** Function smp_process_new_nonce +** +** Description This function notifies SM that it has new nonce. +** +** Returns void +** +*******************************************************************************/ +void smp_process_new_nonce(tSMP_CB *p_cb) +{ + SMP_TRACE_DEBUG ("%s round %d", __FUNCTION__, p_cb->round); + smp_sm_event(p_cb, SMP_HAVE_LOC_NONCE_EVT, NULL); +} + +/******************************************************************************* +** +** Function smp_rand_back +** +** Description This function is to process the rand command finished, +** process the random/encrypted number for further action. +** +** Returns void +** +*******************************************************************************/ +static void smp_rand_back(tBTM_RAND_ENC *p) +{ + tSMP_CB *p_cb = &smp_cb; + UINT8 *pp = p->param_buf; + UINT8 failure = SMP_PAIR_FAIL_UNKNOWN; + UINT8 state = p_cb->rand_enc_proc_state & ~0x80; + + SMP_TRACE_DEBUG ("%s state=0x%x", __FUNCTION__, state); + if (p && p->status == HCI_SUCCESS) + { + switch (state) + { + case SMP_GEN_SRAND_MRAND: + memcpy((void *)p_cb->rand, p->param_buf, p->param_len); + smp_generate_rand_cont(p_cb, NULL); + break; + + case SMP_GEN_SRAND_MRAND_CONT: + memcpy((void *)&p_cb->rand[8], p->param_buf, p->param_len); + smp_generate_confirm(p_cb, NULL); + break; + + case SMP_GEN_DIV_LTK: + STREAM_TO_UINT16(p_cb->div, pp); + smp_generate_ltk_cont(p_cb, NULL); + break; + + case SMP_GEN_DIV_CSRK: + STREAM_TO_UINT16(p_cb->div, pp); + smp_compute_csrk(p_cb, NULL); + break; + + case SMP_GEN_TK: + smp_proc_passkey(p_cb, p); + break; + + case SMP_GEN_RAND_V: + memcpy(p_cb->enc_rand, p->param_buf, BT_OCTET8_LEN); + smp_generate_y(p_cb, NULL); + break; + + case SMP_GENERATE_PRIVATE_KEY_0_7: + case SMP_GENERATE_PRIVATE_KEY_8_15: + case SMP_GENERATE_PRIVATE_KEY_16_23: + case SMP_GENERATE_PRIVATE_KEY_24_31: + smp_continue_private_key_creation(p_cb, p); + break; + + case SMP_GEN_NONCE_0_7: + memcpy((void *)p_cb->rand, p->param_buf, p->param_len); + smp_finish_nonce_generation(p_cb); + break; + + case SMP_GEN_NONCE_8_15: + memcpy((void *)&p_cb->rand[8], p->param_buf, p->param_len); + smp_process_new_nonce(p_cb); + break; + } + + return; + } + + SMP_TRACE_ERROR("%s key generation failed: (%d)", __FUNCTION__, p_cb->rand_enc_proc_state); + smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &failure); +} + +#endif + diff --git a/components/bt/bluedroid/stack/smp/smp_l2c.c b/components/bt/bluedroid/stack/smp/smp_l2c.c new file mode 100755 index 0000000000..6f97742c5e --- /dev/null +++ b/components/bt/bluedroid/stack/smp/smp_l2c.c @@ -0,0 +1,342 @@ +/****************************************************************************** + * + * Copyright (C) 1999-2012 Broadcom Corporation + * + * 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 functions for the SMP L2Cap interface + * + ******************************************************************************/ + +#include "bt_target.h" + +#if SMP_INCLUDED == TRUE + +#include +#include "btm_ble_api.h" +#include "l2c_api.h" + +#include "smp_int.h" + + +static void smp_tx_complete_callback(UINT16 cid, UINT16 num_pkt); + +static void smp_connect_callback(UINT16 channel, BD_ADDR bd_addr, BOOLEAN connected, UINT16 reason, + tBT_TRANSPORT transport); +static void smp_data_received(UINT16 channel, BD_ADDR bd_addr, BT_HDR *p_buf); + +static void smp_br_connect_callback(UINT16 channel, BD_ADDR bd_addr, BOOLEAN connected, UINT16 reason, + tBT_TRANSPORT transport); +static void smp_br_data_received(UINT16 channel, BD_ADDR bd_addr, BT_HDR *p_buf); + +/******************************************************************************* +** +** Function smp_l2cap_if_init +** +** Description This function is called during the SMP task startup +** to register interface functions with L2CAP. +** +*******************************************************************************/ +void smp_l2cap_if_init (void) +{ + tL2CAP_FIXED_CHNL_REG fixed_reg; + SMP_TRACE_EVENT ("SMDBG l2c %s", __func__); + fixed_reg.fixed_chnl_opts.mode = L2CAP_FCR_BASIC_MODE; + fixed_reg.fixed_chnl_opts.max_transmit = 0; + fixed_reg.fixed_chnl_opts.rtrans_tout = 0; + fixed_reg.fixed_chnl_opts.mon_tout = 0; + fixed_reg.fixed_chnl_opts.mps = 0; + fixed_reg.fixed_chnl_opts.tx_win_sz = 0; + + fixed_reg.pL2CA_FixedConn_Cb = smp_connect_callback; + fixed_reg.pL2CA_FixedData_Cb = smp_data_received; + fixed_reg.pL2CA_FixedTxComplete_Cb = smp_tx_complete_callback; + + fixed_reg.pL2CA_FixedCong_Cb = NULL; /* do not handle congestion on this channel */ + fixed_reg.default_idle_tout = 60; /* set 60 seconds timeout, 0xffff default idle timeout */ + + L2CA_RegisterFixedChannel (L2CAP_SMP_CID, &fixed_reg); + + fixed_reg.pL2CA_FixedConn_Cb = smp_br_connect_callback; + fixed_reg.pL2CA_FixedData_Cb = smp_br_data_received; + + L2CA_RegisterFixedChannel (L2CAP_SMP_BR_CID, &fixed_reg); +} + +/******************************************************************************* +** +** Function smp_connect_callback +** +** Description This callback function is called by L2CAP to indicate that +** SMP channel is +** connected (conn = TRUE)/disconnected (conn = FALSE). +** +*******************************************************************************/ +static void smp_connect_callback (UINT16 channel, BD_ADDR bd_addr, BOOLEAN connected, UINT16 reason, + tBT_TRANSPORT transport) +{ + tSMP_CB *p_cb = &smp_cb; + tSMP_INT_DATA int_data; + BD_ADDR dummy_bda = {0}; + + SMP_TRACE_EVENT ("SMDBG l2c %s", __FUNCTION__); + + if (transport == BT_TRANSPORT_BR_EDR || memcmp(bd_addr, dummy_bda, BD_ADDR_LEN) == 0) + return; + + if (memcmp(bd_addr, p_cb->pairing_bda, BD_ADDR_LEN) == 0) + { + SMP_TRACE_EVENT ("%s() for pairing BDA: %08x%04x Event: %s", + __FUNCTION__, + (bd_addr[0]<<24)+(bd_addr[1]<<16)+(bd_addr[2]<<8) + bd_addr[3], + (bd_addr[4]<<8)+bd_addr[5], + (connected) ? "connected" : "disconnected"); + + if (connected) + { + if(!p_cb->connect_initialized) + { + p_cb->connect_initialized = TRUE; + /* initiating connection established */ + p_cb->role = L2CA_GetBleConnRole(bd_addr); + + /* initialize local i/r key to be default keys */ + p_cb->local_r_key = p_cb->local_i_key = SMP_SEC_DEFAULT_KEY; + p_cb->loc_auth_req = p_cb->peer_auth_req = SMP_DEFAULT_AUTH_REQ; + p_cb->cb_evt = SMP_IO_CAP_REQ_EVT; + smp_sm_event(p_cb, SMP_L2CAP_CONN_EVT, NULL); + } + } + else + { + int_data.reason = reason; + /* Disconnected while doing security */ + smp_sm_event(p_cb, SMP_L2CAP_DISCONN_EVT, &int_data); + } + } +} + +/******************************************************************************* +** +** Function smp_data_received +** +** Description This function is called when data is received from L2CAP on +** SMP channel. +** +** +** Returns void +** +*******************************************************************************/ +static void smp_data_received(UINT16 channel, BD_ADDR bd_addr, BT_HDR *p_buf) +{ + tSMP_CB *p_cb = &smp_cb; + UINT8 *p = (UINT8 *)(p_buf + 1) + p_buf->offset; + UINT8 cmd ; + SMP_TRACE_EVENT ("SMDBG l2c %s", __FUNCTION__); + + STREAM_TO_UINT8(cmd, p); + + /* sanity check */ + if ((SMP_OPCODE_MAX < cmd) || (SMP_OPCODE_MIN > cmd)) + { + SMP_TRACE_WARNING( "Ignore received command with RESERVED code 0x%02x", cmd); + GKI_freebuf (p_buf); + return; + } + + /* reject the pairing request if there is an on-going SMP pairing */ + if (SMP_OPCODE_PAIRING_REQ == cmd || SMP_OPCODE_SEC_REQ == cmd) + { + if ((p_cb->state == SMP_STATE_IDLE) && (p_cb->br_state == SMP_BR_STATE_IDLE)) + { + p_cb->role = L2CA_GetBleConnRole(bd_addr); + memcpy(&p_cb->pairing_bda[0], bd_addr, BD_ADDR_LEN); + } + else if (memcmp(&bd_addr[0], p_cb->pairing_bda, BD_ADDR_LEN)) + { + GKI_freebuf (p_buf); + smp_reject_unexpected_pairing_command(bd_addr); + return; + } + /* else, out of state pairing request/security request received, passed into SM */ + } + + if (memcmp(&bd_addr[0], p_cb->pairing_bda, BD_ADDR_LEN) == 0) + { + btu_stop_timer (&p_cb->rsp_timer_ent); + btu_start_timer (&p_cb->rsp_timer_ent, BTU_TTYPE_SMP_PAIRING_CMD, + SMP_WAIT_FOR_RSP_TOUT); + + if (cmd == SMP_OPCODE_CONFIRM) + { + SMP_TRACE_DEBUG ("in %s cmd = 0x%02x, peer_auth_req = 0x%02x," + "loc_auth_req = 0x%02x", + __FUNCTION__, cmd, p_cb->peer_auth_req, p_cb->loc_auth_req); + + if ((p_cb->peer_auth_req & SMP_SC_SUPPORT_BIT) && + (p_cb->loc_auth_req & SMP_SC_SUPPORT_BIT)) + { + cmd = SMP_OPCODE_PAIR_COMMITM; + } + } + + p_cb->rcvd_cmd_code = cmd; + p_cb->rcvd_cmd_len = (UINT8) p_buf->len; + smp_sm_event(p_cb, cmd, p); + } + + GKI_freebuf (p_buf); +} + +/******************************************************************************* +** +** Function smp_tx_complete_callback +** +** Description SMP channel tx complete callback +** +*******************************************************************************/ +static void smp_tx_complete_callback (UINT16 cid, UINT16 num_pkt) +{ + tSMP_CB *p_cb = &smp_cb; + + if (p_cb->total_tx_unacked >= num_pkt) + p_cb->total_tx_unacked -= num_pkt; + else + SMP_TRACE_ERROR("Unexpected %s: num_pkt = %d", __func__,num_pkt); + + UINT8 reason = SMP_SUCCESS; + if (p_cb->total_tx_unacked == 0 && p_cb->wait_for_authorization_complete) + { + if (cid == L2CAP_SMP_CID) + smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &reason); + else + smp_br_state_machine_event(p_cb, SMP_BR_AUTH_CMPL_EVT, &reason); + } +} + +/******************************************************************************* +** +** Function smp_br_connect_callback +** +** Description This callback function is called by L2CAP to indicate that +** SMP BR channel is +** connected (conn = TRUE)/disconnected (conn = FALSE). +** +*******************************************************************************/ +static void smp_br_connect_callback(UINT16 channel, BD_ADDR bd_addr, BOOLEAN connected, + UINT16 reason, tBT_TRANSPORT transport) +{ + tSMP_CB *p_cb = &smp_cb; + tSMP_INT_DATA int_data; + + SMP_TRACE_EVENT ("%s", __func__); + + if (transport != BT_TRANSPORT_BR_EDR) + { + SMP_TRACE_WARNING("%s is called on unexpected transport %d", + __func__, transport); + return; + } + + if (!(memcmp(bd_addr, p_cb->pairing_bda, BD_ADDR_LEN) == 0)) + return; + + SMP_TRACE_EVENT ("%s for pairing BDA: %08x%04x Event: %s", + __func__, + (bd_addr[0]<<24)+(bd_addr[1]<<16)+(bd_addr[2]<<8) + bd_addr[3], + (bd_addr[4]<<8)+bd_addr[5], + (connected) ? "connected" : "disconnected"); + + if (connected) + { + if(!p_cb->connect_initialized) + { + p_cb->connect_initialized = TRUE; + /* initialize local i/r key to be default keys */ + p_cb->local_r_key = p_cb->local_i_key = SMP_BR_SEC_DEFAULT_KEY; + p_cb->loc_auth_req = p_cb->peer_auth_req = 0; + p_cb->cb_evt = SMP_BR_KEYS_REQ_EVT; + smp_br_state_machine_event(p_cb, SMP_BR_L2CAP_CONN_EVT, NULL); + } + } + else + { + int_data.reason = reason; + /* Disconnected while doing security */ + smp_br_state_machine_event(p_cb, SMP_BR_L2CAP_DISCONN_EVT, &int_data); + } +} + +/******************************************************************************* +** +** Function smp_br_data_received +** +** Description This function is called when data is received from L2CAP on +** SMP BR channel. +** +** Returns void +** +*******************************************************************************/ +static void smp_br_data_received(UINT16 channel, BD_ADDR bd_addr, BT_HDR *p_buf) +{ + tSMP_CB *p_cb = &smp_cb; + UINT8 *p = (UINT8 *)(p_buf + 1) + p_buf->offset; + UINT8 cmd ; + SMP_TRACE_EVENT ("SMDBG l2c %s", __func__); + + STREAM_TO_UINT8(cmd, p); + + /* sanity check */ + if ((SMP_OPCODE_MAX < cmd) || (SMP_OPCODE_MIN > cmd)) + { + SMP_TRACE_WARNING( "Ignore received command with RESERVED code 0x%02x", cmd); + GKI_freebuf(p_buf); + return; + } + + /* reject the pairing request if there is an on-going SMP pairing */ + if (SMP_OPCODE_PAIRING_REQ == cmd) + { + if ((p_cb->state == SMP_STATE_IDLE) && (p_cb->br_state == SMP_BR_STATE_IDLE)) + { + p_cb->role = HCI_ROLE_SLAVE; + p_cb->smp_over_br = TRUE; + memcpy(&p_cb->pairing_bda[0], bd_addr, BD_ADDR_LEN); + } + else if (memcmp(&bd_addr[0], p_cb->pairing_bda, BD_ADDR_LEN)) + { + GKI_freebuf (p_buf); + smp_reject_unexpected_pairing_command(bd_addr); + return; + } + /* else, out of state pairing request received, passed into State Machine */ + } + + if (memcmp(&bd_addr[0], p_cb->pairing_bda, BD_ADDR_LEN) == 0) + { + btu_stop_timer (&p_cb->rsp_timer_ent); + btu_start_timer (&p_cb->rsp_timer_ent, BTU_TTYPE_SMP_PAIRING_CMD, + SMP_WAIT_FOR_RSP_TOUT); + + p_cb->rcvd_cmd_code = cmd; + p_cb->rcvd_cmd_len = (UINT8) p_buf->len; + smp_br_state_machine_event(p_cb, cmd, p); + } + + GKI_freebuf (p_buf); +} +#endif /* SMP_INCLUDED == TRUE */ diff --git a/components/bt/bluedroid/stack/smp/smp_main.c b/components/bt/bluedroid/stack/smp/smp_main.c new file mode 100755 index 0000000000..2d80343a6f --- /dev/null +++ b/components/bt/bluedroid/stack/smp/smp_main.c @@ -0,0 +1,862 @@ +/****************************************************************************** + * + * Copyright (C) 2003-2012 Broadcom Corporation + * + * 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. + * + ******************************************************************************/ + +#include "bt_target.h" + +#if SMP_INCLUDED == TRUE + +#include +#include "smp_int.h" + +const char *const smp_state_name [] = +{ + "SMP_STATE_IDLE", + "SMP_STATE_WAIT_APP_RSP", + "SMP_STATE_SEC_REQ_PENDING", + "SMP_STATE_PAIR_REQ_RSP", + "SMP_STATE_WAIT_CONFIRM", + "SMP_STATE_CONFIRM", + "SMP_STATE_RAND", + "SMP_STATE_PUBLIC_KEY_EXCH", + "SMP_STATE_SEC_CONN_PHS1_START", + "SMP_STATE_WAIT_COMMITMENT", + "SMP_STATE_WAIT_NONCE", + "SMP_STATE_SEC_CONN_PHS2_START", + "SMP_STATE_WAIT_DHK_CHECK", + "SMP_STATE_DHK_CHECK", + "SMP_STATE_ENCRYPTION_PENDING", + "SMP_STATE_BOND_PENDING", + "SMP_STATE_CREATE_LOCAL_SEC_CONN_OOB_DATA", + "SMP_STATE_MAX" +}; + +const char *const smp_event_name [] = +{ + "PAIRING_REQ_EVT", + "PAIRING_RSP_EVT", + "CONFIRM_EVT", + "RAND_EVT", + "PAIRING_FAILED_EVT", + "ENC_INFO_EVT", + "MASTER_ID_EVT", + "ID_INFO_EVT", + "ID_ADDR_EVT", + "SIGN_INFO_EVT", + "SECURITY_REQ_EVT", + "PAIR_PUBLIC_KEY_EVT", + "PAIR_DHKEY_CHECK_EVT", + "PAIR_KEYPRESS_NOTIFICATION_EVT", + "PAIR_COMMITMENT_EVT", + "KEY_READY_EVT", + "ENCRYPTED_EVT", + "L2CAP_CONN_EVT", + "L2CAP_DISCONN_EVT", + "API_IO_RSP_EVT", + "API_SEC_GRANT_EVT", + "TK_REQ_EVT", + "AUTH_CMPL_EVT", + "ENC_REQ_EVT", + "BOND_REQ_EVT", + "DISCARD_SEC_REQ_EVT", + "PUBLIC_KEY_EXCHANGE_REQ_EVT", + "LOCAL_PUBLIC_KEY_CRTD_EVT", + "BOTH_PUBLIC_KEYS_RCVD_EVT", + "SEC_CONN_DHKEY_COMPLETE_EVT", + "HAVE_LOCAL_NONCE_EVT", + "SEC_CONN_PHASE1_CMPLT_EVT", + "SEC_CONN_CALC_NC_EVT", + "SEC_CONN_DISPLAY_NC_EVT", + "SEC_CONN_OK_EVT", + "SEC_CONN_2_DHCK_CHECKS_PRESENT_EVT", + "SEC_CONN_KEY_READY_EVT", + "KEYPRESS_NOTIFICATION_EVT", + "SEC_CONN_OOB_DATA_EVT", + "CREATE_LOCAL_SEC_CONN_OOB_DATA_EVT", + "OUT_OF_RANGE_EVT" +}; + +const char *smp_get_event_name(tSMP_EVENT event); +const char *smp_get_state_name(tSMP_STATE state); + +#define SMP_SM_IGNORE 0 +#define SMP_NUM_ACTIONS 2 +#define SMP_SME_NEXT_STATE 2 +#define SMP_SM_NUM_COLS 3 + +typedef const UINT8(*tSMP_SM_TBL)[SMP_SM_NUM_COLS]; + +enum +{ + SMP_PROC_SEC_REQ, + SMP_SEND_PAIR_REQ, + SMP_SEND_PAIR_RSP, + SMP_SEND_CONFIRM, + SMP_SEND_PAIR_FAIL, + SMP_SEND_RAND, + SMP_SEND_ENC_INFO, + SMP_SEND_ID_INFO, + SMP_SEND_LTK_REPLY, + SMP_PROC_PAIR_CMD, + SMP_PROC_PAIR_FAIL, + SMP_PROC_CONFIRM, + SMP_PROC_RAND, + SMP_PROC_ENC_INFO, + SMP_PROC_MASTER_ID, + SMP_PROC_ID_INFO, + SMP_PROC_ID_ADDR, + SMP_PROC_SRK_INFO, + SMP_PROC_SEC_GRANT, + SMP_PROC_SL_KEY, + SMP_PROC_COMPARE, + SMP_PROC_IO_RSP, + SMP_GENERATE_COMPARE, + SMP_GENERATE_CONFIRM, + SMP_GENERATE_STK, + SMP_KEY_DISTRIBUTE, + SMP_START_ENC, + SMP_PAIRING_CMPL, + SMP_DECIDE_ASSO_MODEL, + SMP_SEND_APP_CBACK, + SMP_CHECK_AUTH_REQ, + SMP_PAIR_TERMINATE, + SMP_ENC_CMPL, + SMP_PROC_DISCARD, + SMP_CREATE_PRIVATE_KEY, + SMP_USE_OOB_PRIVATE_KEY, + SMP_SEND_PAIR_PUBLIC_KEY, + SMP_PROCESS_PAIR_PUBLIC_KEY, + SMP_HAVE_BOTH_PUBLIC_KEYS, + SMP_START_SEC_CONN_PHASE1, + SMP_PROCESS_LOCAL_NONCE, + SMP_SEND_COMMITMENT, + SMP_PROCESS_PAIRING_COMMITMENT, + SMP_PROCESS_PEER_NONCE, + SMP_CALCULATE_LOCAL_DHKEY_CHECK, + SMP_SEND_DHKEY_CHECK, + SMP_PROCESS_DHKEY_CHECK, + SMP_CALCULATE_PEER_DHKEY_CHECK, + SMP_MATCH_DHKEY_CHECKS, + SMP_CALCULATE_NUMERIC_COMPARISON_DISPLAY_NUMBER, + SMP_MOVE_TO_SEC_CONN_PHASE2, + SMP_PH2_DHKEY_CHECKS_ARE_PRESENT, + SMP_WAIT_FOR_BOTH_PUBLIC_KEYS, + SMP_START_PASSKEY_VERIFICATION, + SMP_SEND_KEYPRESS_NOTIFICATION, + SMP_PROCESS_KEYPRESS_NOTIFICATION, + SMP_PROCESS_SECURE_CONNECTION_OOB_DATA, + SMP_SET_LOCAL_OOB_KEYS, + SMP_SET_LOCAL_OOB_RAND_COMMITMENT, + SMP_IDLE_TERMINATE, + SMP_FAST_CONN_PARAM, + SMP_SM_NO_ACTION +}; + +static const tSMP_ACT smp_sm_action[] = +{ + smp_proc_sec_req, + smp_send_pair_req, + smp_send_pair_rsp, + smp_send_confirm, + smp_send_pair_fail, + smp_send_rand, + smp_send_enc_info, + smp_send_id_info, + smp_send_ltk_reply, + smp_proc_pair_cmd, + smp_proc_pair_fail, + smp_proc_confirm, + smp_proc_rand, + smp_proc_enc_info, + smp_proc_master_id, + smp_proc_id_info, + smp_proc_id_addr, + smp_proc_srk_info, + smp_proc_sec_grant, + smp_proc_sl_key, + smp_proc_compare, + smp_process_io_response, + smp_generate_compare, + smp_generate_srand_mrand_confirm, + smp_generate_stk, + smp_key_distribution, + smp_start_enc, + smp_pairing_cmpl, + smp_decide_association_model, + smp_send_app_cback, + smp_check_auth_req, + smp_pair_terminate, + smp_enc_cmpl, + smp_proc_discard, + smp_create_private_key, + smp_use_oob_private_key, + smp_send_pair_public_key, + smp_process_pairing_public_key, + smp_both_have_public_keys, + smp_start_secure_connection_phase1, + smp_process_local_nonce, + smp_send_commitment, + smp_process_pairing_commitment, + smp_process_peer_nonce, + smp_calculate_local_dhkey_check, + smp_send_dhkey_check, + smp_process_dhkey_check, + smp_calculate_peer_dhkey_check, + smp_match_dhkey_checks, + smp_calculate_numeric_comparison_display_number, + smp_move_to_secure_connections_phase2, + smp_phase_2_dhkey_checks_are_present, + smp_wait_for_both_public_keys, + smp_start_passkey_verification, + smp_send_keypress_notification, + smp_process_keypress_notification, + smp_process_secure_connection_oob_data, + smp_set_local_oob_keys, + smp_set_local_oob_random_commitment, + smp_idle_terminate, + smp_fast_conn_param +}; + +/************ SMP Master FSM State/Event Indirection Table **************/ +static const UINT8 smp_master_entry_map[][SMP_STATE_MAX] = +{ +/* state name: Idle WaitApp SecReq Pair Wait Confirm Rand PublKey SCPhs1 Wait Wait SCPhs2 Wait DHKChk Enc Bond CrLocSc + Rsp Pend ReqRsp Cfm Exch Strt Cmtm Nonce Strt DHKChk Pend Pend OobData */ +/* PAIR_REQ */{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, +/* PAIR_RSP */{ 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, +/* CONFIRM */{ 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, +/* RAND */{ 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0 }, +/* PAIR_FAIL */{ 0, 0x81, 0, 0x81, 0x81,0x81, 0x81,0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0, 0, 0 }, +/* ENC_INFO */{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0 }, +/* MASTER_ID */{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0 }, +/* ID_INFO */{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0 }, +/* ID_ADDR */{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 0 }, +/* SIGN_INFO */{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0 }, +/* SEC_REQ */{ 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, +/* PAIR_PUBLIC_KEY */{ 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, +/* PAIR_DHKEY_CHCK */{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0 }, +/* PAIR_KEYPR_NOTIF */{ 0, 8, 0, 0, 0, 0, 0, 0, 5, 2, 0, 0, 0, 0, 0, 0, 0 }, +/* PAIR_COMMITM */{ 0, 0, 0, 0, 0, 0, 0, 0, 6, 1, 0, 0, 0, 0, 0, 0, 0 }, +/* KEY_READY */{ 0, 3, 0, 3, 1, 0, 2, 0, 4, 0, 0, 0, 0, 0, 1, 6, 0 }, +/* ENC_CMPL */{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0 }, +/* L2C_CONN */{ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, +/* L2C_DISC */{ 3, 0x83, 0, 0x83, 0x83,0x83, 0x83,0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0 }, +/* IO_RSP */{ 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, +/* SEC_GRANT */{ 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, +/* TK_REQ */{ 0, 0, 0, 2, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0 }, +/* AUTH_CMPL */{ 4, 0x82, 0, 0x82, 0x82,0x82, 0x82,0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0 }, +/* ENC_REQ */{ 0, 4, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0 }, +/* BOND_REQ */{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0 }, +/* DISCARD_SEC_REQ */{ 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0 }, +/* PUBL_KEY_EXCH_REQ */{ 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, +/* LOC_PUBL_KEY_CRTD */{ 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1 }, +/* BOTH_PUBL_KEYS_RCVD */{ 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, +/* SC_DHKEY_CMPLT */{ 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0 }, +/* HAVE_LOC_NONCE */{ 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 2 }, +/* SC_PHASE1_CMPLT */{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, +/* SC_CALC_NC */{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0 }, +/* SC_DSPL_NC */{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0 }, +/* SC_NC_OK */{ 0, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, +/* SC_2_DHCK_CHKS_PRES */{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, +/* SC_KEY_READY */{ 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0 }, +/* KEYPR_NOTIF */{ 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, +/* SC_OOB_DATA */{ 0, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, +/* CR_LOC_SC_OOB_DATA */{ 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, +}; + +static const UINT8 smp_all_table[][SMP_SM_NUM_COLS] = +{ +/* Event Action Next State */ +/* PAIR_FAIL */ {SMP_PROC_PAIR_FAIL, SMP_PAIRING_CMPL, SMP_STATE_IDLE}, +/* AUTH_CMPL */ {SMP_SEND_PAIR_FAIL, SMP_PAIRING_CMPL, SMP_STATE_IDLE}, +/* L2C_DISC */ {SMP_PAIR_TERMINATE, SMP_SM_NO_ACTION, SMP_STATE_IDLE} +}; + +static const UINT8 smp_master_idle_table[][SMP_SM_NUM_COLS] = +{ +/* Event Action Next State */ +/* L2C_CONN */ {SMP_SEND_APP_CBACK, SMP_SM_NO_ACTION, SMP_STATE_WAIT_APP_RSP}, +/* SEC_REQ */ {SMP_PROC_SEC_REQ, SMP_SEND_APP_CBACK, SMP_STATE_WAIT_APP_RSP}, +/* L2C_DISC */ {SMP_IDLE_TERMINATE, SMP_SM_NO_ACTION, SMP_STATE_IDLE}, +/* AUTH_CMPL */ {SMP_PAIRING_CMPL, SMP_SM_NO_ACTION, SMP_STATE_IDLE} +/* CR_LOC_SC_OOB_DATA */ ,{SMP_CREATE_PRIVATE_KEY, SMP_SM_NO_ACTION, SMP_STATE_CREATE_LOCAL_SEC_CONN_OOB_DATA} + +}; + +static const UINT8 smp_master_wait_for_app_response_table[][SMP_SM_NUM_COLS] = +{ +/* Event Action Next State */ +/* SEC_GRANT */ {SMP_PROC_SEC_GRANT, SMP_SEND_APP_CBACK, SMP_STATE_WAIT_APP_RSP}, +/* IO_RSP */ {SMP_SEND_PAIR_REQ, SMP_FAST_CONN_PARAM, SMP_STATE_PAIR_REQ_RSP}, + + /* TK ready */ +/* KEY_READY */ {SMP_GENERATE_CONFIRM, SMP_SM_NO_ACTION, SMP_STATE_WAIT_CONFIRM}, + + /* start enc mode setup */ +/* ENC_REQ */ { SMP_START_ENC, SMP_FAST_CONN_PARAM, SMP_STATE_ENCRYPTION_PENDING}, +/* DISCARD_SEC_REQ */ { SMP_PROC_DISCARD, SMP_SM_NO_ACTION, SMP_STATE_IDLE} +/* user confirms NC 'OK', i.e. phase 1 is completed */ +/* SC_NC_OK */,{ SMP_MOVE_TO_SEC_CONN_PHASE2, SMP_SM_NO_ACTION, SMP_STATE_SEC_CONN_PHS2_START}, +/* user-provided passkey is rcvd */ +/* SC_KEY_READY */ { SMP_START_PASSKEY_VERIFICATION, SMP_SM_NO_ACTION, SMP_STATE_SEC_CONN_PHS1_START}, +/* PAIR_KEYPR_NOTIF */ { SMP_PROCESS_KEYPRESS_NOTIFICATION, SMP_SEND_APP_CBACK, SMP_STATE_WAIT_APP_RSP}, +/* KEYPR_NOTIF */ { SMP_SEND_KEYPRESS_NOTIFICATION, SMP_SM_NO_ACTION, SMP_STATE_WAIT_APP_RSP}, +/* SC_OOB_DATA */ { SMP_USE_OOB_PRIVATE_KEY, SMP_SM_NO_ACTION, SMP_STATE_PUBLIC_KEY_EXCH} +}; + +static const UINT8 smp_master_pair_request_response_table[][SMP_SM_NUM_COLS] = +{ +/* Event Action Next State */ +/* PAIR_RSP */ { SMP_PROC_PAIR_CMD, SMP_SM_NO_ACTION, SMP_STATE_PAIR_REQ_RSP}, +/* TK_REQ */ { SMP_SEND_APP_CBACK, SMP_SM_NO_ACTION, SMP_STATE_WAIT_APP_RSP}, + + /* TK ready */ +/* KEY_READY */{ SMP_GENERATE_CONFIRM, SMP_SM_NO_ACTION, SMP_STATE_WAIT_CONFIRM} +/* PUBL_KEY_EXCH_REQ */,{ SMP_CREATE_PRIVATE_KEY, SMP_SM_NO_ACTION, SMP_STATE_PUBLIC_KEY_EXCH} +}; + +static const UINT8 smp_master_wait_for_confirm_table[][SMP_SM_NUM_COLS] = +{ +/* Event Action Next State */ +/* KEY_READY*/ {SMP_SEND_CONFIRM, SMP_SM_NO_ACTION, SMP_STATE_CONFIRM}/* CONFIRM ready */ +}; + +static const UINT8 smp_master_confirm_table[][SMP_SM_NUM_COLS] = +{ +/* Event Action Next State */ +/* CONFIRM */ { SMP_PROC_CONFIRM, SMP_SEND_RAND, SMP_STATE_RAND} +}; + +static const UINT8 smp_master_rand_table[][SMP_SM_NUM_COLS] = +{ +/* Event Action Next State */ +/* RAND */ { SMP_PROC_RAND, SMP_GENERATE_COMPARE, SMP_STATE_RAND}, +/* KEY_READY*/ { SMP_PROC_COMPARE, SMP_SM_NO_ACTION, SMP_STATE_RAND}, /* Compare ready */ +/* ENC_REQ */ { SMP_GENERATE_STK, SMP_SM_NO_ACTION, SMP_STATE_ENCRYPTION_PENDING} +}; + +static const UINT8 smp_master_public_key_exchange_table[][SMP_SM_NUM_COLS] = +{ +/* Event Action Next State */ +/* LOC_PUBL_KEY_CRTD */{ SMP_SEND_PAIR_PUBLIC_KEY, SMP_SM_NO_ACTION, SMP_STATE_PUBLIC_KEY_EXCH}, +/* PAIR_PUBLIC_KEY */{ SMP_PROCESS_PAIR_PUBLIC_KEY, SMP_SM_NO_ACTION, SMP_STATE_PUBLIC_KEY_EXCH}, +/* BOTH_PUBL_KEYS_RCVD */{ SMP_HAVE_BOTH_PUBLIC_KEYS, SMP_SM_NO_ACTION, SMP_STATE_SEC_CONN_PHS1_START}, +}; + +static const UINT8 smp_master_sec_conn_phs1_start_table[][SMP_SM_NUM_COLS] = +{ +/* Event Action Next State */ +/* SC_DHKEY_CMPLT */{ SMP_START_SEC_CONN_PHASE1, SMP_SM_NO_ACTION, SMP_STATE_SEC_CONN_PHS1_START}, +/* HAVE_LOC_NONCE */{ SMP_PROCESS_LOCAL_NONCE, SMP_SM_NO_ACTION, SMP_STATE_WAIT_COMMITMENT}, +/* TK_REQ */{ SMP_SEND_APP_CBACK, SMP_SM_NO_ACTION, SMP_STATE_WAIT_APP_RSP}, +/* SMP_MODEL_SEC_CONN_PASSKEY_DISP model, passkey is sent up to display,*/ +/* It's time to start commitment calculation */ +/* KEY_READY */{ SMP_START_PASSKEY_VERIFICATION, SMP_SM_NO_ACTION, SMP_STATE_SEC_CONN_PHS1_START}, +/* PAIR_KEYPR_NOTIF */{ SMP_PROCESS_KEYPRESS_NOTIFICATION, SMP_SEND_APP_CBACK, SMP_STATE_SEC_CONN_PHS1_START}, +/* PAIR_COMMITM */{ SMP_PROCESS_PAIRING_COMMITMENT, SMP_SM_NO_ACTION, SMP_STATE_SEC_CONN_PHS1_START}, +}; + +static const UINT8 smp_master_wait_commitment_table[][SMP_SM_NUM_COLS] = +{ +/* Event Action Next State */ +/* PAIR_COMMITM */{ SMP_PROCESS_PAIRING_COMMITMENT, SMP_SEND_RAND, SMP_STATE_WAIT_NONCE}, +/* PAIR_KEYPR_NOTIF */{ SMP_PROCESS_KEYPRESS_NOTIFICATION, SMP_SEND_APP_CBACK, SMP_STATE_WAIT_COMMITMENT}, +}; + +static const UINT8 smp_master_wait_nonce_table[][SMP_SM_NUM_COLS] = +{ +/* Event Action Next State */ +/* peer nonce is received */ +/* RAND */{SMP_PROC_RAND, SMP_PROCESS_PEER_NONCE, SMP_STATE_SEC_CONN_PHS2_START}, +/* NC model, time to calculate number for NC */ +/* SC_CALC_NC */{SMP_CALCULATE_NUMERIC_COMPARISON_DISPLAY_NUMBER, SMP_SM_NO_ACTION, SMP_STATE_WAIT_NONCE}, +/* NC model, time to display calculated number for NC to the user */ +/* SC_DSPL_NC */{SMP_SEND_APP_CBACK, SMP_SM_NO_ACTION, SMP_STATE_WAIT_APP_RSP}, +}; + +static const UINT8 smp_master_sec_conn_phs2_start_table[][SMP_SM_NUM_COLS] = +{ +/* Event Action Next State */ +/* SC_PHASE1_CMPLT */{SMP_CALCULATE_LOCAL_DHKEY_CHECK, SMP_SEND_DHKEY_CHECK, SMP_STATE_WAIT_DHK_CHECK}, +}; + +static const UINT8 smp_master_wait_dhk_check_table[][SMP_SM_NUM_COLS] = +{ +/* Event Action Next State */ +/* PAIR_DHKEY_CHCK */{SMP_PROCESS_DHKEY_CHECK, SMP_CALCULATE_PEER_DHKEY_CHECK, SMP_STATE_DHK_CHECK}, +}; + +static const UINT8 smp_master_dhk_check_table[][SMP_SM_NUM_COLS] = +{ +/* Event Action Next State */ +/* locally calculated peer dhkey check is ready -> compare it withs DHKey Check actually received from peer */ +/* SC_KEY_READY */{SMP_MATCH_DHKEY_CHECKS, SMP_SM_NO_ACTION, SMP_STATE_DHK_CHECK}, +/* locally calculated peer dhkey check is ready -> calculate STK, go to sending */ +/* HCI LE Start Encryption command */ +/* ENC_REQ */{SMP_GENERATE_STK, SMP_SM_NO_ACTION, SMP_STATE_ENCRYPTION_PENDING}, +}; + +static const UINT8 smp_master_enc_pending_table[][SMP_SM_NUM_COLS] = +{ +/* Event Action Next State */ +/* STK ready */ +/* KEY_READY */ { SMP_START_ENC, SMP_SM_NO_ACTION, SMP_STATE_ENCRYPTION_PENDING}, +/* ENCRYPTED */ { SMP_CHECK_AUTH_REQ, SMP_SM_NO_ACTION, SMP_STATE_ENCRYPTION_PENDING}, +/* BOND_REQ */ { SMP_KEY_DISTRIBUTE, SMP_SM_NO_ACTION, SMP_STATE_BOND_PENDING} +}; +static const UINT8 smp_master_bond_pending_table[][SMP_SM_NUM_COLS] = +{ +/* Event Action Next State */ +/* ENC_INFO */ { SMP_PROC_ENC_INFO, SMP_SM_NO_ACTION, SMP_STATE_BOND_PENDING}, +/* ID_INFO */ { SMP_PROC_ID_INFO, SMP_SM_NO_ACTION, SMP_STATE_BOND_PENDING}, +/* SIGN_INFO*/ { SMP_PROC_SRK_INFO, SMP_SM_NO_ACTION, SMP_STATE_BOND_PENDING}, +/* MASTER_ID*/ { SMP_PROC_MASTER_ID, SMP_SM_NO_ACTION, SMP_STATE_BOND_PENDING}, +/* ID_ADDR */ { SMP_PROC_ID_ADDR, SMP_SM_NO_ACTION, SMP_STATE_BOND_PENDING}, +/* KEY_READY */{SMP_SEND_ENC_INFO, SMP_SM_NO_ACTION, SMP_STATE_BOND_PENDING} /* LTK ready */ +}; + +static const UINT8 smp_master_create_local_sec_conn_oob_data[][SMP_SM_NUM_COLS] = +{ +/* Event Action Next State */ +/* LOC_PUBL_KEY_CRTD */ {SMP_SET_LOCAL_OOB_KEYS, SMP_SM_NO_ACTION, SMP_STATE_CREATE_LOCAL_SEC_CONN_OOB_DATA}, +/* HAVE_LOC_NONCE */ {SMP_SET_LOCAL_OOB_RAND_COMMITMENT, SMP_SM_NO_ACTION, SMP_STATE_IDLE} +}; + + +/************ SMP Slave FSM State/Event Indirection Table **************/ +static const UINT8 smp_slave_entry_map[][SMP_STATE_MAX] = +{ +/* state name: Idle WaitApp SecReq Pair Wait Confirm Rand PublKey SCPhs1 Wait Wait SCPhs2 Wait DHKChk Enc Bond CrLocSc + Rsp Pend ReqRsp Cfm Exch Strt Cmtm Nonce Strt DHKChk Pend Pend OobData */ +/* PAIR_REQ */{ 2, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, +/* PAIR_RSP */{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, +/* CONFIRM */{ 0, 4, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, +/* RAND */{ 0, 0, 0, 0, 0, 1, 2, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0 }, +/* PAIR_FAIL */{ 0, 0x81, 0x81, 0x81, 0x81,0x81, 0x81,0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0, 0 }, +/* ENC_INFO */{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0 }, +/* MASTER_ID */{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 0 }, +/* ID_INFO */{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0 }, +/* ID_ADDR */{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 0 }, +/* SIGN_INFO */{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0 }, +/* SEC_REQ */{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, +/* PAIR_PUBLIC_KEY */{ 0, 0, 0, 5, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, +/* PAIR_DHKEY_CHCK */{ 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 1, 2, 0, 0, 0 }, +/* PAIR_KEYPR_NOTIF */{ 0, 9, 0, 0, 0, 0, 0, 0, 5, 2, 0, 0, 0, 0, 0, 0, 0 }, +/* PAIR_COMMITM */{ 0, 8, 0, 0, 0, 0, 0, 0, 6, 1, 0, 0, 0, 0, 0, 0, 0 }, +/* KEY_READY */{ 0, 3, 0, 3, 2, 2, 1, 0, 4, 0, 0, 0, 0, 0, 2, 1, 0 }, +/* ENC_CMPL */{ 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0 }, +/* L2C_CONN */{ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, +/* L2C_DISC */{ 0, 0x83, 0x83, 0x83, 0x83,0x83, 0x83,0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0 }, +/* IO_RSP */{ 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, +/* SEC_GRANT */{ 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, +/* TK_REQ */{ 0, 0, 0, 2, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0 }, +/* AUTH_CMPL */{ 0, 0x82, 0x82, 0x82, 0x82,0x82, 0x82,0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0 }, +/* ENC_REQ */{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0 }, +/* BOND_REQ */{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0 }, +/* DISCARD_SEC_REQ */{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, +/* PUBL_KEY_EXCH_REQ */{ 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, +/* LOC_PUBL_KEY_CRTD */{ 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1 }, +/* BOTH_PUBL_KEYS_RCVD */{ 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, +/* SC_DHKEY_CMPLT */{ 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0 }, +/* HAVE_LOC_NONCE */{ 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 2 }, +/* SC_PHASE1_CMPLT */{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, +/* SC_CALC_NC */{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0 }, +/* SC_DSPL_NC */{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0 }, +/* SC_NC_OK */{ 0, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, +/* SC_2_DHCK_CHKS_PRES */{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0 }, +/* SC_KEY_READY */{ 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0 }, +/* KEYPR_NOTIF */{ 0, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, +/* SC_OOB_DATA */{ 0, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, +/* CR_LOC_SC_OOB_DATA */{ 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, +}; + +static const UINT8 smp_slave_idle_table[][SMP_SM_NUM_COLS] = +{ +/* Event Action Next State */ +/* L2C_CONN */ {SMP_SEND_APP_CBACK, SMP_SM_NO_ACTION, SMP_STATE_WAIT_APP_RSP}, +/* PAIR_REQ */ {SMP_PROC_PAIR_CMD, SMP_SEND_APP_CBACK, SMP_STATE_WAIT_APP_RSP} +/* CR_LOC_SC_OOB_DATA */ ,{SMP_CREATE_PRIVATE_KEY, SMP_SM_NO_ACTION, SMP_STATE_CREATE_LOCAL_SEC_CONN_OOB_DATA} +}; + +static const UINT8 smp_slave_wait_for_app_response_table [][SMP_SM_NUM_COLS] = +{ +/* Event Action Next State */ +/* IO_RSP */ {SMP_PROC_IO_RSP, SMP_FAST_CONN_PARAM, SMP_STATE_PAIR_REQ_RSP}, +/* SEC_GRANT */ {SMP_PROC_SEC_GRANT, SMP_SEND_APP_CBACK, SMP_STATE_WAIT_APP_RSP}, + + /* TK ready */ +/* KEY_READY */ {SMP_PROC_SL_KEY, SMP_SM_NO_ACTION, SMP_STATE_WAIT_APP_RSP}, +/* CONFIRM */ {SMP_PROC_CONFIRM, SMP_SM_NO_ACTION, SMP_STATE_CONFIRM} +/* DHKey Check from master is received before phase 1 is completed - race */ +/* PAIR_DHKEY_CHCK */,{SMP_PROCESS_DHKEY_CHECK, SMP_SM_NO_ACTION, SMP_STATE_WAIT_APP_RSP}, +/* user confirms NC 'OK', i.e. phase 1 is completed */ +/* SC_NC_OK */ {SMP_MOVE_TO_SEC_CONN_PHASE2, SMP_SM_NO_ACTION, SMP_STATE_SEC_CONN_PHS2_START}, +/* user-provided passkey is rcvd */ +/* SC_KEY_READY */ {SMP_START_PASSKEY_VERIFICATION, SMP_SM_NO_ACTION, SMP_STATE_SEC_CONN_PHS1_START}, +/* PAIR_COMMITM */ {SMP_PROCESS_PAIRING_COMMITMENT, SMP_SM_NO_ACTION, SMP_STATE_WAIT_APP_RSP}, +/* PAIR_KEYPR_NOTIF */ {SMP_PROCESS_KEYPRESS_NOTIFICATION, SMP_SEND_APP_CBACK, SMP_STATE_WAIT_APP_RSP}, +/* KEYPR_NOTIF */ {SMP_SEND_KEYPRESS_NOTIFICATION, SMP_SM_NO_ACTION, SMP_STATE_WAIT_APP_RSP}, +/* SC_OOB_DATA */ {SMP_SEND_PAIR_RSP, SMP_SM_NO_ACTION, SMP_STATE_PAIR_REQ_RSP}, +}; + +static const UINT8 smp_slave_sec_request_table[][SMP_SM_NUM_COLS] = +{ +/* Event Action Next State */ +/* PAIR_REQ */{SMP_PROC_PAIR_CMD, SMP_SM_NO_ACTION, SMP_STATE_PAIR_REQ_RSP}, +/* ENCRYPTED*/{SMP_ENC_CMPL, SMP_SM_NO_ACTION, SMP_STATE_PAIR_REQ_RSP}, +}; + +static const UINT8 smp_slave_pair_request_response_table[][SMP_SM_NUM_COLS] = +{ +/* Event Action Next State */ +/* CONFIRM */ {SMP_PROC_CONFIRM, SMP_SM_NO_ACTION, SMP_STATE_CONFIRM}, +/* TK_REQ */ {SMP_SEND_APP_CBACK, SMP_SM_NO_ACTION, SMP_STATE_WAIT_APP_RSP}, + + /* TK/Confirm ready */ +/* KEY_READY */{SMP_PROC_SL_KEY, SMP_SM_NO_ACTION, SMP_STATE_PAIR_REQ_RSP} +/* PUBL_KEY_EXCH_REQ */,{ SMP_CREATE_PRIVATE_KEY, SMP_SM_NO_ACTION, SMP_STATE_PUBLIC_KEY_EXCH}, +/* PAIR_PUBLIC_KEY */ { SMP_PROCESS_PAIR_PUBLIC_KEY, SMP_SM_NO_ACTION, SMP_STATE_PAIR_REQ_RSP}, +}; + +static const UINT8 smp_slave_wait_confirm_table[][SMP_SM_NUM_COLS] = +{ +/* Event Action Next State */ +/* CONFIRM */ {SMP_PROC_CONFIRM, SMP_SEND_CONFIRM, SMP_STATE_CONFIRM}, +/* KEY_READY*/ {SMP_PROC_SL_KEY, SMP_SM_NO_ACTION, SMP_STATE_WAIT_CONFIRM} +}; + +static const UINT8 smp_slave_confirm_table[][SMP_SM_NUM_COLS] = +{ +/* Event Action Next State */ +/* RAND */ {SMP_PROC_RAND, SMP_GENERATE_COMPARE, SMP_STATE_RAND}, + + /* TK/Confirm ready */ +/* KEY_READY*/ {SMP_PROC_SL_KEY, SMP_SM_NO_ACTION, SMP_STATE_CONFIRM} +}; + +static const UINT8 smp_slave_rand_table[][SMP_SM_NUM_COLS] = +{ +/* Event Action Next State */ +/* KEY_READY */ {SMP_PROC_COMPARE, SMP_SM_NO_ACTION, SMP_STATE_RAND}, /* compare match */ +/* RAND */ {SMP_SEND_RAND, SMP_SM_NO_ACTION, SMP_STATE_ENCRYPTION_PENDING} +}; + +static const UINT8 smp_slave_public_key_exch_table[][SMP_SM_NUM_COLS] = +{ +/* Event Action Next State */ +/* LOC_PUBL_KEY_CRTD */{ SMP_WAIT_FOR_BOTH_PUBLIC_KEYS, SMP_SM_NO_ACTION, SMP_STATE_PUBLIC_KEY_EXCH}, +/* PAIR_PUBLIC_KEY */{ SMP_PROCESS_PAIR_PUBLIC_KEY, SMP_SM_NO_ACTION, SMP_STATE_PUBLIC_KEY_EXCH}, +/* BOTH_PUBL_KEYS_RCVD */{ SMP_HAVE_BOTH_PUBLIC_KEYS, SMP_SM_NO_ACTION, SMP_STATE_SEC_CONN_PHS1_START}, +}; + +static const UINT8 smp_slave_sec_conn_phs1_start_table[][SMP_SM_NUM_COLS] = +{ +/* Event Action Next State */ +/* SC_DHKEY_CMPLT */{ SMP_START_SEC_CONN_PHASE1, SMP_SM_NO_ACTION, SMP_STATE_SEC_CONN_PHS1_START}, +/* HAVE_LOC_NONCE */{ SMP_PROCESS_LOCAL_NONCE,SMP_SM_NO_ACTION, SMP_STATE_WAIT_COMMITMENT}, +/* TK_REQ */{ SMP_SEND_APP_CBACK, SMP_SM_NO_ACTION, SMP_STATE_WAIT_APP_RSP}, +/* SMP_MODEL_SEC_CONN_PASSKEY_DISP model, passkey is sent up to display, it's time to start */ +/* commitment calculation */ +/* KEY_READY */{ SMP_START_PASSKEY_VERIFICATION, SMP_SM_NO_ACTION, SMP_STATE_SEC_CONN_PHS1_START}, +/* PAIR_KEYPR_NOTIF */{ SMP_PROCESS_KEYPRESS_NOTIFICATION,SMP_SEND_APP_CBACK, SMP_STATE_SEC_CONN_PHS1_START}, +/*COMMIT*/{SMP_PROCESS_PAIRING_COMMITMENT, SMP_SM_NO_ACTION, SMP_STATE_SEC_CONN_PHS1_START}, +}; + +static const UINT8 smp_slave_wait_commitment_table[][SMP_SM_NUM_COLS] = +{ +/* Event Action Next State */ +/* PAIR_COMMITM */{SMP_PROCESS_PAIRING_COMMITMENT, SMP_SEND_COMMITMENT, SMP_STATE_WAIT_NONCE}, +/* PAIR_KEYPR_NOTIF */{SMP_PROCESS_KEYPRESS_NOTIFICATION, SMP_SEND_APP_CBACK, SMP_STATE_WAIT_COMMITMENT}, +}; + +static const UINT8 smp_slave_wait_nonce_table[][SMP_SM_NUM_COLS] = +{ +/* Event Action Next State */ +/* peer nonce is received */ +/* RAND */{SMP_PROC_RAND, SMP_PROCESS_PEER_NONCE, SMP_STATE_SEC_CONN_PHS2_START}, +/* NC model, time to calculate number for NC */ +/* SC_CALC_NC */{SMP_CALCULATE_NUMERIC_COMPARISON_DISPLAY_NUMBER, SMP_SM_NO_ACTION, SMP_STATE_WAIT_NONCE}, +/* NC model, time to display calculated number for NC to the user */ +/* SC_DSPL_NC */{SMP_SEND_APP_CBACK, SMP_SM_NO_ACTION, SMP_STATE_WAIT_APP_RSP}, +}; + +static const UINT8 smp_slave_sec_conn_phs2_start_table[][SMP_SM_NUM_COLS] = +{ +/* Event Action Next State */ +/* SC_PHASE1_CMPLT */{SMP_CALCULATE_LOCAL_DHKEY_CHECK, SMP_PH2_DHKEY_CHECKS_ARE_PRESENT, SMP_STATE_WAIT_DHK_CHECK}, +/* DHKey Check from master is received before slave DHKey calculation is completed - race */ +/* PAIR_DHKEY_CHCK */{SMP_PROCESS_DHKEY_CHECK, SMP_SM_NO_ACTION, SMP_STATE_SEC_CONN_PHS2_START}, +}; + +static const UINT8 smp_slave_wait_dhk_check_table[][SMP_SM_NUM_COLS] = +{ +/* Event Action Next State */ +/* PAIR_DHKEY_CHCK */{SMP_PROCESS_DHKEY_CHECK, SMP_CALCULATE_PEER_DHKEY_CHECK, SMP_STATE_DHK_CHECK}, +/* DHKey Check from master was received before slave came to this state */ +/* SC_2_DHCK_CHKS_PRES */{SMP_CALCULATE_PEER_DHKEY_CHECK, SMP_SM_NO_ACTION, SMP_STATE_DHK_CHECK}, +}; + +static const UINT8 smp_slave_dhk_check_table[][SMP_SM_NUM_COLS] = +{ +/* Event Action Next State */ + +/* locally calculated peer dhkey check is ready -> compare it withs DHKey Check */ +/* actually received from peer */ +/* SC_KEY_READY */{SMP_MATCH_DHKEY_CHECKS, SMP_SM_NO_ACTION, SMP_STATE_DHK_CHECK}, + +/* dhkey checks match -> send local dhkey check to master, go to wait for HCI LE */ +/* Long Term Key Request Event */ +/* PAIR_DHKEY_CHCK */{SMP_SEND_DHKEY_CHECK, SMP_SM_NO_ACTION, SMP_STATE_ENCRYPTION_PENDING}, +}; + +static const UINT8 smp_slave_enc_pending_table[][SMP_SM_NUM_COLS] = +{ +/* Event Action Next State */ +/* ENC_REQ */ {SMP_GENERATE_STK, SMP_SM_NO_ACTION, SMP_STATE_ENCRYPTION_PENDING}, + + /* STK ready */ +/* KEY_READY */ {SMP_SEND_LTK_REPLY, SMP_SM_NO_ACTION, SMP_STATE_ENCRYPTION_PENDING}, +/* ENCRYPTED */ {SMP_CHECK_AUTH_REQ, SMP_SM_NO_ACTION, SMP_STATE_ENCRYPTION_PENDING}, +/* BOND_REQ */ {SMP_KEY_DISTRIBUTE, SMP_SM_NO_ACTION, SMP_STATE_BOND_PENDING} +}; +static const UINT8 smp_slave_bond_pending_table[][SMP_SM_NUM_COLS] = +{ +/* Event Action Next State */ + + /* LTK ready */ +/* KEY_READY */{ SMP_SEND_ENC_INFO, SMP_SM_NO_ACTION, SMP_STATE_BOND_PENDING}, + + /* rev SRK */ +/* SIGN_INFO */{ SMP_PROC_SRK_INFO, SMP_SM_NO_ACTION, SMP_STATE_BOND_PENDING}, +/* ENC_INFO */ { SMP_PROC_ENC_INFO, SMP_SM_NO_ACTION, SMP_STATE_BOND_PENDING}, +/* ID_INFO */ { SMP_PROC_ID_INFO, SMP_SM_NO_ACTION, SMP_STATE_BOND_PENDING}, +/* MASTER_ID*/ { SMP_PROC_MASTER_ID, SMP_SM_NO_ACTION, SMP_STATE_BOND_PENDING}, +/* ID_ADDR */ { SMP_PROC_ID_ADDR, SMP_SM_NO_ACTION, SMP_STATE_BOND_PENDING} + +}; + +static const UINT8 smp_slave_create_local_sec_conn_oob_data[][SMP_SM_NUM_COLS] = +{ +/* Event Action Next State */ +/* LOC_PUBL_KEY_CRTD */ {SMP_SET_LOCAL_OOB_KEYS, SMP_SM_NO_ACTION, SMP_STATE_CREATE_LOCAL_SEC_CONN_OOB_DATA}, +/* HAVE_LOC_NONCE */ {SMP_SET_LOCAL_OOB_RAND_COMMITMENT, SMP_SM_NO_ACTION, SMP_STATE_IDLE} +}; + +static const tSMP_SM_TBL smp_state_table[][2] = +{ + /* SMP_STATE_IDLE */ + {smp_master_idle_table, smp_slave_idle_table}, + + /* SMP_STATE_WAIT_APP_RSP */ + {smp_master_wait_for_app_response_table, smp_slave_wait_for_app_response_table}, + + /* SMP_STATE_SEC_REQ_PENDING */ + {NULL, smp_slave_sec_request_table}, + + /* SMP_STATE_PAIR_REQ_RSP */ + {smp_master_pair_request_response_table, smp_slave_pair_request_response_table}, + + /* SMP_STATE_WAIT_CONFIRM */ + {smp_master_wait_for_confirm_table, smp_slave_wait_confirm_table}, + + /* SMP_STATE_CONFIRM */ + {smp_master_confirm_table, smp_slave_confirm_table}, + + /* SMP_STATE_RAND */ + {smp_master_rand_table, smp_slave_rand_table}, + + /* SMP_STATE_PUBLIC_KEY_EXCH */ + {smp_master_public_key_exchange_table,smp_slave_public_key_exch_table}, + + /* SMP_STATE_SEC_CONN_PHS1_START */ + {smp_master_sec_conn_phs1_start_table, smp_slave_sec_conn_phs1_start_table}, + + /* SMP_STATE_WAIT_COMMITMENT */ + {smp_master_wait_commitment_table, smp_slave_wait_commitment_table}, + + /* SMP_STATE_WAIT_NONCE */ + {smp_master_wait_nonce_table, smp_slave_wait_nonce_table}, + + /* SMP_STATE_SEC_CONN_PHS2_START */ + {smp_master_sec_conn_phs2_start_table, smp_slave_sec_conn_phs2_start_table}, + + /* SMP_STATE_WAIT_DHK_CHECK */ + {smp_master_wait_dhk_check_table, smp_slave_wait_dhk_check_table}, + + /* SMP_STATE_DHK_CHECK */ + {smp_master_dhk_check_table, smp_slave_dhk_check_table}, + + /* SMP_STATE_ENCRYPTION_PENDING */ + {smp_master_enc_pending_table, smp_slave_enc_pending_table}, + + /* SMP_STATE_BOND_PENDING */ + {smp_master_bond_pending_table, smp_slave_bond_pending_table}, + + /* SMP_STATE_CREATE_LOCAL_SEC_CONN_OOB_DATA */ + {smp_master_create_local_sec_conn_oob_data, smp_slave_create_local_sec_conn_oob_data} +}; + +typedef const UINT8 (*tSMP_ENTRY_TBL)[SMP_STATE_MAX]; +static const tSMP_ENTRY_TBL smp_entry_table[] = +{ + smp_master_entry_map, + smp_slave_entry_map +}; + +#if SMP_DYNAMIC_MEMORY == FALSE +tSMP_CB smp_cb; +#endif +#define SMP_ALL_TBL_MASK 0x80 + +/******************************************************************************* +** Function smp_set_state +** Returns None +*******************************************************************************/ +void smp_set_state(tSMP_STATE state) +{ + if (state < SMP_STATE_MAX) + { + SMP_TRACE_DEBUG( "State change: %s(%d) ==> %s(%d)", + smp_get_state_name(smp_cb.state), smp_cb.state, + smp_get_state_name(state), state ); + smp_cb.state = state; + } + else + { + SMP_TRACE_DEBUG("smp_set_state invalid state =%d", state ); + } +} + +/******************************************************************************* +** Function smp_get_state +** Returns The smp state +*******************************************************************************/ +tSMP_STATE smp_get_state(void) +{ + return smp_cb.state; +} + +/******************************************************************************* +** +** Function smp_sm_event +** +** Description Handle events to the state machine. It looks up the entry +** in the smp_entry_table array. +** If it is a valid entry, it gets the state table.Set the next state, +** if not NULL state.Execute the action function according to the +** state table. If the state returned by action function is not NULL +** state, adjust the new state to the returned state.If (api_evt != MAX), +** call callback function. +** +** Returns void. +** +*******************************************************************************/ +void smp_sm_event(tSMP_CB *p_cb, tSMP_EVENT event, void *p_data) +{ + UINT8 curr_state = p_cb->state; + tSMP_SM_TBL state_table; + UINT8 action, entry, i; + tSMP_ENTRY_TBL entry_table = smp_entry_table[p_cb->role]; + + SMP_TRACE_EVENT("main smp_sm_event"); + if (curr_state >= SMP_STATE_MAX) + { + SMP_TRACE_DEBUG( "Invalid state: %d", curr_state) ; + return; + } + + SMP_TRACE_DEBUG( "SMP Role: %s State: [%s (%d)], Event: [%s (%d)]",\ + (p_cb->role == 0x01) ?"Slave" : "Master", smp_get_state_name( p_cb->state), + p_cb->state, smp_get_event_name(event), event) ; + + /* look up the state table for the current state */ + /* lookup entry /w event & curr_state */ + /* If entry is ignore, return. + * Otherwise, get state table (according to curr_state or all_state) */ + if ((event <= SMP_MAX_EVT) && ( (entry = entry_table[event - 1][curr_state]) != SMP_SM_IGNORE )) + { + if (entry & SMP_ALL_TBL_MASK) + { + entry &= ~SMP_ALL_TBL_MASK; + state_table = smp_all_table; + } + else + state_table = smp_state_table[curr_state][p_cb->role]; + } + else + { + SMP_TRACE_DEBUG( "Ignore event [%s (%d)] in state [%s (%d)]", + smp_get_event_name(event), event, smp_get_state_name(curr_state), + curr_state); + return; + } + + /* Get possible next state from state table. */ + + smp_set_state(state_table[entry-1][SMP_SME_NEXT_STATE]); + + /* If action is not ignore, clear param, exec action and get next state. + * The action function may set the Param for cback. + * Depending on param, call cback or free buffer. */ + /* execute action */ + /* execute action functions */ + for (i = 0; i < SMP_NUM_ACTIONS; i++) + { + if ((action = state_table[entry-1][i]) != SMP_SM_NO_ACTION) + { + (*smp_sm_action[action])(p_cb, (tSMP_INT_DATA *)p_data); + } + else + { + break; + } + } + SMP_TRACE_DEBUG( "result state = %s", smp_get_state_name( p_cb->state ) ) ; +} + +/******************************************************************************* +** Function smp_get_state_name +** Returns The smp state name. +*******************************************************************************/ +const char * smp_get_state_name(tSMP_STATE state) +{ + const char *p_str = smp_state_name[SMP_STATE_MAX]; + + if (state < SMP_STATE_MAX) + { + p_str = smp_state_name[state]; + } + return p_str; +} + +/******************************************************************************* +** Function smp_get_event_name +** Returns The smp event name. +*******************************************************************************/ +const char * smp_get_event_name(tSMP_EVENT event) +{ + const char *p_str = smp_event_name[SMP_MAX_EVT]; + + if (event <= SMP_MAX_EVT) + { + p_str = smp_event_name[event- 1]; + } + return p_str; +} + +#endif + diff --git a/components/bt/bluedroid/stack/smp/smp_utils.c b/components/bt/bluedroid/stack/smp/smp_utils.c new file mode 100755 index 0000000000..a3809115ec --- /dev/null +++ b/components/bt/bluedroid/stack/smp/smp_utils.c @@ -0,0 +1,1579 @@ +/****************************************************************************** + * + * Copyright (C) 1999-2012 Broadcom Corporation + * + * 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 functions for the SMP L2CAP utility functions + * + ******************************************************************************/ +#include "bt_target.h" + +#if SMP_INCLUDED == TRUE + +#include "bt_types.h" +//#include "bt_utils.h" +#include +//#include +#include "hcidefs.h" +#include "btm_ble_api.h" +#include "l2c_api.h" +#include "l2c_int.h" +#include "smp_int.h" +#include "controller.h" +#include "btm_int.h" + +#define SMP_PAIRING_REQ_SIZE 7 +#define SMP_CONFIRM_CMD_SIZE (BT_OCTET16_LEN + 1) +#define SMP_RAND_CMD_SIZE (BT_OCTET16_LEN + 1) +#define SMP_INIT_CMD_SIZE (BT_OCTET16_LEN + 1) +#define SMP_ENC_INFO_SIZE (BT_OCTET16_LEN + 1) +#define SMP_MASTER_ID_SIZE (BT_OCTET8_LEN + 2 + 1) +#define SMP_ID_INFO_SIZE (BT_OCTET16_LEN + 1) +#define SMP_ID_ADDR_SIZE (BD_ADDR_LEN + 1 + 1) +#define SMP_SIGN_INFO_SIZE (BT_OCTET16_LEN + 1) +#define SMP_PAIR_FAIL_SIZE 2 +#define SMP_SECURITY_REQUEST_SIZE 2 +#define SMP_PAIR_PUBL_KEY_SIZE (1 /* opcode */ + (2*BT_OCTET32_LEN)) +#define SMP_PAIR_COMMITM_SIZE (1 /* opcode */ + BT_OCTET16_LEN /*Commitment*/) +#define SMP_PAIR_DHKEY_CHECK_SIZE (1 /* opcode */ + BT_OCTET16_LEN /*DHKey Check*/) +#define SMP_PAIR_KEYPR_NOTIF_SIZE (1 /* opcode */ + 1 /*Notif Type*/) + +/* SMP command sizes per spec */ +static const UINT8 smp_cmd_size_per_spec[] = +{ + 0, + SMP_PAIRING_REQ_SIZE, /* 0x01: pairing request */ + SMP_PAIRING_REQ_SIZE, /* 0x02: pairing response */ + SMP_CONFIRM_CMD_SIZE, /* 0x03: pairing confirm */ + SMP_RAND_CMD_SIZE, /* 0x04: pairing random */ + SMP_PAIR_FAIL_SIZE, /* 0x05: pairing failed */ + SMP_ENC_INFO_SIZE, /* 0x06: encryption information */ + SMP_MASTER_ID_SIZE, /* 0x07: master identification */ + SMP_ID_INFO_SIZE, /* 0x08: identity information */ + SMP_ID_ADDR_SIZE, /* 0x09: identity address information */ + SMP_SIGN_INFO_SIZE, /* 0x0A: signing information */ + SMP_SECURITY_REQUEST_SIZE, /* 0x0B: security request */ + SMP_PAIR_PUBL_KEY_SIZE, /* 0x0C: pairing public key */ + SMP_PAIR_DHKEY_CHECK_SIZE, /* 0x0D: pairing dhkey check */ + SMP_PAIR_KEYPR_NOTIF_SIZE, /* 0x0E: pairing keypress notification */ + SMP_PAIR_COMMITM_SIZE /* 0x0F: pairing commitment */ +}; + +static BOOLEAN smp_parameter_unconditionally_valid(tSMP_CB *p_cb); +static BOOLEAN smp_parameter_unconditionally_invalid(tSMP_CB *p_cb); + +/* type for SMP command length validation functions */ +typedef BOOLEAN (*tSMP_CMD_LEN_VALID)(tSMP_CB *p_cb); + +static BOOLEAN smp_command_has_valid_fixed_length(tSMP_CB *p_cb); + +static const tSMP_CMD_LEN_VALID smp_cmd_len_is_valid[] = +{ + smp_parameter_unconditionally_invalid, + smp_command_has_valid_fixed_length, /* 0x01: pairing request */ + smp_command_has_valid_fixed_length, /* 0x02: pairing response */ + smp_command_has_valid_fixed_length, /* 0x03: pairing confirm */ + smp_command_has_valid_fixed_length, /* 0x04: pairing random */ + smp_command_has_valid_fixed_length, /* 0x05: pairing failed */ + smp_command_has_valid_fixed_length, /* 0x06: encryption information */ + smp_command_has_valid_fixed_length, /* 0x07: master identification */ + smp_command_has_valid_fixed_length, /* 0x08: identity information */ + smp_command_has_valid_fixed_length, /* 0x09: identity address information */ + smp_command_has_valid_fixed_length, /* 0x0A: signing information */ + smp_command_has_valid_fixed_length, /* 0x0B: security request */ + smp_command_has_valid_fixed_length, /* 0x0C: pairing public key */ + smp_command_has_valid_fixed_length, /* 0x0D: pairing dhkey check */ + smp_command_has_valid_fixed_length, /* 0x0E: pairing keypress notification */ + smp_command_has_valid_fixed_length /* 0x0F: pairing commitment */ +}; + +/* type for SMP command parameter ranges validation functions */ +typedef BOOLEAN (*tSMP_CMD_PARAM_RANGES_VALID)(tSMP_CB *p_cb); + +static BOOLEAN smp_pairing_request_response_parameters_are_valid(tSMP_CB *p_cb); +static BOOLEAN smp_pairing_keypress_notification_is_valid(tSMP_CB *p_cb); + +static const tSMP_CMD_PARAM_RANGES_VALID smp_cmd_param_ranges_are_valid[] = +{ + smp_parameter_unconditionally_invalid, + smp_pairing_request_response_parameters_are_valid, /* 0x01: pairing request */ + smp_pairing_request_response_parameters_are_valid, /* 0x02: pairing response */ + smp_parameter_unconditionally_valid, /* 0x03: pairing confirm */ + smp_parameter_unconditionally_valid, /* 0x04: pairing random */ + smp_parameter_unconditionally_valid, /* 0x05: pairing failed */ + smp_parameter_unconditionally_valid, /* 0x06: encryption information */ + smp_parameter_unconditionally_valid, /* 0x07: master identification */ + smp_parameter_unconditionally_valid, /* 0x08: identity information */ + smp_parameter_unconditionally_valid, /* 0x09: identity address information */ + smp_parameter_unconditionally_valid, /* 0x0A: signing information */ + smp_parameter_unconditionally_valid, /* 0x0B: security request */ + smp_parameter_unconditionally_valid, /* 0x0C: pairing public key */ + smp_parameter_unconditionally_valid, /* 0x0D: pairing dhkey check */ + smp_pairing_keypress_notification_is_valid, /* 0x0E: pairing keypress notification */ + smp_parameter_unconditionally_valid /* 0x0F: pairing commitment */ +}; + +/* type for action functions */ +typedef BT_HDR * (*tSMP_CMD_ACT)(UINT8 cmd_code, tSMP_CB *p_cb); + +static BT_HDR *smp_build_pairing_cmd(UINT8 cmd_code, tSMP_CB *p_cb); +static BT_HDR *smp_build_confirm_cmd(UINT8 cmd_code, tSMP_CB *p_cb); +static BT_HDR *smp_build_rand_cmd(UINT8 cmd_code, tSMP_CB *p_cb); +static BT_HDR *smp_build_pairing_fail(UINT8 cmd_code, tSMP_CB *p_cb); +static BT_HDR *smp_build_identity_info_cmd(UINT8 cmd_code, tSMP_CB *p_cb); +static BT_HDR *smp_build_encrypt_info_cmd(UINT8 cmd_code, tSMP_CB *p_cb); +static BT_HDR *smp_build_security_request(UINT8 cmd_code, tSMP_CB *p_cb); +static BT_HDR *smp_build_signing_info_cmd(UINT8 cmd_code, tSMP_CB *p_cb); +static BT_HDR *smp_build_master_id_cmd(UINT8 cmd_code, tSMP_CB *p_cb); +static BT_HDR *smp_build_id_addr_cmd(UINT8 cmd_code, tSMP_CB *p_cb); +static BT_HDR *smp_build_pair_public_key_cmd(UINT8 cmd_code, tSMP_CB *p_cb); +static BT_HDR *smp_build_pairing_commitment_cmd(UINT8 cmd_code, tSMP_CB *p_cb); +static BT_HDR *smp_build_pair_dhkey_check_cmd(UINT8 cmd_code, tSMP_CB *p_cb); +static BT_HDR *smp_build_pairing_keypress_notification_cmd(UINT8 cmd_code, tSMP_CB *p_cb); + +static const tSMP_CMD_ACT smp_cmd_build_act[] = +{ + NULL, + smp_build_pairing_cmd, /* 0x01: pairing request */ + smp_build_pairing_cmd, /* 0x02: pairing response */ + smp_build_confirm_cmd, /* 0x03: pairing confirm */ + smp_build_rand_cmd, /* 0x04: pairing random */ + smp_build_pairing_fail, /* 0x05: pairing failure */ + smp_build_encrypt_info_cmd, /* 0x06: encryption information */ + smp_build_master_id_cmd, /* 0x07: master identification */ + smp_build_identity_info_cmd, /* 0x08: identity information */ + smp_build_id_addr_cmd, /* 0x09: identity address information */ + smp_build_signing_info_cmd, /* 0x0A: signing information */ + smp_build_security_request, /* 0x0B: security request */ + smp_build_pair_public_key_cmd, /* 0x0C: pairing public key */ + smp_build_pair_dhkey_check_cmd, /* 0x0D: pairing DHKey check */ + smp_build_pairing_keypress_notification_cmd, /* 0x0E: pairing keypress notification */ + smp_build_pairing_commitment_cmd /* 0x0F: pairing commitment */ +}; + +static const UINT8 smp_association_table[2][SMP_IO_CAP_MAX][SMP_IO_CAP_MAX] = +{ + /* display only */ /* Display Yes/No */ /* keyboard only */ + /* No Input/Output */ /* keyboard display */ + + /* initiator */ + /* model = tbl[peer_io_caps][loc_io_caps] */ + /* Display Only */ + {{SMP_MODEL_ENCRYPTION_ONLY, SMP_MODEL_ENCRYPTION_ONLY, SMP_MODEL_PASSKEY, + SMP_MODEL_ENCRYPTION_ONLY, SMP_MODEL_PASSKEY}, + + /* Display Yes/No */ + {SMP_MODEL_ENCRYPTION_ONLY, SMP_MODEL_ENCRYPTION_ONLY, SMP_MODEL_PASSKEY, + SMP_MODEL_ENCRYPTION_ONLY, SMP_MODEL_PASSKEY}, + + /* Keyboard only */ + {SMP_MODEL_KEY_NOTIF, SMP_MODEL_KEY_NOTIF, SMP_MODEL_PASSKEY, + SMP_MODEL_ENCRYPTION_ONLY, SMP_MODEL_KEY_NOTIF}, + + /* No Input No Output */ + {SMP_MODEL_ENCRYPTION_ONLY, SMP_MODEL_ENCRYPTION_ONLY, SMP_MODEL_ENCRYPTION_ONLY, + SMP_MODEL_ENCRYPTION_ONLY, SMP_MODEL_ENCRYPTION_ONLY}, + + /* keyboard display */ + {SMP_MODEL_KEY_NOTIF, SMP_MODEL_KEY_NOTIF, SMP_MODEL_PASSKEY, + SMP_MODEL_ENCRYPTION_ONLY, SMP_MODEL_KEY_NOTIF}}, + + /* responder */ + /* model = tbl[loc_io_caps][peer_io_caps] */ + /* Display Only */ + {{SMP_MODEL_ENCRYPTION_ONLY, SMP_MODEL_ENCRYPTION_ONLY, SMP_MODEL_KEY_NOTIF, + SMP_MODEL_ENCRYPTION_ONLY, SMP_MODEL_KEY_NOTIF}, + + /* Display Yes/No */ + {SMP_MODEL_ENCRYPTION_ONLY, SMP_MODEL_ENCRYPTION_ONLY, SMP_MODEL_KEY_NOTIF, + SMP_MODEL_ENCRYPTION_ONLY, SMP_MODEL_KEY_NOTIF}, + + /* keyboard only */ + {SMP_MODEL_PASSKEY, SMP_MODEL_PASSKEY, SMP_MODEL_PASSKEY, + SMP_MODEL_ENCRYPTION_ONLY, SMP_MODEL_PASSKEY}, + + /* No Input No Output */ + {SMP_MODEL_ENCRYPTION_ONLY, SMP_MODEL_ENCRYPTION_ONLY, SMP_MODEL_ENCRYPTION_ONLY, + SMP_MODEL_ENCRYPTION_ONLY, SMP_MODEL_ENCRYPTION_ONLY}, + + /* keyboard display */ + {SMP_MODEL_PASSKEY, SMP_MODEL_PASSKEY, SMP_MODEL_KEY_NOTIF, + SMP_MODEL_ENCRYPTION_ONLY, SMP_MODEL_PASSKEY}} +}; + +static const UINT8 smp_association_table_sc[2][SMP_IO_CAP_MAX][SMP_IO_CAP_MAX] = +{ + /* display only */ /* Display Yes/No */ /* keyboard only */ + /* No InputOutput */ /* keyboard display */ + + /* initiator */ + /* model = tbl[peer_io_caps][loc_io_caps] */ + + /* Display Only */ + {{SMP_MODEL_SEC_CONN_JUSTWORKS, SMP_MODEL_SEC_CONN_JUSTWORKS, SMP_MODEL_SEC_CONN_PASSKEY_ENT, + SMP_MODEL_SEC_CONN_JUSTWORKS, SMP_MODEL_SEC_CONN_PASSKEY_ENT}, + + /* Display Yes/No */ + {SMP_MODEL_SEC_CONN_JUSTWORKS, SMP_MODEL_SEC_CONN_NUM_COMP, SMP_MODEL_SEC_CONN_PASSKEY_ENT, + SMP_MODEL_SEC_CONN_JUSTWORKS, SMP_MODEL_SEC_CONN_NUM_COMP}, + + /* keyboard only */ + {SMP_MODEL_SEC_CONN_PASSKEY_DISP, SMP_MODEL_SEC_CONN_PASSKEY_DISP, SMP_MODEL_SEC_CONN_PASSKEY_ENT, + SMP_MODEL_SEC_CONN_JUSTWORKS, SMP_MODEL_SEC_CONN_PASSKEY_DISP}, + + /* No Input No Output */ + {SMP_MODEL_SEC_CONN_JUSTWORKS, SMP_MODEL_SEC_CONN_JUSTWORKS, SMP_MODEL_SEC_CONN_JUSTWORKS, + SMP_MODEL_SEC_CONN_JUSTWORKS, SMP_MODEL_SEC_CONN_JUSTWORKS}, + + /* keyboard display */ + {SMP_MODEL_SEC_CONN_PASSKEY_DISP, SMP_MODEL_SEC_CONN_NUM_COMP, SMP_MODEL_SEC_CONN_PASSKEY_ENT, + SMP_MODEL_SEC_CONN_JUSTWORKS, SMP_MODEL_SEC_CONN_NUM_COMP}}, + + /* responder */ + /* model = tbl[loc_io_caps][peer_io_caps] */ + + /* Display Only */ + {{SMP_MODEL_SEC_CONN_JUSTWORKS, SMP_MODEL_SEC_CONN_JUSTWORKS, SMP_MODEL_SEC_CONN_PASSKEY_DISP, + SMP_MODEL_SEC_CONN_JUSTWORKS, SMP_MODEL_SEC_CONN_PASSKEY_DISP}, + + /* Display Yes/No */ + {SMP_MODEL_SEC_CONN_JUSTWORKS, SMP_MODEL_SEC_CONN_NUM_COMP, SMP_MODEL_SEC_CONN_PASSKEY_DISP, + SMP_MODEL_SEC_CONN_JUSTWORKS, SMP_MODEL_SEC_CONN_NUM_COMP}, + + /* keyboard only */ + {SMP_MODEL_SEC_CONN_PASSKEY_ENT, SMP_MODEL_SEC_CONN_PASSKEY_ENT, SMP_MODEL_SEC_CONN_PASSKEY_ENT, + SMP_MODEL_SEC_CONN_JUSTWORKS, SMP_MODEL_SEC_CONN_PASSKEY_ENT}, + + /* No Input No Output */ + {SMP_MODEL_SEC_CONN_JUSTWORKS, SMP_MODEL_SEC_CONN_JUSTWORKS, SMP_MODEL_SEC_CONN_JUSTWORKS, + SMP_MODEL_SEC_CONN_JUSTWORKS, SMP_MODEL_SEC_CONN_JUSTWORKS}, + + /* keyboard display */ + {SMP_MODEL_SEC_CONN_PASSKEY_ENT, SMP_MODEL_SEC_CONN_NUM_COMP, SMP_MODEL_SEC_CONN_PASSKEY_DISP, + SMP_MODEL_SEC_CONN_JUSTWORKS, SMP_MODEL_SEC_CONN_NUM_COMP}} +}; + +static tSMP_ASSO_MODEL smp_select_legacy_association_model(tSMP_CB *p_cb); +static tSMP_ASSO_MODEL smp_select_association_model_secure_connections(tSMP_CB *p_cb); + +/******************************************************************************* +** +** Function smp_send_msg_to_L2CAP +** +** Description Send message to L2CAP. +** +*******************************************************************************/ +BOOLEAN smp_send_msg_to_L2CAP(BD_ADDR rem_bda, BT_HDR *p_toL2CAP) +{ + UINT16 l2cap_ret; + UINT16 fixed_cid = L2CAP_SMP_CID; + + if (smp_cb.smp_over_br) + { + fixed_cid = L2CAP_SMP_BR_CID; + } + + SMP_TRACE_EVENT("%s", __FUNCTION__); + smp_cb.total_tx_unacked += 1; + + if ((l2cap_ret = L2CA_SendFixedChnlData (fixed_cid, rem_bda, p_toL2CAP)) == L2CAP_DW_FAILED) + { + smp_cb.total_tx_unacked -= 1; + SMP_TRACE_ERROR("SMP failed to pass msg:0x%0x to L2CAP", + *((UINT8 *)(p_toL2CAP + 1) + p_toL2CAP->offset)); + return FALSE; + } + else + return TRUE; +} + +/******************************************************************************* +** +** Function smp_send_cmd +** +** Description send a SMP command on L2CAP channel. +** +*******************************************************************************/ +BOOLEAN smp_send_cmd(UINT8 cmd_code, tSMP_CB *p_cb) +{ + BT_HDR *p_buf; + BOOLEAN sent = FALSE; + UINT8 failure = SMP_PAIR_INTERNAL_ERR; + SMP_TRACE_EVENT("smp_send_cmd on l2cap cmd_code=0x%x", cmd_code); + if ( cmd_code <= (SMP_OPCODE_MAX + 1 /* for SMP_OPCODE_PAIR_COMMITM */) && + smp_cmd_build_act[cmd_code] != NULL) + { + p_buf = (*smp_cmd_build_act[cmd_code])(cmd_code, p_cb); + + if (p_buf != NULL && + smp_send_msg_to_L2CAP(p_cb->pairing_bda, p_buf)) + { + sent = TRUE; + + btu_stop_timer (&p_cb->rsp_timer_ent); + btu_start_timer (&p_cb->rsp_timer_ent, BTU_TTYPE_SMP_PAIRING_CMD, + SMP_WAIT_FOR_RSP_TOUT); + } + } + + if (!sent) + { + if (p_cb->smp_over_br) + { + smp_br_state_machine_event(p_cb, SMP_BR_AUTH_CMPL_EVT, &failure); + } + else + { + smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &failure); + } + } + return sent; +} + +/******************************************************************************* +** +** Function smp_rsp_timeout +** +** Description Called when SMP wait for SMP command response timer expires +** +** Returns void +** +*******************************************************************************/ +void smp_rsp_timeout(TIMER_LIST_ENT *p_tle) +{ + tSMP_CB *p_cb = &smp_cb; + UINT8 failure = SMP_RSP_TIMEOUT; + UNUSED(p_tle); + + SMP_TRACE_EVENT("%s state:%d br_state:%d", __FUNCTION__, p_cb->state, p_cb->br_state); + + if (p_cb->smp_over_br) + { + smp_br_state_machine_event(p_cb, SMP_BR_AUTH_CMPL_EVT, &failure); + } + else + { + smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &failure); + } +} + +/******************************************************************************* +** +** Function smp_build_pairing_req_cmd +** +** Description Build pairing request command. +** +*******************************************************************************/ +BT_HDR * smp_build_pairing_cmd(UINT8 cmd_code, tSMP_CB *p_cb) +{ + BT_HDR *p_buf = NULL ; + UINT8 *p; + + SMP_TRACE_EVENT("smp_build_pairing_cmd"); + if ((p_buf = (BT_HDR *)GKI_getbuf(sizeof(BT_HDR) + SMP_PAIRING_REQ_SIZE + L2CAP_MIN_OFFSET)) != NULL) + { + p = (UINT8 *)(p_buf + 1) + L2CAP_MIN_OFFSET; + + UINT8_TO_STREAM (p, cmd_code); + UINT8_TO_STREAM (p, p_cb->local_io_capability); + UINT8_TO_STREAM (p, p_cb->loc_oob_flag); + UINT8_TO_STREAM (p, p_cb->loc_auth_req); + UINT8_TO_STREAM (p, p_cb->loc_enc_size); + UINT8_TO_STREAM (p, p_cb->local_i_key); + UINT8_TO_STREAM (p, p_cb->local_r_key); + + p_buf->offset = L2CAP_MIN_OFFSET; + /* 1B ERR_RSP op code + 1B cmd_op_code + 2B handle + 1B status */ + p_buf->len = SMP_PAIRING_REQ_SIZE; + } + + return p_buf; +} + +/******************************************************************************* +** +** Function smp_build_confirm_cmd +** +** Description Build confirm request command. +** +*******************************************************************************/ +static BT_HDR * smp_build_confirm_cmd(UINT8 cmd_code, tSMP_CB *p_cb) +{ + BT_HDR *p_buf = NULL ; + UINT8 *p; + UNUSED(cmd_code); + + SMP_TRACE_EVENT("smp_build_confirm_cmd"); + if ((p_buf = (BT_HDR *)GKI_getbuf(sizeof(BT_HDR) + SMP_CONFIRM_CMD_SIZE + L2CAP_MIN_OFFSET)) != NULL) + { + p = (UINT8 *)(p_buf + 1) + L2CAP_MIN_OFFSET; + + UINT8_TO_STREAM (p, SMP_OPCODE_CONFIRM); + ARRAY_TO_STREAM (p, p_cb->confirm, BT_OCTET16_LEN); + + p_buf->offset = L2CAP_MIN_OFFSET; + p_buf->len = SMP_CONFIRM_CMD_SIZE; + } + + return p_buf; +} +/******************************************************************************* +** +** Function smp_build_rand_cmd +** +** Description Build Random command. +** +*******************************************************************************/ +static BT_HDR * smp_build_rand_cmd(UINT8 cmd_code, tSMP_CB *p_cb) +{ + BT_HDR *p_buf = NULL ; + UINT8 *p; + UNUSED(cmd_code); + + SMP_TRACE_EVENT("%s", __func__); + if ((p_buf = (BT_HDR *)GKI_getbuf(sizeof(BT_HDR) + SMP_RAND_CMD_SIZE + L2CAP_MIN_OFFSET)) + != NULL) + { + p = (UINT8 *)(p_buf + 1) + L2CAP_MIN_OFFSET; + + UINT8_TO_STREAM (p, SMP_OPCODE_RAND); + ARRAY_TO_STREAM (p, p_cb->rand, BT_OCTET16_LEN); + + p_buf->offset = L2CAP_MIN_OFFSET; + p_buf->len = SMP_RAND_CMD_SIZE; + } + + return p_buf; +} +/******************************************************************************* +** +** Function smp_build_encrypt_info_cmd +** +** Description Build security information command. +** +*******************************************************************************/ +static BT_HDR * smp_build_encrypt_info_cmd(UINT8 cmd_code, tSMP_CB *p_cb) +{ + BT_HDR *p_buf = NULL ; + UINT8 *p; + UNUSED(cmd_code); + + SMP_TRACE_EVENT("smp_build_encrypt_info_cmd"); + if ((p_buf = (BT_HDR *)GKI_getbuf(sizeof(BT_HDR) + SMP_ENC_INFO_SIZE + L2CAP_MIN_OFFSET)) != NULL) + { + p = (UINT8 *)(p_buf + 1) + L2CAP_MIN_OFFSET; + + UINT8_TO_STREAM (p, SMP_OPCODE_ENCRYPT_INFO); + ARRAY_TO_STREAM (p, p_cb->ltk, BT_OCTET16_LEN); + + p_buf->offset = L2CAP_MIN_OFFSET; + p_buf->len = SMP_ENC_INFO_SIZE; + } + + return p_buf; +} + +/******************************************************************************* +** +** Function smp_build_master_id_cmd +** +** Description Build security information command. +** +*******************************************************************************/ +static BT_HDR * smp_build_master_id_cmd(UINT8 cmd_code, tSMP_CB *p_cb) +{ + BT_HDR *p_buf = NULL ; + UINT8 *p; + UNUSED(cmd_code); + + SMP_TRACE_EVENT("%s", __func__); + + if ((p_buf = (BT_HDR *)GKI_getbuf(sizeof(BT_HDR) + SMP_MASTER_ID_SIZE + L2CAP_MIN_OFFSET)) != NULL) + { + p = (UINT8 *)(p_buf + 1) + L2CAP_MIN_OFFSET; + + UINT8_TO_STREAM (p, SMP_OPCODE_MASTER_ID); + UINT16_TO_STREAM (p, p_cb->ediv); + ARRAY_TO_STREAM (p, p_cb->enc_rand, BT_OCTET8_LEN); + + p_buf->offset = L2CAP_MIN_OFFSET; + p_buf->len = SMP_MASTER_ID_SIZE; + } + + return p_buf; +} + +/******************************************************************************* +** +** Function smp_build_identity_info_cmd +** +** Description Build identity information command. +** +*******************************************************************************/ +static BT_HDR * smp_build_identity_info_cmd(UINT8 cmd_code, tSMP_CB *p_cb) +{ + BT_HDR *p_buf = NULL ; + UINT8 *p; + BT_OCTET16 irk; + UNUSED(cmd_code); + UNUSED(p_cb); + + SMP_TRACE_EVENT("smp_build_identity_info_cmd"); + if ((p_buf = (BT_HDR *)GKI_getbuf(sizeof(BT_HDR) + SMP_ID_INFO_SIZE + L2CAP_MIN_OFFSET)) != NULL) + { + p = (UINT8 *)(p_buf + 1) + L2CAP_MIN_OFFSET; + + BTM_GetDeviceIDRoot(irk); + + UINT8_TO_STREAM (p, SMP_OPCODE_IDENTITY_INFO); + ARRAY_TO_STREAM (p, irk, BT_OCTET16_LEN); + + p_buf->offset = L2CAP_MIN_OFFSET; + p_buf->len = SMP_ID_INFO_SIZE; + } + + return p_buf; +} + +/******************************************************************************* +** +** Function smp_build_id_addr_cmd +** +** Description Build identity address information command. +** +*******************************************************************************/ +static BT_HDR * smp_build_id_addr_cmd(UINT8 cmd_code, tSMP_CB *p_cb) +{ + BT_HDR *p_buf = NULL; + UINT8 *p; + + UNUSED(cmd_code); + UNUSED(p_cb); + SMP_TRACE_EVENT("smp_build_id_addr_cmd"); + if ((p_buf = (BT_HDR *)GKI_getbuf(sizeof(BT_HDR) + SMP_ID_ADDR_SIZE + L2CAP_MIN_OFFSET)) != NULL) + { + p = (UINT8 *)(p_buf + 1) + L2CAP_MIN_OFFSET; + + UINT8_TO_STREAM (p, SMP_OPCODE_ID_ADDR); + UINT8_TO_STREAM (p, 0); + BDADDR_TO_STREAM (p, controller_get_interface()->get_address()->address); + + p_buf->offset = L2CAP_MIN_OFFSET; + p_buf->len = SMP_ID_ADDR_SIZE; + } + + return p_buf; +} + +/******************************************************************************* +** +** Function smp_build_signing_info_cmd +** +** Description Build signing information command. +** +*******************************************************************************/ +static BT_HDR * smp_build_signing_info_cmd(UINT8 cmd_code, tSMP_CB *p_cb) +{ + BT_HDR *p_buf = NULL ; + UINT8 *p; + UNUSED(cmd_code); + + SMP_TRACE_EVENT("smp_build_signing_info_cmd"); + if ((p_buf = (BT_HDR *)GKI_getbuf(sizeof(BT_HDR) + SMP_SIGN_INFO_SIZE + L2CAP_MIN_OFFSET)) != NULL) + { + p = (UINT8 *)(p_buf + 1) + L2CAP_MIN_OFFSET; + + UINT8_TO_STREAM (p, SMP_OPCODE_SIGN_INFO); + ARRAY_TO_STREAM (p, p_cb->csrk, BT_OCTET16_LEN); + + p_buf->offset = L2CAP_MIN_OFFSET; + p_buf->len = SMP_SIGN_INFO_SIZE; + } + + return p_buf; +} + +/******************************************************************************* +** +** Function smp_build_pairing_fail +** +** Description Build Pairing Fail command. +** +*******************************************************************************/ +static BT_HDR * smp_build_pairing_fail(UINT8 cmd_code, tSMP_CB *p_cb) +{ + BT_HDR *p_buf = NULL ; + UINT8 *p; + UNUSED(cmd_code); + + SMP_TRACE_EVENT("%s", __func__); + if ((p_buf = (BT_HDR *)GKI_getbuf(sizeof(BT_HDR) + SMP_PAIR_FAIL_SIZE + L2CAP_MIN_OFFSET)) != NULL) + { + p = (UINT8 *)(p_buf + 1) + L2CAP_MIN_OFFSET; + + UINT8_TO_STREAM (p, SMP_OPCODE_PAIRING_FAILED); + UINT8_TO_STREAM (p, p_cb->failure); + + p_buf->offset = L2CAP_MIN_OFFSET; + p_buf->len = SMP_PAIR_FAIL_SIZE; + } + + return p_buf; +} + +/******************************************************************************* +** +** Function smp_build_security_request +** +** Description Build security request command. +** +*******************************************************************************/ +static BT_HDR *smp_build_security_request(UINT8 cmd_code, tSMP_CB *p_cb) +{ + BT_HDR *p_buf = NULL ; + UINT8 *p; + UNUSED(cmd_code); + + SMP_TRACE_EVENT("%s", __func__); + if ((p_buf = (BT_HDR *)GKI_getbuf(sizeof(BT_HDR) + 2 + L2CAP_MIN_OFFSET)) != NULL) + { + p = (UINT8 *)(p_buf + 1) + L2CAP_MIN_OFFSET; + + UINT8_TO_STREAM (p, SMP_OPCODE_SEC_REQ); + UINT8_TO_STREAM (p, p_cb->loc_auth_req); + + p_buf->offset = L2CAP_MIN_OFFSET; + p_buf->len = SMP_SECURITY_REQUEST_SIZE; + + SMP_TRACE_EVENT("opcode=%d auth_req=0x%x",SMP_OPCODE_SEC_REQ, p_cb->loc_auth_req ); + } + + return p_buf; + +} + +/******************************************************************************* +** +** Function smp_build_pair_public_key_cmd +** +** Description Build pairing public key command. +** +*******************************************************************************/ +static BT_HDR *smp_build_pair_public_key_cmd(UINT8 cmd_code, tSMP_CB *p_cb) +{ + BT_HDR *p_buf = NULL ; + UINT8 *p; + UINT8 publ_key[2*BT_OCTET32_LEN]; + UINT8 *p_publ_key = publ_key; + UNUSED(cmd_code); + + SMP_TRACE_EVENT("%s", __FUNCTION__); + + memcpy(p_publ_key, p_cb->loc_publ_key.x, BT_OCTET32_LEN); + memcpy(p_publ_key + BT_OCTET32_LEN, p_cb->loc_publ_key.y, BT_OCTET32_LEN); + + if ((p_buf = (BT_HDR *)GKI_getbuf(sizeof(BT_HDR) + + SMP_PAIR_PUBL_KEY_SIZE + L2CAP_MIN_OFFSET)) != NULL) + { + p = (UINT8 *)(p_buf + 1) + L2CAP_MIN_OFFSET; + + UINT8_TO_STREAM (p, SMP_OPCODE_PAIR_PUBLIC_KEY); + ARRAY_TO_STREAM (p, p_publ_key, 2*BT_OCTET32_LEN); + + p_buf->offset = L2CAP_MIN_OFFSET; + p_buf->len = SMP_PAIR_PUBL_KEY_SIZE; + } + + return p_buf; +} + +/******************************************************************************* +** +** Function smp_build_pairing_commitment_cmd +** +** Description Build pairing commitment command. +** +*******************************************************************************/ +static BT_HDR *smp_build_pairing_commitment_cmd(UINT8 cmd_code, tSMP_CB *p_cb) +{ + BT_HDR *p_buf = NULL; + UINT8 *p; + UNUSED(cmd_code); + + SMP_TRACE_EVENT("%s", __func__); + if ((p_buf = (BT_HDR *)GKI_getbuf(sizeof(BT_HDR) + SMP_PAIR_COMMITM_SIZE + L2CAP_MIN_OFFSET)) + != NULL) + { + p = (UINT8 *)(p_buf + 1) + L2CAP_MIN_OFFSET; + + UINT8_TO_STREAM (p, SMP_OPCODE_CONFIRM); + ARRAY_TO_STREAM (p, p_cb->commitment, BT_OCTET16_LEN); + + p_buf->offset = L2CAP_MIN_OFFSET; + p_buf->len = SMP_PAIR_COMMITM_SIZE; + } + + return p_buf; +} + +/******************************************************************************* +** +** Function smp_build_pair_dhkey_check_cmd +** +** Description Build pairing DHKey check command. +** +*******************************************************************************/ +static BT_HDR *smp_build_pair_dhkey_check_cmd(UINT8 cmd_code, tSMP_CB *p_cb) +{ + BT_HDR *p_buf = NULL; + UINT8 *p; + UNUSED(cmd_code); + + SMP_TRACE_EVENT("%s", __FUNCTION__); + if ((p_buf = (BT_HDR *)GKI_getbuf(sizeof(BT_HDR) + + SMP_PAIR_DHKEY_CHECK_SIZE + L2CAP_MIN_OFFSET)) != NULL) + { + p = (UINT8 *)(p_buf + 1) + L2CAP_MIN_OFFSET; + + UINT8_TO_STREAM (p, SMP_OPCODE_PAIR_DHKEY_CHECK); + ARRAY_TO_STREAM (p, p_cb->dhkey_check, BT_OCTET16_LEN); + + p_buf->offset = L2CAP_MIN_OFFSET; + p_buf->len = SMP_PAIR_DHKEY_CHECK_SIZE; + } + + return p_buf; +} + +/******************************************************************************* +** +** Function smp_build_pairing_keypress_notification_cmd +** +** Description Build keypress notification command. +** +*******************************************************************************/ +static BT_HDR * smp_build_pairing_keypress_notification_cmd(UINT8 cmd_code, tSMP_CB *p_cb) +{ + BT_HDR *p_buf = NULL ; + UINT8 *p; + UNUSED(cmd_code); + + SMP_TRACE_EVENT("%s", __FUNCTION__); + if ((p_buf = (BT_HDR *)GKI_getbuf(sizeof(BT_HDR)\ + + SMP_PAIR_KEYPR_NOTIF_SIZE + L2CAP_MIN_OFFSET)) != NULL) + { + p = (UINT8 *)(p_buf + 1) + L2CAP_MIN_OFFSET; + + UINT8_TO_STREAM (p, SMP_OPCODE_PAIR_KEYPR_NOTIF); + UINT8_TO_STREAM (p, p_cb->local_keypress_notification); + + p_buf->offset = L2CAP_MIN_OFFSET; + p_buf->len = SMP_PAIR_KEYPR_NOTIF_SIZE; + } + + return p_buf; +} + +/******************************************************************************* +** +** Function smp_convert_string_to_tk +** +** Description This function is called to convert a 6 to 16 digits numeric +** character string into SMP TK. +** +** +** Returns void +** +*******************************************************************************/ +void smp_convert_string_to_tk(BT_OCTET16 tk, UINT32 passkey) +{ + UINT8 *p = tk; + tSMP_KEY key; + SMP_TRACE_EVENT("smp_convert_string_to_tk"); + UINT32_TO_STREAM(p, passkey); + + key.key_type = SMP_KEY_TYPE_TK; + key.p_data = tk; + + smp_sm_event(&smp_cb, SMP_KEY_READY_EVT, &key); +} + +/******************************************************************************* +** +** Function smp_mask_enc_key +** +** Description This function is called to mask off the encryption key based +** on the maximum encryption key size. +** +** +** Returns void +** +*******************************************************************************/ +void smp_mask_enc_key(UINT8 loc_enc_size, UINT8 * p_data) +{ + SMP_TRACE_EVENT("smp_mask_enc_key"); + if (loc_enc_size < BT_OCTET16_LEN) + { + for (; loc_enc_size < BT_OCTET16_LEN; loc_enc_size ++) + * (p_data + loc_enc_size) = 0; + } + return; +} + +/******************************************************************************* +** +** Function smp_xor_128 +** +** Description utility function to do an biteise exclusive-OR of two bit +** strings of the length of BT_OCTET16_LEN. +** +** Returns void +** +*******************************************************************************/ +void smp_xor_128(BT_OCTET16 a, BT_OCTET16 b) +{ + UINT8 i, *aa = a, *bb = b; + + SMP_TRACE_EVENT("smp_xor_128"); + for (i = 0; i < BT_OCTET16_LEN; i++) + { + aa[i] = aa[i] ^ bb[i]; + } +} + +/******************************************************************************* +** +** Function smp_cb_cleanup +** +** Description Clean up SMP control block +** +** Returns void +** +*******************************************************************************/ +void smp_cb_cleanup(tSMP_CB *p_cb) +{ + tSMP_CALLBACK *p_callback = p_cb->p_callback; + UINT8 trace_level = p_cb->trace_level; + + SMP_TRACE_EVENT("smp_cb_cleanup"); + + memset(p_cb, 0, sizeof(tSMP_CB)); + p_cb->p_callback = p_callback; + p_cb->trace_level = trace_level; +} + +/******************************************************************************* +** +** Function smp_remove_fixed_channel +** +** Description This function is called to remove the fixed channel +** +** Returns void +** +*******************************************************************************/ +void smp_remove_fixed_channel(tSMP_CB *p_cb) +{ + SMP_TRACE_DEBUG("%s", __func__); + + if (p_cb->smp_over_br) + L2CA_RemoveFixedChnl (L2CAP_SMP_BR_CID, p_cb->pairing_bda); + else + L2CA_RemoveFixedChnl (L2CAP_SMP_CID, p_cb->pairing_bda); +} + +/******************************************************************************* +** +** Function smp_reset_control_value +** +** Description This function is called to reset the control block value when +** pairing procedure finished. +** +** +** Returns void +** +*******************************************************************************/ +void smp_reset_control_value(tSMP_CB *p_cb) +{ + SMP_TRACE_EVENT("smp_reset_control_value"); + btu_stop_timer (&p_cb->rsp_timer_ent); + p_cb->flags = 0; + /* set the link idle timer to drop the link when pairing is done + usually service discovery will follow authentication complete, to avoid + racing condition for a link down/up, set link idle timer to be + SMP_LINK_TOUT_MIN to guarantee SMP key exchange */ + L2CA_SetIdleTimeoutByBdAddr(p_cb->pairing_bda, SMP_LINK_TOUT_MIN, BT_TRANSPORT_LE); + + /* We can tell L2CAP to remove the fixed channel (if it has one) */ + smp_remove_fixed_channel(p_cb); + smp_cb_cleanup(p_cb); +} + +/******************************************************************************* +** +** Function smp_proc_pairing_cmpl +** +** Description This function is called to process pairing complete +** +** +** Returns void +** +*******************************************************************************/ +void smp_proc_pairing_cmpl(tSMP_CB *p_cb) +{ + tSMP_EVT_DATA evt_data = {0}; + tSMP_CALLBACK *p_callback = p_cb->p_callback; + BD_ADDR pairing_bda; + + SMP_TRACE_DEBUG ("smp_proc_pairing_cmpl "); + + evt_data.cmplt.reason = p_cb->status; + evt_data.cmplt.smp_over_br = p_cb->smp_over_br; + + if (p_cb->status == SMP_SUCCESS) + evt_data.cmplt.sec_level = p_cb->sec_level; + + evt_data.cmplt.is_pair_cancel = FALSE; + + if (p_cb->is_pair_cancel) + evt_data.cmplt.is_pair_cancel = TRUE; + + + SMP_TRACE_DEBUG ("send SMP_COMPLT_EVT reason=0x%0x sec_level=0x%0x", + evt_data.cmplt.reason, + evt_data.cmplt.sec_level ); + + memcpy (pairing_bda, p_cb->pairing_bda, BD_ADDR_LEN); + + smp_reset_control_value(p_cb); + + if (p_callback) + (*p_callback) (SMP_COMPLT_EVT, pairing_bda, &evt_data); +} + +/******************************************************************************* +** +** Function smp_command_has_invalid_parameters +** +** Description Checks if the received SMP command has invalid parameters i.e. +** if the command length is valid and the command parameters are +** inside specified range. +** It returns TRUE if the command has invalid parameters. +** +** Returns TRUE if the command has invalid parameters, FALSE otherwise. +** +*******************************************************************************/ +BOOLEAN smp_command_has_invalid_parameters(tSMP_CB *p_cb) +{ + UINT8 cmd_code = p_cb->rcvd_cmd_code; + + SMP_TRACE_DEBUG("%s for cmd code 0x%02x", __func__, cmd_code); + + if ((cmd_code > (SMP_OPCODE_MAX + 1 /* for SMP_OPCODE_PAIR_COMMITM */)) || + (cmd_code < SMP_OPCODE_MIN)) + { + SMP_TRACE_WARNING("Somehow received command with the RESERVED code 0x%02x", cmd_code); + return TRUE; + } + + if (!(*smp_cmd_len_is_valid[cmd_code])(p_cb)) + return TRUE; + + if (!(*smp_cmd_param_ranges_are_valid[cmd_code])(p_cb)) + return TRUE; + + return FALSE; +} + +/******************************************************************************* +** +** Function smp_command_has_valid_fixed_length +** +** Description Checks if the received command size is equal to the size +** according to specs. +** +** Returns TRUE if the command size is as expected, FALSE otherwise. +** +** Note The command is expected to have fixed length. +*******************************************************************************/ +BOOLEAN smp_command_has_valid_fixed_length(tSMP_CB *p_cb) +{ + UINT8 cmd_code = p_cb->rcvd_cmd_code; + + SMP_TRACE_DEBUG("%s for cmd code 0x%02x", __func__, cmd_code); + + if (p_cb->rcvd_cmd_len != smp_cmd_size_per_spec[cmd_code]) + { + SMP_TRACE_WARNING("Rcvd from the peer cmd 0x%02x with invalid length\ + 0x%02x (per spec the length is 0x%02x).", + cmd_code, p_cb->rcvd_cmd_len, smp_cmd_size_per_spec[cmd_code]); + return FALSE; + } + + return TRUE; +} + +/******************************************************************************* +** +** Function smp_pairing_request_response_parameters_are_valid +** +** Description Validates parameter ranges in the received SMP command +** pairing request or pairing response. +** The parameters to validate: +** IO capability, +** OOB data flag, +** Bonding_flags in AuthReq +** Maximum encryption key size. +** Returns FALSE if at least one of these parameters is out of range. +** +*******************************************************************************/ +BOOLEAN smp_pairing_request_response_parameters_are_valid(tSMP_CB *p_cb) +{ + UINT8 io_caps = p_cb->peer_io_caps; + UINT8 oob_flag = p_cb->peer_oob_flag; + UINT8 bond_flag = p_cb->peer_auth_req & 0x03; //0x03 is gen bond with appropriate mask + UINT8 enc_size = p_cb->peer_enc_size; + + SMP_TRACE_DEBUG("%s for cmd code 0x%02x", __func__, p_cb->rcvd_cmd_code); + + if (io_caps >= BTM_IO_CAP_MAX) + { + SMP_TRACE_WARNING("Rcvd from the peer cmd 0x%02x with IO Capabilty \ + value (0x%02x) out of range).", + p_cb->rcvd_cmd_code, io_caps); + return FALSE; + } + + if (!((oob_flag == SMP_OOB_NONE) || (oob_flag == SMP_OOB_PRESENT))) + { + SMP_TRACE_WARNING("Rcvd from the peer cmd 0x%02x with OOB data flag value \ + (0x%02x) out of range).", + p_cb->rcvd_cmd_code, oob_flag); + return FALSE; + } + + if (!((bond_flag == SMP_AUTH_NO_BOND) || (bond_flag == SMP_AUTH_BOND))) + { + SMP_TRACE_WARNING("Rcvd from the peer cmd 0x%02x with Bonding_Flags value (0x%02x)\ + out of range).", + p_cb->rcvd_cmd_code, bond_flag); + return FALSE; + } + + if ((enc_size < SMP_ENCR_KEY_SIZE_MIN) || (enc_size > SMP_ENCR_KEY_SIZE_MAX)) + { + SMP_TRACE_WARNING("Rcvd from the peer cmd 0x%02x with Maximum Encryption \ + Key value (0x%02x) out of range).", + p_cb->rcvd_cmd_code, enc_size); + return FALSE; + } + + return TRUE; +} + +/******************************************************************************* +** +** Function smp_pairing_keypress_notification_is_valid +** +** Description Validates Notification Type parameter range in the received SMP command +** pairing keypress notification. +** Returns FALSE if this parameter is out of range. +** +*******************************************************************************/ +BOOLEAN smp_pairing_keypress_notification_is_valid(tSMP_CB *p_cb) +{ + tBTM_SP_KEY_TYPE keypress_notification = p_cb->peer_keypress_notification; + + SMP_TRACE_DEBUG("%s for cmd code 0x%02x", __func__, p_cb->rcvd_cmd_code); + + if (keypress_notification >= BTM_SP_KEY_OUT_OF_RANGE) + { + SMP_TRACE_WARNING("Rcvd from the peer cmd 0x%02x with Pairing Keypress \ + Notification value (0x%02x) out of range).", + p_cb->rcvd_cmd_code, keypress_notification); + return FALSE; + } + + return TRUE; +} + +/******************************************************************************* +** +** Function smp_parameter_unconditionally_valid +** +** Description Always returns TRUE. +** +*******************************************************************************/ +BOOLEAN smp_parameter_unconditionally_valid(tSMP_CB *p_cb) +{ + return TRUE; +} + +/******************************************************************************* +** +** Function smp_parameter_unconditionally_invalid +** +** Description Always returns FALSE. +** +*******************************************************************************/ +BOOLEAN smp_parameter_unconditionally_invalid(tSMP_CB *p_cb) +{ + return FALSE; +} + +/******************************************************************************* +** +** Function smp_reject_unexpected_pairing_command +** +** Description send pairing failure to an unexpected pairing command during +** an active pairing process. +** +** Returns void +** +*******************************************************************************/ +void smp_reject_unexpected_pairing_command(BD_ADDR bd_addr) +{ + BT_HDR *p_buf; + UINT8 *p; + + SMP_TRACE_DEBUG ("%s", __FUNCTION__); + + if ((p_buf = (BT_HDR *)GKI_getbuf(sizeof(BT_HDR) +\ + SMP_PAIR_FAIL_SIZE + L2CAP_MIN_OFFSET)) != NULL) + { + p = (UINT8 *)(p_buf + 1) + L2CAP_MIN_OFFSET; + + UINT8_TO_STREAM (p, SMP_OPCODE_PAIRING_FAILED); + UINT8_TO_STREAM (p, SMP_PAIR_NOT_SUPPORT); + + p_buf->offset = L2CAP_MIN_OFFSET; + p_buf->len = SMP_PAIR_FAIL_SIZE; + + smp_send_msg_to_L2CAP(bd_addr, p_buf); + } +} + +/******************************************************************************* +** Function smp_select_association_model +** +** Description This function selects association model to use for STK +** generation. Selection is based on both sides' io capability, +** oob data flag and authentication request. +** +** Note If Secure Connections Only mode is required locally then we +** come to this point only if both sides support Secure Connections +** mode, i.e. if p_cb->secure_connections_only_mode_required = TRUE then we come +** to this point only if +** (p_cb->peer_auth_req & SMP_SC_SUPPORT_BIT) == +** (p_cb->loc_auth_req & SMP_SC_SUPPORT_BIT) == +** SMP_SC_SUPPORT_BIT +** +*******************************************************************************/ +tSMP_ASSO_MODEL smp_select_association_model(tSMP_CB *p_cb) +{ + tSMP_ASSO_MODEL model = SMP_MODEL_OUT_OF_RANGE; + p_cb->le_secure_connections_mode_is_used = FALSE; + + SMP_TRACE_EVENT("%s", __FUNCTION__); + SMP_TRACE_DEBUG("%s p_cb->peer_io_caps = %d p_cb->local_io_capability = %d", + __FUNCTION__, p_cb->peer_io_caps, p_cb->local_io_capability); + SMP_TRACE_DEBUG("%s p_cb->peer_oob_flag = %d p_cb->loc_oob_flag = %d", + __FUNCTION__, p_cb->peer_oob_flag, p_cb->loc_oob_flag); + SMP_TRACE_DEBUG("%s p_cb->peer_auth_req = 0x%02x p_cb->loc_auth_req = 0x%02x", + __FUNCTION__, p_cb->peer_auth_req, p_cb->loc_auth_req); + SMP_TRACE_DEBUG("%s p_cb->secure_connections_only_mode_required = %s", + __FUNCTION__, p_cb->secure_connections_only_mode_required ? + "TRUE" : "FALSE"); + + if ((p_cb->peer_auth_req & SMP_SC_SUPPORT_BIT) && (p_cb->loc_auth_req & SMP_SC_SUPPORT_BIT)) + { + p_cb->le_secure_connections_mode_is_used = TRUE; + } + + SMP_TRACE_DEBUG("use_sc_process = %d", p_cb->le_secure_connections_mode_is_used); + + if (p_cb->le_secure_connections_mode_is_used) + { + model = smp_select_association_model_secure_connections(p_cb); + } + else + { + model = smp_select_legacy_association_model(p_cb); + } + return model; +} + +/******************************************************************************* +** Function smp_select_legacy_association_model +** +** Description This function is called to select association mode if at least +** one side doesn't support secure connections. +** +*******************************************************************************/ +tSMP_ASSO_MODEL smp_select_legacy_association_model(tSMP_CB *p_cb) +{ + tSMP_ASSO_MODEL model = SMP_MODEL_OUT_OF_RANGE; + + SMP_TRACE_DEBUG("%s", __func__); + /* if OOB data is present on both devices, then use OOB association model */ + if (p_cb->peer_oob_flag == SMP_OOB_PRESENT && p_cb->loc_oob_flag == SMP_OOB_PRESENT) + return SMP_MODEL_OOB; + + /* else if neither device requires MITM, then use Just Works association model */ + if (SMP_NO_MITM_REQUIRED (p_cb->peer_auth_req) && SMP_NO_MITM_REQUIRED(p_cb->loc_auth_req)) + return SMP_MODEL_ENCRYPTION_ONLY; + + /* otherwise use IO capability to select association model */ + if (p_cb->peer_io_caps < SMP_IO_CAP_MAX && p_cb->local_io_capability < SMP_IO_CAP_MAX) + { + if (p_cb->role == HCI_ROLE_MASTER) + { + model = smp_association_table[p_cb->role][p_cb->peer_io_caps] + [p_cb->local_io_capability]; + } + else + { + model = smp_association_table[p_cb->role][p_cb->local_io_capability] + [p_cb->peer_io_caps]; + } + } + + return model; +} + +/******************************************************************************* +** Function smp_select_association_model_secure_connections +** +** Description This function is called to select association mode if both +** sides support secure connections. +** +*******************************************************************************/ +tSMP_ASSO_MODEL smp_select_association_model_secure_connections(tSMP_CB *p_cb) +{ + tSMP_ASSO_MODEL model = SMP_MODEL_OUT_OF_RANGE; + + SMP_TRACE_DEBUG("%s", __func__); + /* if OOB data is present on at least one device, then use OOB association model */ + if (p_cb->peer_oob_flag == SMP_OOB_PRESENT || p_cb->loc_oob_flag == SMP_OOB_PRESENT) + return SMP_MODEL_SEC_CONN_OOB; + + /* else if neither device requires MITM, then use Just Works association model */ + if (SMP_NO_MITM_REQUIRED (p_cb->peer_auth_req) && SMP_NO_MITM_REQUIRED(p_cb->loc_auth_req)) + return SMP_MODEL_SEC_CONN_JUSTWORKS; + + /* otherwise use IO capability to select association model */ + if (p_cb->peer_io_caps < SMP_IO_CAP_MAX && p_cb->local_io_capability < SMP_IO_CAP_MAX) + { + if (p_cb->role == HCI_ROLE_MASTER) + { + model = smp_association_table_sc[p_cb->role][p_cb->peer_io_caps] + [p_cb->local_io_capability]; + } + else + { + model = smp_association_table_sc[p_cb->role][p_cb->local_io_capability] + [p_cb->peer_io_caps]; + } + } + + return model; +} + +/******************************************************************************* +** Function smp_reverse_array +** +** Description This function reverses array bytes +** +*******************************************************************************/ +void smp_reverse_array(UINT8 *arr, UINT8 len) +{ + UINT8 i =0, tmp; + + SMP_TRACE_DEBUG("smp_reverse_array"); + + for (i = 0; i < len/2; i ++) + { + tmp = arr[i]; + arr[i] = arr[len -1 - i]; + arr[len -1 - i] = tmp; + } +} + +/******************************************************************************* +** Function smp_calculate_random_input +** +** Description This function returns random input value to be used in commitment +** calculation for SC passkey entry association mode +** (if bit["round"] in "random" array == 1 then returns 0x81 +** else returns 0x80). +** +** Returns ri value +** +*******************************************************************************/ +UINT8 smp_calculate_random_input(UINT8 *random, UINT8 round) +{ + UINT8 i = round/8; + UINT8 j = round%8; + UINT8 ri; + + SMP_TRACE_DEBUG("random: 0x%02x, round: %d, i: %d, j: %d", random[i], round, i, j); + ri = ((random[i] >> j) & 1) | 0x80; + SMP_TRACE_DEBUG("%s ri=0x%02x", __func__, ri); + return ri; +} + +/******************************************************************************* +** Function smp_collect_local_io_capabilities +** +** Description This function puts into IOcap array local device +** IOCapability, OOB data, AuthReq. +** +** Returns void +** +*******************************************************************************/ +void smp_collect_local_io_capabilities(UINT8 *iocap, tSMP_CB *p_cb) +{ + SMP_TRACE_DEBUG("%s", __func__); + + iocap[0] = p_cb->local_io_capability; + iocap[1] = p_cb->loc_oob_flag; + iocap[2] = p_cb->loc_auth_req; +} + +/******************************************************************************* +** Function smp_collect_peer_io_capabilities +** +** Description This function puts into IOcap array peer device +** IOCapability, OOB data, AuthReq. +** +** Returns void +** +*******************************************************************************/ +void smp_collect_peer_io_capabilities(UINT8 *iocap, tSMP_CB *p_cb) +{ + SMP_TRACE_DEBUG("%s", __func__); + + iocap[0] = p_cb->peer_io_caps; + iocap[1] = p_cb->peer_oob_flag; + iocap[2] = p_cb->peer_auth_req; +} + +/******************************************************************************* +** Function smp_collect_local_ble_address +** +** Description This function puts into le_addr array local device le address: +** le_addr[0-5] = local BD ADDR, +** le_addr[6] = local le address type (PUBLIC/RANDOM). +** +** Returns void +** +*******************************************************************************/ +void smp_collect_local_ble_address(UINT8 *le_addr, tSMP_CB *p_cb) +{ + tBLE_ADDR_TYPE addr_type = 0; + BD_ADDR bda; + UINT8 *p = le_addr; + + SMP_TRACE_DEBUG("%s", __func__); + + BTM_ReadConnectionAddr( p_cb->pairing_bda, bda, &addr_type); + BDADDR_TO_STREAM(p, bda); + UINT8_TO_STREAM(p, addr_type); +} + +/******************************************************************************* +** Function smp_collect_peer_ble_address +** +** Description This function puts into le_addr array peer device le address: +** le_addr[0-5] = peer BD ADDR, +** le_addr[6] = peer le address type (PUBLIC/RANDOM). +** +** Returns void +** +*******************************************************************************/ +void smp_collect_peer_ble_address(UINT8 *le_addr, tSMP_CB *p_cb) +{ + tBLE_ADDR_TYPE addr_type = 0; + BD_ADDR bda; + UINT8 *p = le_addr; + + SMP_TRACE_DEBUG("%s", __func__); + + if (!BTM_ReadRemoteConnectionAddr(p_cb->pairing_bda, bda, &addr_type)) + { + SMP_TRACE_ERROR("can not collect peer le addr information for unknown device"); + return; + } + + BDADDR_TO_STREAM(p, bda); + UINT8_TO_STREAM(p, addr_type); +} + +/******************************************************************************* +** Function smp_check_commitment +** +** Description This function compares peer commitment values: +** - expected (i.e. calculated locally), +** - received from the peer. +** +** Returns TRUE if the values are the same +** FALSE otherwise +** +*******************************************************************************/ +BOOLEAN smp_check_commitment(tSMP_CB *p_cb) +{ + BT_OCTET16 expected; + + SMP_TRACE_DEBUG("%s", __func__); + + smp_calculate_peer_commitment(p_cb, expected); + print128(expected, (const UINT8 *)"calculated peer commitment"); + print128(p_cb->remote_commitment, (const UINT8 *)"received peer commitment"); + + if (memcmp(p_cb->remote_commitment, expected, BT_OCTET16_LEN)) + { + SMP_TRACE_WARNING("Commitment check fails"); + return FALSE; + } + + SMP_TRACE_DEBUG("Commitment check succeeds"); + return TRUE; +} + +/******************************************************************************* +** +** Function smp_save_secure_connections_long_term_key +** +** Description The function saves SC LTK as BLE key for future use as local +** and/or peer key. +** +** Returns void +** +*******************************************************************************/ +void smp_save_secure_connections_long_term_key(tSMP_CB *p_cb) +{ + tBTM_LE_LENC_KEYS lle_key; + tBTM_LE_PENC_KEYS ple_key; + + SMP_TRACE_DEBUG("%s-Save LTK as local LTK key", __func__); + memcpy(lle_key.ltk, p_cb->ltk, BT_OCTET16_LEN); + lle_key.div = 0; + lle_key.key_size = p_cb->loc_enc_size; + lle_key.sec_level = p_cb->sec_level; + btm_sec_save_le_key(p_cb->pairing_bda, BTM_LE_KEY_LENC, (tBTM_LE_KEY_VALUE *)&lle_key, TRUE); + + SMP_TRACE_DEBUG("%s-Save LTK as peer LTK key", __func__); + ple_key.ediv = 0; + memset(ple_key.rand, 0, BT_OCTET8_LEN); + memcpy(ple_key.ltk, p_cb->ltk, BT_OCTET16_LEN); + ple_key.sec_level = p_cb->sec_level; + ple_key.key_size = p_cb->loc_enc_size; + btm_sec_save_le_key(p_cb->pairing_bda, BTM_LE_KEY_PENC, (tBTM_LE_KEY_VALUE *)&ple_key, TRUE); +} + +/******************************************************************************* +** +** Function smp_calculate_f5_mackey_and_long_term_key +** +** Description The function calculates MacKey and LTK and saves them in CB. +** To calculate MacKey and LTK it calls smp_calc_f5(...). +** MacKey is used in dhkey calculation, LTK is used to encrypt +** the link. +** +** Returns FALSE if out of resources, TRUE otherwise. +** +*******************************************************************************/ +BOOLEAN smp_calculate_f5_mackey_and_long_term_key(tSMP_CB *p_cb) +{ + UINT8 a[7]; + UINT8 b[7]; + UINT8 *p_na; + UINT8 *p_nb; + + SMP_TRACE_DEBUG("%s", __func__); + + if (p_cb->role == HCI_ROLE_MASTER) + { + smp_collect_local_ble_address(a, p_cb); + smp_collect_peer_ble_address(b, p_cb); + p_na = p_cb->rand; + p_nb = p_cb->rrand; + } + else + { + smp_collect_local_ble_address(b, p_cb); + smp_collect_peer_ble_address(a, p_cb); + p_na = p_cb->rrand; + p_nb = p_cb->rand; + } + + if(!smp_calculate_f5(p_cb->dhkey, p_na, p_nb, a, b, p_cb->mac_key, p_cb->ltk)) + { + SMP_TRACE_ERROR("%s failed", __func__); + return FALSE; + } + + SMP_TRACE_EVENT ("%s is completed", __func__); + return TRUE; +} + +/******************************************************************************* +** +** Function smp_request_oob_data +** +** Description Requests application to provide OOB data. +** +** Returns TRUE - OOB data has to be provided by application +** FALSE - otherwise (unexpected) +** +*******************************************************************************/ +BOOLEAN smp_request_oob_data(tSMP_CB *p_cb) +{ + tSMP_OOB_DATA_TYPE req_oob_type = SMP_OOB_INVALID_TYPE; + + SMP_TRACE_DEBUG("%s", __func__); + + if (p_cb->peer_oob_flag == SMP_OOB_PRESENT && p_cb->loc_oob_flag == SMP_OOB_PRESENT) + { + /* both local and peer rcvd data OOB */ + req_oob_type = SMP_OOB_BOTH; + } + else if (p_cb->peer_oob_flag == SMP_OOB_PRESENT) + { + /* peer rcvd OOB local data, local didn't receive OOB peer data */ + req_oob_type = SMP_OOB_LOCAL; + } + else if (p_cb->loc_oob_flag == SMP_OOB_PRESENT) + { + req_oob_type = SMP_OOB_PEER; + } + + SMP_TRACE_DEBUG("req_oob_type = %d", req_oob_type); + + if (req_oob_type == SMP_OOB_INVALID_TYPE) + return FALSE; + + p_cb->req_oob_type = req_oob_type; + p_cb->cb_evt = SMP_SC_OOB_REQ_EVT; + smp_sm_event(p_cb, SMP_TK_REQ_EVT, &req_oob_type); + + return TRUE; +} + + +#endif + diff --git a/components/bt/component.mk b/components/bt/component.mk index 110d022672..eb031ad372 100644 --- a/components/bt/component.mk +++ b/components/bt/component.mk @@ -2,11 +2,7 @@ # Component Makefile # -#COMPONENT_ADD_INCLUDEDIRS := - -CURRENT_DIR=$(IDF_PATH)/components/bt - -COMPONENT_ADD_INCLUDEDIRS := ./include +COMPONENT_ADD_INCLUDEDIRS := ./include bluedroid/include bluedroid/osi/include bluedroid/gki/include bluedroid/btcore/include bluedroid/hci/include bluedroid/device/include bluedroid/stack/include bluedroid/app/include bluedroid/profiles/include bluedroid/bta/include bluedroid/stack/avrc/include bluedroid/stack/rfcomm/include bluedroid/bta/sys/include CFLAGS += -Wno-error=unused-label -Wno-error=return-type -Wno-error=missing-braces -Wno-error=pointer-sign -Wno-error=parentheses @@ -20,6 +16,44 @@ COMPONENT_ADD_LDFLAGS := -lbt -L$(abspath lib) \ ALL_LIB_FILES := $(patsubst %,$(COMPONENT_PATH)/lib/lib%.a,$(LIBS)) $(COMPONENT_LIBRARY): $(ALL_LIB_FILES) -COMPONENT_SRCDIRS := ./ +COMPONENT_SRCDIRS := \ + bluedroid/main \ + bluedroid/profiles/hid_le \ + bluedroid/profiles/baterry \ + bluedroid/profiles/sample_button \ + bluedroid/profiles/diss \ + bluedroid/profiles \ + bluedroid/hci \ + bluedroid/stack/btu \ + bluedroid/stack/btm \ + bluedroid/stack/gatt \ + bluedroid/stack/avrc \ + bluedroid/stack/hcic \ + bluedroid/stack/srvc \ + bluedroid/stack/gap \ + bluedroid/stack/l2cap \ + bluedroid/stack/smp \ + bluedroid/stack/sdp \ + bluedroid/stack/rfcomm \ + bluedroid/stack \ + bluedroid/btcore \ + bluedroid/device \ + bluedroid/app/app_client_profiles \ + bluedroid/app/app_client_profiles/battery_c \ + bluedroid/app/app_project \ + bluedroid/app/app_profiles \ + bluedroid/app/app_profiles/app_sample_button \ + bluedroid/app/app_core \ + bluedroid/app \ + bluedroid/gki \ + bluedroid/bta/gatt \ + bluedroid/bta/dm \ + bluedroid/bta/sys \ + bluedroid/bta \ + bluedroid/osi \ + bluedroid/test \ + bluedroid/btif \ + bluedroid \ + ./ include $(IDF_PATH)/make/component_common.mk